읽기 설정
만약 원격 팀에서 개발 업무를 해보셨다면, Xceladraw라는 도구를 접해보셨을 가능성이 높습니다.00:00
계정이 필요하지 않은 상태에서도 누구나 참여하여 실시간으로 협업할 수 있는, 무료로 공개된 오픈 소스 프로젝트입니다.00:04
동료나 함께 작업하시는 분들과 실시간으로 다양한 아이디어를 자유롭게 논의할 수 있는 공간입니다.00:09
정말 멋진 제품이고, 몇 년 동안 정말 열심히 사용해 왔습니다. 그런데 최근에 보니, API를 사용하기가 정말 쉽더라고요.00:15
몇 줄의 코드만으로 Xceladraw 컴포넌트를 React 앱에 삽입하실 수 있습니다.00:22
거의 엑셀드로우 웹사이트에 접속하신 것과 같은 방식으로 자유롭게 사용하실 수 있습니다. 이렇게 UI 부분을 실행하는 것이 비교적 간단하다는 점을 고려하면,00:26
라이브 스트리밍 관리를 위해 직접 백엔드를 구축하는 프로젝트를 구상해 보았습니다.00:33
이런 협업 세션은 이전에도 있었지만, 이번에는 Cloudflare의 내구성이 뛰어난 오브젝트를 기반으로 완전히 구축되었습니다. 이번 영상에서는 바로 그 내용에 대해 다루겠습니다.00:38
호노에서 지속 가능한 객체를 사용하여 웹소켓 설정을 진행해 보겠습니다. 실시간 다중 사용자 관리에 대해 배우도록 하겠습니다.00:44
그리고 마지막에는 저희 도메인 아래 Cloudflare에 이 프로젝트를 배포할 예정입니다. 코드를 시작하기 전에 WebSocket에 대해 이야기해 보겠습니다.00:49
웹소켓은 웹 브라우저와 같은 클라이언트와 서버 간에 단일 연결을 통해 실시간 양방향 통신을 가능하게 합니다.00:56
지속적인 TCP 연결을 통해, 끊임없이 연결을 다시 설정할 필요 없이 효율적인 데이터 교환이 가능합니다.01:01
웹소켓에 대해 알아보기 전에, 폴링이라는 개념에 대해 먼저 이야기해 보도록 하겠습니다.01:05
전통적으로, 특히 서버리스 환경에서는 무언가를 구축할 때 보통...01:09
페이지에 데이터를 지속적으로 새로 고침하는 것이 필요하며, 흔히 사용되는 방식은 어느 정도 로직을 구축하는 것입니다.01:13
UI에 통합하여 지속적으로 서버에 연결하고, 서버는 데이터베이스에 접근하여 해당 상태 정보의 최신 버전을 가져온 후 전송할 것입니다.01:17
데이터를 클라이언트에게 다시 전달합니다. 그런 다음 사용자께서 어떤 작업을 수행하시는 경우도 있을 수 있고, 그 사용자가 어떤 동작을 통해 데이터를 데이터베이스에 저장하는 경우도 있을 수 있습니다.01:23
다음번에 웹 클라이언트가 서버에 접속하여 데이터베이스에 접근할 때, 업데이트된 상태를 얻게 됩니다.01:30
음, 지금 구현하기는 꽤 간단한 패턴이에요. 그리고 제가 생각하기로는, 종종 이러한 패턴에 도달하는 경우가 많다고 생각합니다.01:35
웹소켓이 조금 까다로울 수 있지만, 서비스를 구축하는 과정이 꽤 재미있습니다.01:41
같이 일하기에 좋겠네요. 자, 그럼 웹소켓이 어떻게 동작할지, 특히 웹소켓이 어떻게 작동할지를 자세히 알아봅시다.01:44
정말 수준이 높습니다. Xceladraw를 사용하실 때 웹페이지를 열고 링크를 공유하시면 됩니다.01:48
이 라이브 공동 작업 세션을 활성화할 예정입니다. 해당 링크를 열면, 기본적으로...01:53
현재 일어나고 있는 일은 서버와 양방향 연결을 구축하고 있다는 것이고, 그 서버는...01:58
그 데이터를 아마도 데이터베이스 어딘가에 저장하게 될 예정이고, 또한 다른 웹 페이지와의 연결도 허용할 수 있습니다.02:02
실시간 협업 링크를 공유하실 수 있습니다. 여러 클라이언트가 동일한 링크를 통해 접속하여 동일한 그림을 보면서 작업하실 수 있고, 그럴 때마다...02:08
사용자 또는 첫 번째 고객님께서 데이터를 서버로 전송하시면, 서버는 지속적인 연결을 유지합니다.02:13
고객 2와 고객 3 모두에게 업데이트를 보내드리고, 그 업데이트를 직접 전달해 드립니다.02:18
이것은 근본적으로 요청을 해서 응답을 받는 것과는 완전히 다른 방식입니다.02:22
연결을 닫으시는군요. 요청을 보내시고 연결을 설정하신 후, 해당 연결이 애플리케이션 사용 기간 동안 계속 유지됩니다.02:27
이 모델은 사실 서버리스 환경에서 전통적으로는 아주 잘 작동하지 않는 편입니다.02:33
클라우드플레어 듀러블 오브젝트를 사용하면 바로 이것을 만들 수 있습니다. 그럼 코드로 넘어가 보겠습니다. 코드를 얻기 위해02:39
시작되었으니, 프로젝트 구조와 저희가 어떻게 진행하고 있는지 빠르게 살펴보겠습니다.02:43
저희는 XkeleDraw 경로를 노출하고 XkeleDraw를 구현하는 매우 기본적인 React 애플리케이션을 가지고 있습니다.02:47
이 Xceladraw 컴포넌트예요. Xceladraw 컴포넌트는 Xceladraw 엘리먼트를 감싸는 간단한 래퍼일 뿐이에요. 그리고 이 엘리먼트는 Xceladraw 라이브러리에서 가져온 거랍니다.02:51
오픈 소스입니다. 바로 사용하실 수 있도록 준비되어 있어요. Xceladraw를 설치하신 후, 프로젝트에 불러오기만 하시면 됩니다. 그러면 React를 사용하실 수 있습니다.02:58
로컬 호스트에서 엑셀 드로우를 사용하실 수 있도록 해주는 앱이라고 할 수 있습니다.03:04
꽤 멋지네요. 시작하기도 정말 쉬워요. 그리고 앱을 만들 때, 전체적인 부분에 너무 신경 쓰지 않으셔도 괜찮습니다.03:09
프로젝트 설정은 클라우드플레어 공식 문서를 참고하는 것을 선호합니다.03:14
프레임워크 가이드들이 정말 많아요. 리액트 가이드도 있고요. 이건 워커 플랫폼에서 실행돼요.03:17
이 명령어를 실행하면 돼요. 원하는 이름으로 지을 수 있죠. 이 명령어를 실행하면 이 앱 전체가 바로 실행되고, 바로 사용할 수 있을 거예요. 시작하기도 정말 쉬워요.03:22
이것은 프로젝트 구조입니다. 문서와 GitHub에 모든 내용을 연결해 드리겠습니다.03:28
나중에 필요하시면 이 내용을 복제하실 수 있습니다. 하지만 처음부터 시작하고 싶으시다면, 저는 그들의 공식 문서를 참고하는 것을 좋아합니다.03:31
프레임워크 가이드라인을 살펴보니, 클라우드플레어에 배포되는 것을 만들 때 어떻게 시작해야 하는지 추천하고 있네요. 네.03:36
Xceledra를 어떻게 활용할 건지에 대해 이해하기 위해, 우선 이 라이브 세션이 어떻게 진행되는지 설명드리겠습니다.03:42
기본적으로 Xceledra를 실행하시면...03:46
공유 링크를 복사하여 시크릿 모드 탭에 붙여넣어보세요. 움직일 때마다 확인하실 수 있습니다.03:48
왼쪽 화면에 있는 마우스의 상태가 이 오른쪽 창에도 반영될 것입니다.03:54
여기서는 반대로도 마찬가지입니다. 제가 오른쪽으로 움직일 때, 커서가 왼쪽에서 업데이트되는 것을 보실 수 있습니다. 기본적으로 여기서는 웹소켓을 활용하여 데이터를 연동하고 있습니다.03:58
비록 같은 컴퓨터에서 실행되고 있지만, 클라이언트마다 상태가 달라질 수 있습니다.04:05
여기서는 마치 이 창문이 지구 반대편에 있는 누군가와 연결되는 것처럼 상상해 볼 수 있습니다.04:09
여기 제 탭이 되고, 실시간으로 누가 무엇을 하고 있는지 정확히 확인하실 수 있을 겁니다.04:12
이걸 다시 만들어 보겠습니다. 이를 재현하기 위해 Xceledra 문서로 이동해야 합니다.04:16
API에 대한 다양한 정보를 게시하는 것을 확인할 수 있습니다. 변경 이벤트와 포인터 관련 기능들이 있습니다.04:20
업데이트 이벤트가 발생한 후, 해당 이벤트들이 어떤 영향을 미칠지 살펴볼 수 있을 겁니다.04:25
여기 제가 중요하다고 생각하는 것 중 하나가 있는데, '온 포인터 업데이트'라고 불립니다. 간단히 말해서, 페이로드를 입력받는 방식이라고 할 수 있습니다.04:29
X와 Y 좌표를 알려줍니다. 그래서 이제 페이로드라고 말씀드리겠습니다.04:35
그리고 저희가 로컬에서 실행 중인 애플리케이션으로 이동해서 콘솔을 확인할 수 있습니다.04:38
그리고 이 객체를 움직이면서 보면 여러 개의 포인터 이벤트가 발생하는 것을 확인할 수 있습니다. 이 포인터 이벤트는 단순하게…04:47
x와 y 좌표를 말씀하시고, 그리고 포인터 유형이신 것 같은데, 음, 그거는 기본적으로 하는 것과 같은 거라고 생각합니다.04:52
화면에 표시되는 이 작은 아이콘은 결국 우리가 시도하고 있는 일과는 별개입니다. 클라이언트가 있을 경우, 클라이언트 1...04:56
두 명의 고객님과 세 명의 고객님, 그리고 여기에는 서버가 있습니다.05:03
이 서버는 기본적으로 내구성이 뛰어난 객체로 작동할 예정입니다. 저희가 하고 싶은 말은, 말씀드리고 싶은 바는...05:09
클라이언트 원의 포인터 이벤트가 변경될 때마다, 그 상태가 클라이언트 투로 연쇄적으로 전달될 것입니다.05:12
그리고 세 번째 고객에게도 마찬가지 패턴이 모든 고객에게 적용될 것입니다.05:18
그래서 기본적으로 포인터 이벤트가 변경될 때마다 내구성이 있는 객체로 오게 될 겁니다. 내구성이 있는 객체는 클라이언트 1과 클라이언트 2와 연결되어, 그걸 공유하게 됩니다.05:22
UI에 반영될 수 있도록 상태를 조정하겠습니다. 그렇게 말씀드린 바와 같이, 백엔드 코드로 넘어가 보겠습니다.05:29
그리고 나서, 내구 가능한 객체(durable object) 설정 방법과 그리고 그 상태를 관리하는 데 필요한 API들을 자세히 살펴보겠습니다.05:33
견고한 객체를 시작하려면, 기본적인 예시와 사용법을 보러 공식 문서를 참고하시는 것을 추천합니다.05:38
이 가이드를 실제로 따르지는 않을 겁니다. 내구성이 뛰어난 객체 스타터 템플릿은 사용하지 않겠지만, 여기 내구성이 뛰어난 객체를 설정하는 방식에서 영감을 얻어 적용해 볼 생각입니다.05:43
클라우드플레어 워커즈에서 내구성을 가진 객체를 어떻게 가져오고, 어떻게 구현하는지에 대한 기본적인 문법 구조를 보실 수 있습니다.05:49
그것이 어떻게 메서드를 노출하는지, 어떻게 API 뒤에서 그 메서드에 접근하는지, 그리고 대부분...05:54
중요한 것은 프로젝트를 어떻게 구성하여 Cloudflare에게 여러분이 안정적인 환경을 가지고 있다는 점을 알려주는 것입니다.06:00
우리가 앞으로 할 일은 호노 스타터 템플릿으로 이동하는 것입니다.06:03
그리고 저희는 지속 가능한 데이터를 접근하는 방법을 제공하는 Hono API를 만들 예정입니다.06:07
네, 그렇습니다. 해당 명령어를 따라 하셔서 워커 플랫폼에 배포하시면 됩니다.06:12
이름은 원하시는 대로 지으셔도 괜찮습니다. 제가 여기서는 그렇게 했습니다. 보시다시피 아주 기본적인 형태로 만들었습니다.06:16
스타터 호노 템플릿은 단순히 '안녕하세요'를 반환합니다. 저희는 `ip run dev` 명령어를 실행하여 결과를 확인하실 수 있습니다.06:21
우리 로컬 호스트에서 실행 중인 애플리케이션이 이 API를 제공하고 있는데, 이제 내구성이 뛰어난 객체로 옮겨가고 있습니다.06:28
여기서 한 가지 더 다뤄볼 부분은 새로운 파일인 '내구성 객체(durable object)'를 만드는 것입니다. 이 파일은 관련 내용을 담게 될 것입니다.06:32
저는 내구성이 뛰어난 객체에 대한 모든 로직을 index.ts 파일 안에 넣는 것을 좋아하지 않습니다.06:36
예시에서 보시는 것처럼, 저희 코드를 분리하고 이 프로젝트를 조금 더 효율적으로 진행하기 위해서입니다.06:39
더 관리하기 쉽도록, XceladrawWebSocketServer라는 아주 기본적인 DurableObject 클래스를 만들겠습니다. 이 클래스는 DurableObject를 상속받으며, Cloudflare를 전달하고 있습니다.06:43
곧바로 확인하실 수 있도록 준비 상태를 보여드리겠습니다. 기본적으로 이 부분이 어떻게 들어오는지06:50
클래스에는 카운터가 있고, 이 increment 메서드가 있습니다.06:56
이 나중에는 삭제할 거예요. DurableObject가 어떻게 작동하는지 검증할 수 있다는 점을 보여주고 싶습니다.06:59
인덱스(.ts) 파일로 이동하여, 이 파일 안에 있는 XceladrawWebSocketServer 클래스를 내보내겠습니다.07:02
그리고 나서 저희는 Wrangler 설정으로 이동할 예정입니다.07:08
그리고 Wrangler 설정은 아마 Wrangler.toml 파일일 수도 있습니다. 저는 JSON 구조를 선호해서 JSON-C 형식을 사용하고 있습니다.07:12
톰보다 조금 더 많지만, 사실은 큰 상관이 없습니다.07:18
여기서는 내구성을 갖춘 객체만 추가해 주시면 됩니다. 바인딩을 전달하신 후 클래스 이름을 전달하시면 됩니다.07:21
이 클래스 이름은 여기에서 내보내는 정확한 클래스 이름이 됩니다.07:26
프로젝트 설정 파일이 어디서 가져와야 하는지 알고 있습니다. 인덱스 파일에서 가져오기 때문입니다. 그래서 여기 WebSocket 서버가 있습니다.07:29
그리고 수출될 것이며, 저희는 이 설정 안에서 영구 객체를 정의하고 있습니다.07:36
이름을 변경해야 할 경우, 이 마이그레이션 명령어를 추가해야 할 것입니다.07:42
견고한 객체에 관해서는 클래스 이름처럼 그렇게 마이그레이션을 관리할 수 있습니다. 저는 보통 이런 방식은 선호하지 않습니다.07:46
그렇게 하는 것이 조금 번거로워질 수 있지만, 필요한 사항은 저장하는 것입니다.07:51
그리고 나서 터미널에서 cftypegen 명령을 실행하시면 됩니다.07:54
제가 할 일은, 이 코드를 내보내거나 워커 내부에 있는 이러한 유형의 데이터를 출력하는 것입니다.08:00
configuration d.ts 파일을 확인하시면, 저희가 정의한 이름을 가진 durable object를 보실 수 있습니다.08:05
여기서 이렇게 바꾸면, 예를 들어 '테스트'라고만 했다고 가정해 보겠습니다. 저희는 이 CF 유형을 테스트해 보았는데요.08:10
다시 한번 보시다 보면 지금 이름은 테스트라고 되어 있지만, 당연히 저희는 조금 더 다듬고 싶습니다.08:16
설명적인 실행, CF 유형, 일반, 저희는 내구 객체를 가지고 있으며, 이 내구 객체에 접근할 수 있습니다.08:20
여기서 네임스페이스를 가져오고 있는데, index.ts에서 가져오고 있습니다. 이것은 기본적인 설정 방식입니다.08:26
클라우드플레어가 프로젝트를 어떻게 구성했는지 참고하여, 사용자님께서도 동일하게 적용하실 수 있도록 안내해 드립니다.08:32
실제 운영 환경에서 작업할 때는 조금 다른 방식으로 처리하지만, 지금 이 프로젝트는 현재 상태 그대로 완벽하게 작동할 테니 신경 쓰지 않으셔도 됩니다.08:36
이것이 바로 Cloudflare 바인딩과 함께 일어나는 일의 본질입니다. Hono를 사용하면 Cloudflare 바인딩에 접근할 수 있습니다.08:43
지금부터는 ID라고 말씀드리겠습니다. 여기서 보시는 것처럼, 저희는 영구 객체에 접근할 수 있습니다.08:49
이름을 통해 ID를 확인할 수 있습니다. 기본적으로 이것은 영구적인 객체에 대한 ID를 제공하는 것입니다, 그리고 저희는 이것을 활용할 수 있습니다.08:53
이것을 스텁이라고 부르겠습니다. 문서에 그렇게 설명되어 있어서요. DurableObject의 getID입니다.08:57
그리고 이것을 통해 저희는 정의했던 영구 객체에 접근할 수 있게 될 것입니다.09:02
여기에 전달되는 ID를 기준으로 내구재 객체가 세분화됩니다. 그리고 여기서부터...09:06
여기서 볼 수 있듯이 'const'라고 선언할 수 있으며, 내구 가능한 객체를 호출할 수 있는 스텁을 사용할 수 있습니다.09:13
여기서 정의한 내구 객체 증분 메서드인데, count i를 반환할 것입니다.09:19
지금부터 이 프로젝트를 진행하겠습니다.09:27
프로젝트로 넘어가 보시면, 이 카운터는 저희가 이 엔드포인트를 호출할 때마다 증가하는 것을 확인할 수 있습니다.09:32
이곳부터는 여러분이 영구 객체를 사용하고 작동하는지 확인하는 부분입니다. 매우 간단하고 기본적인 뼈대 코드일 뿐이죠. 프로젝트를 설정할 때마다 이 과정을 거치지 않아요. 이미 방법을 알고 있어서요.09:39
혹시 내구 가능한 객체를 한 번도 보지 않으셨다면, 이게 프로젝트가 제대로 돌아가는지 확인하는 좋은 방법일 거예요.09:46
자, 이제 설정이 끝났으니, WebSocket 관리를 위한 실제 API로 넘어가도록 하겠습니다.09:52
내구 가능한 객체(Durable Object) 문서의 예제 부분을 살펴보니, 웹소켓 서버 구축에 대한 두 개의 섹션이 있네요.09:57
WebSocket 서버를 구축하고, 그런 다음 WebSocket 휴면 기능을 갖춘 WebSocket 서버를 구축해야 합니다.10:02
WebSocket 서버 구축을 살펴보면, 이전에 WebSockets을 사용해 보신 분들은 이 패턴이 매우 익숙하실 겁니다.10:06
서버를 생성하시고, 이벤트 리스너를 추가하신 후, 메시지 이벤트(message event)를 수신하여 들어오는 메시지를 처리하실 수 있습니다.10:12
이것은 데이터를 보내는 것일 뿐입니다. 그리고 닫을 때 다른 이벤트 리스너를 정의할 수 있습니다.10:18
몇 가지 다른 이벤트도 들어보실 수 있습니다. 이 패턴은 WebSockets나 Express, 심지어 Python을 사용해 보신 적이 있다면 상당히 일반적인 형태라고 보시면 됩니다.10:23
매우 유사한 과정입니다. 하지만 이 부분의 문제는 WebSocket 연결이 내구성이 있는 객체를 메모리에 고정시킨다는 점입니다.10:30
WebSocket 연결이 유지되는 동안에는 활동 여부와 상관없이 지속 시간의 변경이 발생할 수 있습니다.10:37
활동 중단 시 요금이 부과되는 것을 피하려면 WebSocket Hibernation API를 사용하시기 바랍니다.10:43
이것을 바탕으로 보면, 유지되는 관계만 있다고 해도 기본적으로 그렇게 말하는 것입니다.10:47
거기 아무 일도 일어나지 않고 있습니다. 내구성이 뛰어난 객체로 이벤트가 들어오거나 전송되지 않는 것 같습니다.10:54
내구성 있는 객체는 지속 시간을 발생시키게 되는데, 이는 비용이 상당히 많이 들 수 있습니다. 음, 그리고...10:57
활동으로 인해 연결을 실제로 닫아내는 부분에 대해서는 매우 주의하셔야 합니다.11:02
애플리케이션에 불필요한 부분이 상당히 많이 추가될 것 같고, 딱히 사용될 사례가 떠오르지 않네요.11:06
이제 실제로 이 웹 소켓 패턴을 어디에서 활용할 수 있을지 현실적으로 파악하게 되셨으니, 그 점이 중요하다고 생각합니다.11:09
튼튼하고 오래가는 물건들의 경우, 저는 거의 항상 보존하는 방법을 선택할 것 같습니다.11:13
여기서 가장 큰 차이점은, 이 부분입니다.11:17
데이터를 가져오는 함수 내에서 정의하는 대신, WebSocket 서버를 활용하여 리스너들을 처리하는 것을 고려해 볼 수 있습니다.11:19
그리고 이 안에서 코드를 모두 구축하는 것과 더불어, 내구성이 뛰어난 객체가 실제로 API를 제공하기도 합니다.11:25
WebSocket의 전체 수명 주기 이벤트를 관리하는 역할을 합니다.11:29
네, 그렇게 하면 확인해 볼 수 있습니다. 기본적으로 WebSocket 쌍을 생성하실 수 있습니다.11:34
이것은 첫 번째 예시와 마찬가지로, 서버에서 클라이언트를 생성하신 후, 이 '웹소켓 연결 수락'을 호출하시면 됩니다.11:38
클라우드플레어 런타임에 현재 웹소켓 연결을 시작하고 있다는 것을 알리는 기본적인 내용입니다.11:45
그 연결들의 생명 주기를 관리하기 위해 히베르네이션 API에 의존하게 되실 겁니다.11:49
문서 내용을 꼼꼼히 살펴보시면 추가적인 설명이 더 있을 것이고, 그리고 이런 것들도 있습니다.11:54
관리 기능을 구현하기 위해 필요하신 모든 로직을 구축할 수 있도록 하는 내장 메서드들을 제공합니다.11:59
웹소켓을 사용하시면 웹소켓 메시지를 받으시는 것을 확인하실 수 있습니다. 해당 메시지는 호출될 것입니다.12:03
웹소켓이 연결될 때마다, 클라이언트로부터 메시지가 전송될 때마다요.12:08
그리고 WebSocket 연결이 종료되고, 몇 가지 다른 항목들도 있습니다. 잠시 후에 그 부분들을 살펴보겠습니다.12:12
패턴은 대체로 비슷하지만, 이 안에 모든 비즈니스 로직을 정의하는 대신...12:16
데이터를 가져오는 함수를 호출하면 연결을 설정하고 수락하는 작업을 수행하게 됩니다.12:21
이 내장 메서드를 호출하고 계시고, 이 클라이언트 객체를 다시 클라이언트에게 반환하시는군요.12:27
WebSocket 서버와의 연결을 시도하고 있으며, 이후 귀사의 비즈니스 관련 사항들을 처리하려 합니다.12:30
논리적인 내용이 여기 들어갈 수 있습니다. 저희는 이 기능을 실제로 어떻게 적용하는지 살펴보겠습니다.12:34
저희의 사용 사례에 맞춰서, 기존 API를 기반으로 확장해 나가는 방법을 배우기 시작할 예정입니다.12:38
그리고 나서 클라우드플레어가 관리하는 것이 얼마나 강력한지 직접 경험하게 되실 겁니다.12:42
웹소켓의 수명주기를 설명드리려고 합니다. 꽤 복잡해질 수 있기 때문입니다. 다시, 저희는...12:47
코드에서는 내구성을 가진 객체로 이동하여, 실제로 무엇을 구현할 예정입니다.12:51
방금 문서에서 확인했던 내용인데요, 이 증분 메서드는 더 이상 중요하게 생각하지 않아서 삭제하려고 합니다. 내구성이 뛰어난 오브젝트가 정상적으로 작동하는 것을 알고 있습니다.12:55
그리고 나서 여기에서 정확히 무슨 일이 벌어지고 있는지 좀 자세히 살펴보겠습니다.13:01
저희는 fetch 메서드를 가지고 시작하게 될 것입니다.13:05
WebSocket 쌍을 구현하겠습니다. 서버에서 클라이언트를 제공하게 될 것입니다.13:09
서버를 통해 지속 가능한 객체에 내장된 WebSocket으로 요청을 전달할 예정입니다.13:14
이것은 런타임에 내구 가능한 객체 연결을 시작하고, 하이버네이션 API에 의해 관리되어야 한다는 것을 알리는 역할을 합니다.13:18
이어서 사용자에게 응답을 보내드리겠습니다. 이것은 웹소켓에서 흔히 사용되는 응답 패턴입니다.13:24
101 상태로 되돌아가신 후에는, 그 다음에 진행되실 겁니다.13:29
웹 소켓을 반환하며, 이 웹 소켓 클라이언트를 통해 연결을 가능하게 할 것입니다.13:32
서버와 클라이언트 간의 양방향 연결을 구축한 후, 관련 API 몇 가지를 안내해 드리겠습니다.13:36
방금 확인했는데 웹 소켓 메시지를 받게 될 것이며, 이는 메시지가 발생할 때마다 호출될 것입니다.13:40
클라이언트로부터 메시지가 전송되면, 저희가 처리할 수 있습니다. 현재는 일단...13:44
저희가 할 일은 그 메시지를 다시 고객님께 전달드리고, 또한 개수를 세는 것입니다.13:47
현재 저희의 영구 객체에 연결되어 있는 웹 소켓 또는 클라이언트들을 말씀드리고자 합니다. 나중에 이 부분에 대해 더 자세히 다루겠습니다. 정말 강력하기 때문입니다.13:54
그리고 WebSocket 연결이 닫히면, 로그를 기록하겠습니다.14:01
WebSocket 연결이 종료되었음을 알 수 있습니다. 그리고 다른 메서드들도 존재한다는 것을 확인할 수 있습니다.14:04
전화할 수 있는 내구성이 뛰어난 객체에 대해 말씀드리고자 합니다. WebSocket에서 오류가 발생하면 해당 이벤트를 감지하고 필요에 따라 처리하실 수 있습니다.14:08
처음 실행될 때, 저희는 오늘 구현하는 예시를 통해 이것을 더욱 발전시켜 나갈 예정입니다.14:14
하지만 이것들은 추가적인 방법 두 가지이며, WebSocket과 관련된 다른 방법들도 몇 가지 더 있습니다.14:19
그래서 내구성이 뛰어난 객체에 라이프사이클 메서드들을 많이 포함하고 있습니다.14:23
일단 이것들은 삭제하고 API로 넘어가도록 하겠습니다. 네, API에서 이 경로를 제거할 예정입니다.14:26
더 이상 필요하지 않지만, 이전과 대체로 같은 방식으로 진행될 예정입니다.14:31
잠시 삭제를 멈추고 기다려 볼게요. 혹시 기억하시겠지만, 제가 increment 메서드를 삭제했었죠. 그래서 지금은 타입 에러가 발생할 텐데, 해당 메서드가 존재하지 않기 때문입니다.14:35
지금부터는 여기에서 추가적인 엔드포인트를 생성할 텐데요, 슬래시 API로 만들겠습니다.14:41
프론트 슬래시 WS는 WebSocket을 의미하고, 그 다음에 drawing ID라는 파라미터가 있는데, drawing ID는...14:49
엑셀라드라 그림을 나타내겠습니다. 그림 ID를 추출할 예정입니다.14:55
이것은 기본적인 HONO 의미론에 대한 설명입니다. 그리고 나서 요청받은 연결이 제대로 이루어지는지 확인하도록 하겠습니다.14:58
고객님께서 웹 소켓이 맞는지 확인해야 합니다. 그렇지 않다면 오류가 발생할 것입니다. 그리고 그 다음에 무엇을 할 것인지요.15:04
우리는 ID를 수집하고, 영구 객체에서 가져오고, 그리고...15:08
실제 내구성 있는 객체 ID를 전달하고 있습니다.15:13
보이는 바에 의하면 이것이 항상 정의되지 않는 것 같습니다.15:16
그래서 저희는 누락된 그림 ID도 반환할 예정입니다.15:19
네, 지금은 스텁이 완성되었고, 지속 가능한 객체, 지속 가능한 객체의 인스턴스가 준비된 상태입니다.15:23
드로우 ID를 입력하면, 기본적으로 새로운 인스턴스가 생성되거나, 이전에 생성된 경우 기존 인스턴스가 사용됩니다.15:29
그러니까, 내구성이 있는 객체, 특히 그 특정 ID를 가진 객체는 존재할 것입니다. 그러니 여러분이 어떤 객체를 가지고 있다고 상상해 보시면 됩니다.15:36
다양한 그림들이 있고, 각각의 그림에 대한 정보를 저장하고 싶을 때 활용할 수 있습니다.15:41
드로우 ID로 텍스트를 분할하고, 그런 다음 그 데이터를 영구 객체에 저장할 수 있습니다.15:45
그리고 연결 상태는 도면을 기반으로 관리할 수도 있습니다. 이것이 어떻게 분할하는지 보여주는 방식 중 하나입니다.15:49
귀하의 주, 특히 Xceladraw에서 도면을 분할하는 사업적 활용 사례에 맞게 적용될 수 있습니다.15:53
그리고 나서 저희는 요청 데이터를 fetch 메서드에 전달할 예정입니다.15:58
여기에서 구현했습니다. 이것은 내구 가능한 객체 API의 일부이며, 이 fetch 메서드입니다.16:05
이것은 저희가 즉흥적으로 만든 것이 아닙니다. 내구 가능한 객체의 일부로서, 원본 요청을 그대로 전달하고 있습니다.16:09
그리고 반환되고 있습니다. 기본적으로 이 정보를 전달하고, 영구 객체를 설정한 다음, 내용을 전달하고 있습니다.16:16
고객님과의 연결을 다시 한 번 연결하여 이러한 양방향 소통을 지속적으로 유지할 수 있도록 하겠습니다.16:22
네, 이것이 바로 웹소켓에서 서버를 구축하는 기본적인 방식입니다. 이제 UI로 넘어가서, 저희는 이 서버에 로컬 환경에서 연결을 시도해 보겠습니다.16:29
이 WebSocket에 연결을 시도할 텐데, 이 모든 설정이 제대로 완료되면요.16:35
콘솔에서도 이 메시지가 다시 저희에게 돌아오는 것을 확인하고, 로그로 출력하며, 네트워크 탭에서도 확인할 수 있을 겁니다.16:39
UI에서 기억하시겠지만, 저희는 포인터가 움직이거나 업데이트될 때마다, 해당 페이로드를 기록하고 있습니다. 그 페이로드에는 마우스의 좌표 정보가 담겨 있답니다.16:47
화면에 마우스 위치가 표시되고 있습니다. 대략 이런 모습이죠. X 좌표, Y 좌표, 그리고 마우스 도구를 확인할 수 있습니다.16:54
궁극적으로 우리가 하고 싶은 것은 로그를 출력하는 대신, 그 데이터를 영구 객체에 보내는 것입니다.16:59
제가 구현한 것은 꽤 기본적인 훅인데, 이 훅을 통해 WebSocket과 연결을 설정할 수 있습니다.17:04
제가 이 코드를 빠르게 설명드리겠습니다. 원하시는 시간에 React 안에서 WebSocket을 사용하는 모범 사례들을 살펴보시면 됩니다.17:10
이것은 단순히 예시일 뿐이며, 아마 더 좋은 패턴들이 있을 겁니다.17:16
만약 실제 서비스 환경에서 이 작업을 진행한다면, 이와 똑같은 방식으로 적용하지는 않을 것 같습니다. 하지만, 이 데모 목적을 위해서입니다.17:21
예시로, WebSocket에 연결해서 어떻게 작동하는지 보여드리고 싶습니다.17:25
이것이 훅입니다. 그리고 이 컴포넌트가 마운트될 때, 저희는 실행 중인 웹소켓과의 연결을 설정하고 있습니다.17:28
그리고 저희가 로컬에서 실행하고 있는 서버와 연결하거나, 두 개의 이벤트 핸들러가 있습니다.17:35
본질적으로 메시지를 받는 즉시, 메시지가 들어올 때마다, 고객님 또는 사용자 인터페이스나 웹페이지를 통해요.17:41
서버로부터 이벤트를 받으면, 단순히 로그아웃시키는 것 뿐입니다.17:47
그리고 WebSocket이 실제로 열리고 연결되었을 때, WebSocket이 열렸다는 로그를 기록하고 있습니다.17:50
본 코드는 기본적으로 WebSocket을 활용하는 과정을 수행합니다.17:57
이 메서드를 통해 데이터를 저희 서버로 전송하게 됩니다.18:02
여기서 서버를 정의해두었고, 이 메서드는 이벤트를 입력받아 데이터를 문자열로 변환하는 역할을 합니다.18:07
서버에서 제대로 받을 수 있도록 적절한 형태로 변환할 수 있도록 하겠습니다. 그리고 나서 저희가 어떻게 사용하는지 정확히 보여드리겠습니다.18:14
그래서 이 useBufferWebSocket을 수출하게 됩니다. 그리고 나중에 네이밍에 대해서 다시 말씀드리겠습니다.18:19
여기서 제가 의도적으로 '버퍼'라는 단어를 사용하게 되는 이유를 알아보겠습니다. 자, 이제 저희의 Excalibraw 컴포넌트가 있습니다.18:23
저희 useBufferWebSocket을 가져왔는데, 서버로 데이터를 전송하는 메서드를 반환하고 있습니다.18:30
그리고 동시에 그런 연결을 만들어냅니다. 그런 다음 이 메서드, 이 콜백이 있습니다.18:36
보내는 이벤트입니다. 그리고 제가 할 일은 페이로드를 로그아웃하는 대신, 여기 보내는 이벤트를 전달하는 것입니다.18:41
자, UI로 다시 돌아가서 살펴보겠습니다.18:47
네, 페이지를 다시 로드하겠습니다. 보시면 ID 1로 나가는 요청이 있음을 확인하실 수 있습니다.18:52
아마 제가 조금 더 먼저 언급했어야 했을 것 같습니다. 저희는 경로에서 ID를 가져오고 있습니다.18:58
그래서 엑스칼리버가 있고, 여기 ID 1이 있습니다. 이 ID를 가져다가 웹 소켓으로 전달하고 있습니다.19:03
그리고 그 내용이 저희 API 경로의 끝부분에 추가되고 있습니다.19:09
방금 스쳐 지나가듯이 말씀드린 내용과 관련하여, 이것이 그림을 분할하는 데 사용되는 방법입니다.19:14
이제 이 연결이 만들어졌고, 마우스를 움직이는 것을 보시면 확인할 수 있습니다.19:18
우리 네트워크를 통해 이벤트가 발생하고 있습니다. 이벤트들이 전송되고 있으며, 수신되고 있습니다.19:23
여기 보이는 빨간 화살표는 이벤트가 수신되고 있는 것을 의미하며, 이쪽으로 나가는 것을 나타냅니다.19:28
서버를 잠시 재시작해야 할 것 같습니다. 다시 시작한 다음에 콘솔 로그를 확인해 보겠습니다.19:33
페이지를 새로고침하면 로그를 확인하실 수 있습니다. WebSocket 연결이 열리고, 마우스를 움직일 때마다 'received' 이벤트가 발생합니다.19:39
기본적으로 현재 일어나고 있는 일은 저희 서버가 있습니다.19:46
저희는 고객님을 가지고 있으므로 이 웹페이지입니다.19:51
그리고 나서 저희는 요청을 드리고, 지속적으로 유지되는 양방향 연결을 구축하고 있습니다.19:58
이 연결이 종료되지 않고 있습니다. 클라이언트가 계속해서 서버로 데이터를 보내고 있고, 서버는 그 데이터의 일부를 클라이언트로 다시 보내는 것 같습니다.20:03
그리고 저희가 로그에서 확인하고 있는 데이터가 서버에서 직접 오는 것이 맞습니다.20:09
그래서 여기서 이 URL을 가져와서 조금 더 자세히 보여드리겠습니다. 그리고 이것이 있습니다.20:12
이 인코그니토 탭이라서, 다시 로드해서 보여드리려고요. 이렇게 하면 보실 수 있을 거예요.20:19
알고 계시겠지만, 저희도 이 데이터를 확보하고 있습니다. 잠시 여기 계시면 됩니다.20:25
저희 서버에서 발송된 메시지인데, 연결에 관한 내용이 담겨 있습니다.20:31
여기 오셔서 이 사람을 움직여 주시면 됩니다. 페이지를 다시 로드하겠습니다.20:35
이제 연결 관계를 확인하실 수 있습니다. 지금은 닫도록 하겠습니다. 닫았으니, 이제 서버를...20:41
이 이벤트가 가까이 왔습니다. 마우스를 움직여 보시면 연결 관계를 확인하실 수 있습니다. 여기 보시면 됩니다.20:46
음, 기본적으로 탭을 닫는 즉시 연결이 끊어졌고, 서버는 그걸 인지했습니다.20:50
그리고 나서 이 숨김 브라우저 탭에서 받은 다음 이벤트는 연결이 하나뿐이라는 것이었습니다.20:56
여기 돌아와서 이것을 불러오고, 이 사람을 움직일 수 있습니다. 이제 연결고리 두 개를 확인할 수 있습니다.21:01
여기서 우리가 하고 있는 것은 기본적으로 클라이언트와 서버 간에 데이터를 주고받는 것입니다.21:08
참고하실 점이 하나 있다면, 제가 이 웹페이지에서 마우스를 움직일 때 데이터를 받고 있다는 점입니다.21:12
이 고객으로부터 데이터를 서버로 보내 다시 이 고객에게 전달하려고 하는데, 아무것도 받지 못하고 있습니다.21:20
이 인코그니토 탭에서 이쪽으로 이벤트가 진행되고 반대로 다른 쪽으로도 진행될 수 있습니다. 따라서 이 탭을 삭제하면 해당 정보가 사라질 수 있습니다.21:25
여기 물건들을 옮기기 시작합니다. 이벤트들이 보이고는 있지만, 제대로 받아들이지는 못하고 있습니다.21:29
이 창 안에서, 그리고 기본적으로, 이것은 저희가 어떻게 실제로 관리할 수 있는지에 대한 방법을 제시할 것입니다.21:33
저희 서버에서 여러 클라이언트 간의 상태를 공유하고 있습니다. 현재 저희 서버의 동작 방식은 이렇습니다.21:38
고객 1과 고객 2가 있습니다. 그리고 두 고객 모두 서버와 연결을 설정했습니다.21:45
그 문제가 계속되고 있습니다. 그런데 고객님 1이 서버에 데이터를 보낼 때마다, 그 데이터가 다시 돌아오는 현상이 반복되고 있습니다.21:51
고객 1에게 전달되기는 하지만, 그 데이터가 고객 1에서 고객 2로 바로 가지 않고 다시 돌아오지는 않습니다.21:56
그리고 저희는 여기서 클라이언트 세 번째를 새로 생성할 때에도 이렇게 동작하는 것을 기대하고 있습니다.22:00
양방향 연결을 원합니다. 클라이언트 1에서 데이터를 서버로 전송하고, 그 로그를 확인하고 싶습니다.22:05
고객님 두 번째와 세 번째는 괜찮지만, 고객님 첫 번째에서는 로그를 필수로 보지는 않으셔도 됩니다.22:10
그 이유가 바로 마우스가 웹페이지 위에서 움직일 때, 필연적으로 그렇게 느껴지지 않기 때문입니다.22:15
마우스 위치가 어디에 있는지는 신경 쓰지 않으시고, 서버에 마우스 위치를 알려주는 것만 중요합니다.22:21
서버가 다른 클라이언트에게 해당 페이지에 접속해 계시고 움직이고 계신다는 것을 알려줄 수 있도록 하기 위함입니다.22:24
주변을 둘러보았으니, 이제 백엔드로 돌아가서 어떻게 구현할 수 있는지 확인해 보겠습니다.22:28
메시지 수신 및 전송을 처리하는 서버 측 코드를 살펴보겠습니다.22:33
서버로 들어오는 데이터를 클라이언트로 다시 보내는 과정에서, 내구성이 뛰어난 객체(durable object)의 일부인 WebSocket 메시지 메서드를 살펴보실 수 있습니다.22:38
현재는 WebSocket을 수신 중입니다. 이 WebSocket은 현재 데이터를 보내고 있는 클라이언트의 것입니다.22:45
서버로 데이터를 보내고 있습니다. 그리고 클라이언트가 보낸 메시지를 다시 클라이언트에게 돌려보내는 과정입니다.22:51
하지만 우리가 할 수 있는 것은 이 getMethodsWebSocket 배열을 통해 모든 WebSocket 또는 모든 것을 가져올 수 있다는 것입니다.22:57
현재 이 서버에 연결되어 있는 클라이언트들을 확인한 다음, 계층 구조로 연결할 수 있습니다.23:03
연결된 모든 웹소켓이나 일부 특정 웹소켓에 메시지를 전송할 수 있습니다.23:07
자, 그럼 그게 어떻게 보이는지 한번 살펴보겠습니다. 기본적으로 여기에는 루프를 정의하는 부분이 있습니다.23:11
이 목록에 있는 소켓을 사용하겠습니다.23:14
연결된 웹소켓들을 사용했습니다. 그리고 각 웹소켓마다 동일한 내용을 전달하고 있습니다.23:19
답장을 주시면, 현재 코드를 그대로 유지한다면, 어떤 일이 발생할지 확인해 보겠습니다.23:23
클라이언트가 서버로 데이터를 전송하면, 해당 데이터는 현재 연결된 모든 곳으로 전달될 예정입니다.23:28
소켓을 통해 이 메시지를 모든 클라이언트에게 보내주세요.23:33
이제, 이 메시지를 보내는 클라이언트가 소유하지 않은 모든 소켓을 식별하고 싶습니다.23:36
이 메시지를 고객님께 다시 보내드리고 싶지 않아서, 이 메시지를 현재 연결된 다른 모든 고객님들께 보내드리고 싶습니다.23:41
음, 그러니까, 여기서 말씀드릴 수 있는 것은, 만약...23:47
이 루프 내의 소켓 또는 반복 과정에서 git 웹 소켓을 순회하는 특정 소켓이 동일합니까?23:51
이 메시지를 보낸 소켓은 건너뛸게요.23:58
만약 아니라면, 이 반복을 계속 진행하고 데이터를 다시 보낼 거예요. 이 부분의 동작은...24:03
UI에서 마우스를 움직일 때마다 다른 로그에서도 확인할 수 있도록 해야 합니다.24:09
서버나 다른 클라이언트의 로그 기록, 이벤트들이 들어오기는 하는데, 웹페이지에서는 그렇지 않네요.24:15
실제로 그 이벤트들을 보내고 있어요. 좀 더 명확하게 하기 위해 한번 살펴봅시다. 연결을 설정해 봅시다. 여기 연결을 설정해 봅시다.24:22
이것은 저희의 인코그니토 탭입니다. 보시면 거기서 확인할 수 있습니다. 여기서는 처음부터 다시 해볼게요.24:29
이제 로그를 지워볼까요. 제가 이 웹페이지에서 움직일 때마다 저쪽에서는 로그아웃되고 있어요.24:34
다른 웹페이지에서 서버와 연결되어 있고, 그 반대도 마찬가지예요.24:40
그래서 여기로 와서 이것들을 움직여보면, 이 웹페이지에서는 로그가 뜨지 않지만, 저쪽에서는 로그가 뜹니다.24:44
여기서 로그를 실제로 받고 있어서 정말 멋지네요. 기본적으로 저희가 한 일은, 이렇습니다.24:51
저희 서버가 여러 곳에서 상태를 관리하는 기본적인 방식을 결정했습니다.24:56
저희는 서버가 있고, 그리고 클라이언트 1번, 그리고 클라이언트 2번이 있습니다.25:00
그리고 클라이언트 1이 서버에 데이터를 보낼 때, 그 데이터가 클라이언트 1에게 다시 돌아오지 않고, 실제로는...25:04
고객님께 전달되었습니다. 그리고 만약 더 많은 창문을 열었다면, 기본적으로 이런 현상이 발생할 것입니다.25:10
데이터가 서버로 전송되는 방식은 웹 페이지 하나 또는 클라이언트 하나에서 서버로 가는 것입니다.25:15
서버와 연결되어 있지만 클라이언트에는 연결되지 않은 이러한 다른 웹 페이지들로도 전달됩니다.25:19
그러한 데이터를 전송하도록 설정하는 것입니다. 따라서 마우스를 움직이는 동작을 실제로 연결하는 방식이 그렇게 됩니다.25:24
그리고 다른 화면에 나타나는 것을 확인했는데요, 이제 간단하게 사용자 인터페이스를 조금 수정해 보도록 하겠습니다.25:29
이 동작을 구현하기 위해서입니다. 따라서 저희 UI에서 웹 소켓을 처리하는 코드를 살펴보겠습니다.25:32
이 훅에 전달되는 `handleMessage`라는 추가적인 프로퍼티를 더했습니다.25:37
결국에 발생하게 될 일은, 우리가 메시지를 받았을 때 로깅하는 대신에…25:41
서버에서 데이터를 받아와서, 그 데이터를 핸들 함수에 전달할 예정입니다.25:45
이렇게 하면 렌더링하는 ExcelaDraw 컴포넌트 내부에 이 로직을 정의할 수 있습니다.25:50
지금, 여기에 Zod 스키마를 몇 가지 추가해서, 기본적으로...25:56
이쪽에 좀 더 깔끔하게 정리할 수 있도록 몇 가지 다른 유형을 정의하는 중입니다. 그렇게 하면 조금 더 효율적으로 관리할 수 있을 거예요.26:02
하지만 너무 신경 쓰지 마세요. 저희가 있다는 것만 알아주시면 됩니다.26:07
데이터를 handle message에 전달한 후, 그 데이터는 UI에서 사용되어 작업을 수행합니다.26:10
그 관점에서는, 웹소켓 측면에서 실제로 이렇게 변화가 있었던 것이 전부입니다.26:15
그리고 나서 UI에 어떻게 연결했는지 보여드릴 수 있을 것 같습니다.26:19
결과적으로, 저희는 몇 가지 다른 사항들을 정의해 봤습니다. 그리고 저는 지금부터 아래쪽부터 설명드리겠습니다.26:23
여기 있는 Xcaladraw 컴포넌트의 경우, 이전에 포인터 업데이트 시 데이터를 전송하고 있었습니다.26:28
WebSocket에 그대로 전달하고 있습니다. 그런데 제가 여기서 하고 있는 일은, 제가 '포인터'라고 부르는 이 타입 데이터를 가져다 쓰는 것입니다.26:35
그리고 나서 사용자 ID에 대한 추가 데이터를 전달해 드립니다.26:41
화면에 표시되는 사용자 이름과 비슷한 것 같아요. 제가 임의의 ID를 생성해서 차이점을 조금이나마 확인하실 수 있도록 하는 거예요.26:45
화면에서 활발하게 마우스를 움직이는 사용자들과 X 및 Y 좌표 간의 관계입니다.26:50
UI에서 마우스를 움직일 때마다 WebSocket으로 데이터를 전송하게 됩니다.26:55
하지만 특정 데이터 형식으로 전송될 예정이어서, 프로젝트가 확장됨에 따라 작업하기가 조금 더 수월해질 것으로 예상됩니다.27:00
그리고 여기 또 다른 부분은 Xcaladra 컴포넌트 안에 이른바 '훅(hook)'이라는 기능이 내장되어 있다는 점입니다.27:07
Xcaladra API를 설정하여, 특정 이벤트 발생 시 UI를 업데이트하기 위한 다양한 핸들러를 호출할 수 있도록 하고 있습니다.27:13
기본적으로 저희가 해야 했던 일은 API를 전달하는 것뿐이고, 제가 여기서 정의한 상태 객체가 있습니다.27:20
기본적으로 널(null)로 설정되지만, 컴포넌트가 렌더링될 때 API에 접근할 수 있게 됩니다.27:29
그럼 서버로부터 이벤트를 받을 때마다 다양한 로직을 처리할 수 있게 될 거예요.27:35
제가 어떻게 활용되고 있는지 보여드릴 수 있도록 하겠습니다. 여기 몇 가지 기본적인 내용들이 더 있고, 사용자 ID를 무작위로 생성하는 것도 있습니다.27:40
컴포넌트가 마운트될 때, 이를 로컬 스토리지에 저장하고 있습니다. 나중에 접근할 수 있도록 하기 위해서입니다.27:47
그리고 그 사용자 ID가 페이지 새로 고침을 하거나 개발 서버를 다시 렌더링할 때마다 계속 바뀌지 않도록 하는 것이 중요합니다.27:53
그리고 핸들 메시지에 약간의 개선 사항이 추가되었습니다. 기본적으로 이제 타입(type)을 단순히 'any'로 받는 대신, 다음과 같이 변경될 예정입니다.27:59
이 버퍼 이벤트 유형을 처리하면서 포인터와 좌표에 접근할 수 있게 됩니다.28:05
화면에 표시되고, 포인터 이벤트와 관련된 데이터를 서버로부터 받을 때마다요.28:10
이곳을 지나 흘러갈 거예요. 그리고 이 방법은 여러 가지를 하고 있습니다.28:15
Xceledraw에 관심 있으시다면, API를 좀 더 자세히 살펴보시고 어떤 일이 일어나는지 직접 확인해 보시기를 권장 드립니다. 빠르게 지나가겠지만, 알아봐 주시면 감사하겠습니다.28:20
기본적으로, 사실 Xceladraw를 사용하면 협업자들에게 접근할 수 있습니다.28:26
지금 프로젝트와 함께 작업하고 계시는 분들과 비슷한 것이고, 이것은 그 모든 고유 사용자들을 나타내는 지도와 같습니다.28:30
기본적으로 협력자들을 모두 확보한 다음, 협력자 목록이나 맵을 생성하게 됩니다.28:37
그리고 나서 저희가 받아온 서버 데이터를 추가하고 있습니다.28:44
프로젝트를 진행하시는 분이 데이터를 서버에 보내셨다가 다시 여기로 돌아오는 과정을 상상해 보실 수 있을 겁니다.28:48
서버에서 들어오는 데이터로부터 해당 사용자 ID에 접근할 수 있습니다.28:54
저희는 그들의 좌표에 접근할 수 있으며, 협력자를 지정하고 있습니다.28:57
그리고 마지막으로, 여기서 우리가 할 일은 바로 그 API를 호출하는 것입니다.29:01
엑셀러드리 API와 관련하여, 협력자들과 새로운 업데이트 사항을 반영하여 장면을 갱신하고 있습니다.29:05
마우스의 위치, 특히 움직일 때 화면 위의 위치와 같은 정보들을 파악하는 것이 중요합니다.29:11
UI 측면에서는 이것이 전부입니다.29:15
Xceladry API에 간단히 연결해서 GitHub에 연결해 드리려고 합니다.29:19
이해하기가 조금 어려우실 수도 있다는 건 압니다. 꽤 여러 요소들이 움직이고 있어서요. 하지만 보시다시피, 여기로 오시면 이 페이지들을 새로 고쳐드립니다.29:23
오른쪽으로 이 부분을 움직여 보면, 아시겠지만, 그렇게 보입니다.29:29
좌측에서 그 포인터를 얻고, 그 반대의 경우에도 마찬가지입니다.29:33
방문 시 마우스 움직임이 시크릿 모드 탭에 반영되는 현상이 발생합니다.29:37
기본적으로 저희 서버가 있고, 클라이언트1이 서버로 데이터를 전송하는 것이 꽤 멋진 일인 것 같습니다.29:43
그 서버에서 클라이언트2로 데이터를 전송하고 있습니다.29:50
여기에서 혹시 다른 인코그니토 탭을 새로 열게 된다면요.29:52
여기서 쥐를 볼 예정입니다. 여기서 쥐를 보게 될 거예요.30:01
지금은 저희가 기본적으로 세 명의 사용자를 가지고 있습니다. 아마 눈치채셨을 텐데, 제가 새 창을 열 때...30:06
화면에 보이는 그림이 제대로 전달되지 않고 있습니다. 저희 모두 같은 팀임에도 불구하고요.30:12
그리고 그것은 동일한 드로잉 ID의 일부이며, 바로 다음 단계에서 구축해야 할 부분입니다.30:16
자, 그럼 시작해 볼까요?30:20
Xceladra API를 한번 살펴보면서 어떤 종류의 이벤트들을 지원하는지 정확히 파악해 보도록 하겠습니다.30:21
화면에서 그림이 그려지는 것처럼 발생할 때마다 데이터를 얻기 위해 들어주세요.30:27
이렇게 하면 해당 데이터가 저희 서버로 전송된 후, 엑셀라드라 세션에 현재 접속 중인 모든 클라이언트로 다시 전달될 수 있습니다.30:31
Xceladra 컴포넌트를 살펴보면, 변경 시 실행되는 on change 메서드가 있습니다.30:39
이를 통해 요소에 접근할 수 있고, 앱 상태에도 접근할 수 있습니다.30:43
그래서 지금부터 변경 사항을 확인하기 위해 로그아웃을 진행할 예정입니다.30:47
여기서 정확히 무슨 일이 일어나는지 파악하려고 합니다. 페이지를 새로고침하고, 이제 몇 가지 이동을 시작할 예정입니다.30:51
주변을 둘러보면, 이렇게 비어있는 배열이 있는데, 아마 이 안에 요소들이 들어있을 것이라고 추측됩니다.30:54
그리고 이 데이터 블록은 앱의 상태 정보를 담고 있습니다.30:58
이제 제가 화면에 무언가를 그려볼 텐데요, 지금 보시면 실제로 이 안에 요소가 하나 있다는 것을 확인할 수 있습니다.31:02
네, 좋습니다. 하나만 더 가져가겠습니다. 원을 넣어볼까요? 이제 여기 안에 두 개의 요소가 있습니다.31:08
저 요소의 외관, 크기에 대한 정보가 일부 포함되어 있다는 것을 알 수 있습니다.31:13
위치는 어디인지, 어떤 종류의 요소인지, 그리고 ID가 있으며, 그 외에도 흥미로운 정보들이 있습니다.31:19
이런 버전이 있으신 것 같고, 업데이트된 시간이 있으신 것 같습니다.31:23
마우스 움직임이나 클릭과 같은 변경 사항에 대한 이 동작만 살펴봐도 엄청난 양의 데이터가 전송되는 것을 알 수 있습니다.31:28
혹은 뭔가를 드래그했을 때도 이 이벤트에서 많은 데이터가 발생하므로, 지금은 이 데이터를 보고 리스너와 핸들러를 구축하기가 꽤 까다로울 수 있습니다.31:34
물론, 여러분도 아시는 것처럼요.31:39
화면에 천 개의 서로 다른 요소들이 있을 때, 뭐라고 해야 할까요?31:44
혹시 업데이트될 때마다 모든 요소를 서버에 전부 전송하실 계획이신가요?31:48
너무 많은 데이터가 주고받아질 것 같습니다. 만약 제가 실제 프로덕션 환경에서 이 작업을 진행한다면, 더 자세한 내용을 배우고 싶으시다면 권장하겠습니다.31:52
웹소켓을 기반으로 정말 멋진 시스템을 구축하는 방법에 대해 좀 더 알아가고 있습니다.32:00
견고한 제품들을 찾으시는군요. 혹시 엑셀러드로우에 관심이 있으시다면, 아마 제가 하셨을 만한 일은 웹사이트를 방문해 보시는 겁니다.32:04
앱 상태에서 무엇을 보고 있는지 확인하는 것이 중요합니다. 이전에는 제가 확인해보니...32:07
이것에는 선택된 요소 ID라고 불리는 속성이 기본적으로 존재합니다. 이 속성은 ID를 가지고 있습니다.32:12
현재 선택되어 있는 항목입니다. 따라서 선택된 항목을 이동할 때마다32:19
그 속성 내에서 보시면, 두 개의 이러한 ID가 있을 것입니다.32:23
보통 스케일 드로잉 작업 하실 때, 한 번에 하나 또는 두 개 정도만 움직이시는 경우가 많죠. 만약 이 시스템을 구축한다면, 저는 아마 이렇게 할 것 같습니다.32:27
그 사건이 발생하거나 변동되는 내용을 주의 깊게 듣고, 변경되거나 선택된 요소들을 수집하는 방식으로 진행할 것 같습니다.32:33
그리고 저는 그 데이터 중 실제로 유용한 부분을 분석하여 무언가 변경되었는지 알려드리려고 합니다.32:39
아마 그 전체 블록은 필요하지 않으실 것 같고, 이 요소 안에 있는 버전은 그대로 유지하시는 게 좋을 것 같습니다.32:45
매번 해당 요소가 움직일 때마다 버전이 증가하고, 서버로 전송될 것입니다. 그런 다음 백엔드에서는 이를 처리할 로직이 존재합니다.32:51
각각의 모든 요소를 꼼꼼히 추적하고, 최신 버전인지 확인하는 방식으로 진행하면 됩니다.32:59
만약 그렇다면 해당 요소의 값을 다른 모든 클라이언트에게 브로드캐스트하고, 상태를 업데이트해 주십시오.33:03
백엔드에서 그렇게 처리하면 항상 최신 버전을 유지할 수 있습니다.33:08
Xceladraw 그림의 상태에 대해 말씀드리자면, 제 생각과 비슷하게 진행되고 있는 것 같습니다.33:12
저희가 지금 실제로 사용하시는 엑셀러드로 도구에 구현하고 있습니다.33:16
그리고 그건 별로 중요하지 않아요. 지금 영상에 너무 깊이 들어가 있는 상태라서, 이 모든 걸 다 만들지는 않을 거예요. 괜히 영상만 길어지게 하고 싶지 않거든요.33:23
이 프로젝트가 정말 멋있다고 생각해요. 혹시 더 자세히 알고 싶으시다면, 한번 시도해 보시는 걸 추천드려요. 분명 많은 것을 배우실 수 있을 거예요.33:29
아시죠, 상태를 추적하는 방법, 경합 상태를 처리하는 방법, 그리고 실제로 여러 클라이언트에 데이터를 효율적으로 브로드캐스팅하는 방법 같은 것들을요.33:35
그러다가 그림이 정말 커지게 되면, 있잖아요, 데이터를 주고받는 양을 어떻게 줄여서 효율적으로 만들 수 있을까요?33:41
음, 이 기능, 즉 드로잉을 모든 클라이언트와 동기화하는 방식을 어떻게 구현할지 다시 말씀드리자면요.33:47
이런, 제가 간단하게 떠올린 아이디어가 있는데, 아직 실제 사용하기까지는 많이 부족하지만, 적어도 시작점으로는 괜찮을 것 같아요.33:53
요소들의 상태를 저희 서버로 전송해주시면, 이를 다양한 곳으로 전달할 수 있습니다.33:57
고객님들께, 포인터 업 이벤트가 있는데, 이것은 기본적으로 어떤 작업을 하시든 발생하는 이벤트입니다.34:02
물건을 움직이시거나 화살표를 그리시거나 무언가를 입력하실 때에는 보통 그래야 합니다.34:08
화살표를 눌러서 그렇게 하세요, 아니면 모든 키 명령을 사용하고 있다면요. 지금 이 방법은34:13
완벽한 해결책은 아니지만, 기본적으로 제가 할 일은 특정34:18
이벤트가 발생하는 이유는 로그를 끄기 전에는 실행되지 않기 때문입니다. 로그를 끄기 전에는 단 한번만 실행될 뿐입니다.34:23
마우스 클릭을 감지할 수 있을 때, 화면 주변을 움직일 때 사용하시면 됩니다.34:29
놔주세요. 그 상황이 발생했으니, 여기에서 우리가 할 수 있는 일은 마우스 조작입니다.34:33
포인터를 올려서 로그아웃하는 대신, 제가 할 것은 이미 이런 종류의 미리 만들어 놓은 것을 가지고 있다는 점입니다.34:38
하지만 저는 그러려고 합니다.34:42
API를 호출하여 장면 요소를 가져올 예정입니다. 이를 통해 가장 많은 정보를 얻을 수 있을 겁니다.34:46
최근 요소 장면의 버전을 확인해 보셨을 텐데, 이것이 굉장히 멀리 떨어져 있는 이유가 있습니다.34:51
제작 준비가 완료되면, 음, 이 전체 블록의 요소를 그냥 보내게 되는 방식입니다.34:56
매우 효율적이지 않을 뿐만 아니라, 여러 클라이언트가 동시에 이 작업을 수행할 수 있기 때문에 많은 경쟁 조건 문제가 발생할 수 있습니다. 서버는 이를 처리할 방법이 없을 것입니다.35:00
어떻게 화해하는지, 가장 최신 버전은 또 무엇인가요? 가장 최신 버전은 또 무엇인지 궁금합니다.35:07
이러한 요소들과 마찬가지로 서버가 그렇게 처리하는 것은 매우 어려울 것입니다. 따라서 이 방법은 적절하지 않습니다.35:12
만약 이것을 만들어서 사람들에게 공개한다면 그러지 마십시오. 하지만 저희의 사용 사례에 대해서는 제가 말씀드리는…35:16
제가 다시 방송을 켜서 알려드릴 것이고, 그때 제가 종료하는 것을 확인하실 수 있을 겁니다.35:19
이 분을 다시 불러와서, 페이지를 새로고침해 주시고, 살짝만 가져와 주세요.35:23
제가 이것을 가져가 보겠습니다. 한번 살펴볼까요?35:28
여기 보시면 이 게 있습니다. 그림을 그리고 마우스를 올려보시면 그 결과가 나타납니다.35:31
상태가 변경되었고, 서버로 전송된 후 다른 클라이언트로 다시 전파되었습니다.35:35
여기서도 같은 행동을 하십시오. 펑, 하고 터지네요. 그리고 또 펑, 하고 터지네요.35:38
적어도, 이랬던 것이 남아 있어서 다행이라고 할 수 있겠네요. 많이 남아있지는 않지만요.35:42
제가 말씀드린 것처럼 최종 버전과는 꽤 차이가 있지만, 음, 기본적으로 이 부분은...35:46
여기서 확인되는 것은 데이터가 주고받아지면서 서버로 전송되는 상황입니다.35:51
페이지를 새로고침하면 아무 곳에도 저장되지 않아서요.35:55
알겠습니다. 제가 여기다가 그림을 그리면, 아마 이런 모양이 나올 거예요.35:59
업데이트가 완료되었고, 다시 한번 이 페이지를 새로 고침한다고 가정해 보겠습니다. 이 캐릭터를 옮기면 펑 하고, 이제 완전히 사라졌습니다.36:04
음, 제가 다른 분을 위해 그림 자체를 지웠습니다.36:07
그것이 어느 정도 이 솔루션이 아직 프로덕션 환경에 바로 적용하기는 어려운 이유이기도 합니다만, 제가 생각하기에는 저희가…36:12
마지막으로 보여드리고 싶은 내구성 있는 객체에 대한 내용을 조금 더 설명드리자면, 어떻게 하는지에 대해 보여드리겠습니다.36:17
페이지를 새로고침하더라도, 내구성이 뛰어난 오브젝트에 요소 상태를 유지할 수 있도록 그렇게 하면 됩니다.36:21
그 요소들의 최신 버전을 가져올 수 있도록, 음, 네, 그럼 제가 할 일은요.36:26
백엔드로 이동해서 내구성이 보장되는 객체로 가볼 텐데요, 무엇을 할 수 있는지 확인해 보겠습니다.36:31
네, 그렇다면 'elements'라고 부르는 요소를 만들려고 합니다. 제가 이미 이렇게 적어 놓았거든요.36:37
이미 출발해서, 시간을 조금이라도 절약하기 위해 잠시 차를 세울게요. 네, 자, 무엇을 가지고 있는지 확인해볼까요?36:42
여기서 요소 배열이 있습니다. 이 요소 배열은 진행되고 있습니다.36:48
이 elements 배열은 클래스 레벨에서 정의될 예정이고, 이를 통해 마치 변수처럼 접근할 수 있습니다.36:55
이 비디오의 시작 부분에서 딕은 저희에게, 즉석 메모리 변수를 어떻게 활용할 수 있는지 보여주셨습니다.37:01
반론하는 것으로 보아, 기본적으로 같은 개념이겠지만, 생성자에서 이 클래스가37:06
처음으로 동시성 잠금을 구현할 때, 스토리지로 접근하게 됩니다.37:10
알려져 있다면, 모든 요소를 가져온 후 빈 배열로 기본 설정하도록 하겠습니다.37:14
이전에 저장된 요소가 전혀 없습니다. 그런 다음 저희가 할 수 있는 일은, 우리가 필요할 때마다 할 수 있도록 하는 것입니다.37:19
웹소켓 메시지를 수신하고, 해당 상태를 클라이언트로 다시 브로드캐스팅할 수 있습니다.37:24
추가 확인을 해야 하는데, 저희가 이미 해당 사용자 분께 답변을 드린 상황인 것 같습니다.37:29
그다음에는 조금 더 처리 진행하고, 간단하게 확인해 보도록 하겠습니다.37:33
아마 좀 더 깔끔하게 만들 수 있는 방법들이 있을 겁니다만, 시간을 고려해서 진행하겠습니다.37:37
메시지가 문자열인지 확인해야 합니다. 배열 버퍼일 수도 있는데, 기술적으로는 문자열로 정의할 수도 있을 것 같습니다.37:41
이런 확인 작업을 하지 않아도 될 텐데요. 그리고 나서 저희가 할 작업은 제가 이 버퍼 이벤트라는 것을 가지고 있다는 건데, 이건 일종의 타입이나 스키마, Zod 스키마와 같은 겁니다.37:47
시스템으로 전송되는 다양한 데이터 유형을 나타내는 것입니다.37:54
만약 요소 변경 유형이라면, 저희는 해당 요소를 업데이트할 예정입니다.37:58
그리고 나서 그 데이터를 저장 장치로 전송할 예정입니다. 말씀드린 것처럼, 여기까지 오셨다면...38:03
안녕하세요, 영상 보시는 분들께 몇 주 동안 생각하고 있던 아이디어를 간단히 소개해 드리고 싶습니다. 여러 분들께서 저에게 연락 주셔서, 혹시 강의를 만들거나 콘텐츠를 제작할 수 있는지 여쭤보셨어요.38:10
음, 긴 형식의 콘텐츠를 만드는 걸 사실 저는 그렇게 즐기는 편은 아니에요. 너무 길게 만드는 건 좀 그렇죠.38:16
유튜브에서 정말 잘 되는 것 같아요. 그런데, 솔직히 말씀드리면 대부분의 분들이 이렇게 긴 영상을 끝까지 시청할 집중력이 없을 거라고 생각하기도 합니다. 혹시, 이 영상을 보시면서 무언가를 얻고 싶으신 분이시라면요.38:21
이 콘텐츠가 정말 심도 있고 실습 위주이지만, 그래도 어느 정도 빠른 진행을 보여주는 것 같아요. 고려해 볼 만한 가치가 있겠네요.38:28
정말로 건축 과정을 상세하게 다루는 본격적인 강좌를 만들까 진지하게 고민하고 있습니다.38:32
포괄적인 사용자 인터페이스와 실제 양산 가능한 백엔드 서비스들을 갖추고 있는 것을 말씀하시는 것 같습니다.38:36
CICD 파이프라인과 버전 관리, 그리고 큐와 같은 시스템 위에 실제 데이터 시스템을 구축하는 것에 대해 잘 알고 있습니다.38:40
작업 흐름이 있고, 제가 만약 창작을 한다면 정말 다양한 각도에서 접근할 수 있을 것 같습니다.38:46
이런 다양한 프로젝트를 여러 고객들을 위해 진행하다 보니, 배우는 점이 많습니다.38:50
시장에서 진지한 무언가를 구축한 사람들에 대한 공백이 있는 것 같아요.38:53
클라우드플레어에 대해 정말 많은 분들이 가르치고 있지는 않은 것 같아서, 혹시 이 강의를 만들어볼까 생각 중입니다. 아직은 확정 지은 건 아니고, 그냥 관심이 있는지 한번 알아보고 싶어서요. 관심이 있는지 확인해 보려고 합니다.38:58
관심 있으시면 이메일 주소를 남겨주세요. 스팸 메일을 보내거나 연락드릴 일은 없을 것입니다.39:05
아마 메일을 보내서 어떤 콘텐츠가 흥미로울지 알려드릴 수도 있을 것 같아요.39:08
그리고 제가 강좌에 정말 관심 있는 분들이 많아지면, 저는 아마39:12
시간이 괜찮을 것 같아서 진행해 보려고 합니다. 네, 관심 있으시면 신청해주세요. 이만 할게요. 다음에 또 봐요.39:17
AI Summary
이 영상들은 Xceladraw를 활용한 실시간 협업 드로잉 애플리케이션 구축 방법을 다룹니다. Hono 프레임워크와 Cloudflare Durable Objects를 사용하여 서버리스 환경에서 WebSocket 서버를 구축하고, 실시간 데이터 동기화 및 상태 유지를 가능하게 합니다. 사용자 ID 관리, 데이터 전송 효율성, 데이터 타입 정의 등 다양한 기술적 세부 사항을 다루며, 향후 강의 제작 계획도 소개합니다. 핵심은 Xceladraw API, WebSocket, Durable Objects를 결합하여 실시간 협업 기능을 구현하는 것입니다.
Key Highlights
- •Xceladraw API를 활용하여 실시간 협업 드로잉 애플리케이션 구축
- •Cloudflare Durable Objects를 사용하여 서버리스 환경에서 상태 유지 및 데이터 동기화 구현
- •Hono 프레임워크를 사용하여 개발 효율성을 높임
- •WebSocket을 이용한 실시간 양방향 통신 구현
- •데이터 효율성을 높이기 위한 다양한 전략 (예: 변경 사항만 전송, 데이터 압축)