Skip to content

Commit

Permalink
Merge pull request #187 from boostcampwm-2024/feature-#186
Browse files Browse the repository at this point in the history
websocket 서버를 SocketIO로 변경
  • Loading branch information
ezcolin2 authored Nov 18, 2024
2 parents 8891fbf + c07b044 commit 773d59b
Show file tree
Hide file tree
Showing 10 changed files with 255 additions and 43 deletions.
Binary file added apps/backend/db
Binary file not shown.
11 changes: 7 additions & 4 deletions apps/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,26 @@
"@nestjs/core": "^10.0.0",
"@nestjs/mapped-types": "*",
"@nestjs/platform-express": "^10.0.0",
"@nestjs/platform-socket.io": "^10.4.8",
"@nestjs/platform-ws": "^10.4.7",
"@nestjs/serve-static": "^4.0.2",
"@nestjs/swagger": "^8.0.5",
"@nestjs/typeorm": "^10.0.2",
"@nestjs/websockets": "^10.4.7",
"@nestjs/websockets": "^10.4.8",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.1",
"lib0": "^0.2.98",
"path": "^0.12.7",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.8.1",
"socket.io": "^4.8.1",
"sqlite3": "^5.1.7",
"typeorm": "^0.3.20",
"ws": "^8.18.0",
"ws": "^8.14.2",
"y-protocols": "^1.0.6",
"y-websocket": "^1.4.0",
"yjs": "^13.6.20"
"y-socket.io": "^1.1.3",
"y-websocket": "^1.5.0",
"yjs": "^13.6.8"
},
"devDependencies": {
"@nestjs/cli": "^10.0.0",
Expand Down
5 changes: 3 additions & 2 deletions apps/backend/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { HttpExceptionFilter } from './filter/http-exception.filter';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { WsAdapter } from '@nestjs/platform-ws';
import { IoAdapter } from '@nestjs/platform-socket.io';

import * as dotenv from 'dotenv';
dotenv.config();

async function bootstrap() {
const app = await NestFactory.create(AppModule);

app.useWebSocketAdapter(new WsAdapter(app));
app.useWebSocketAdapter(new IoAdapter(app));
app.useGlobalFilters(new HttpExceptionFilter());
app.setGlobalPrefix('api');

Expand Down
65 changes: 52 additions & 13 deletions apps/backend/src/yjs/yjs.service.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,59 @@
import { Injectable, OnModuleInit, Logger } from '@nestjs/common';
import * as WebSocket from 'ws';
import { setupWSConnection } from 'y-websocket/bin/utils';
import {
OnGatewayConnection,
OnGatewayDisconnect,
OnGatewayInit,
WebSocketGateway,
WebSocketServer,
} from '@nestjs/websockets';
import { Logger } from '@nestjs/common';
import { Server } from 'socket.io';
import { YSocketIO } from 'y-socket.io/dist/server';
import * as Y from 'yjs';

@Injectable()
export class YjsService implements OnModuleInit {
private wss: WebSocket.Server;
private logger = new Logger('YjsService');
@WebSocketGateway(1234)
export class YjsService
implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect
{
private logger = new Logger('YjsGateway');
private ysocketio: YSocketIO;

onModuleInit() {
this.wss = new WebSocket.Server({ port: 1234 });
@WebSocketServer()
server: Server;

this.wss.on('connection', (ws: WebSocket, req: any) => {
this.logger.log('Client connected');
setupWSConnection(ws, req);
afterInit() {
if (!this.server) {
this.logger.error('서버 초기화 안됨..!');
this.server = new Server();
}

this.ysocketio = new YSocketIO(this.server, {
gcEnabled: true,
});

this.ysocketio.initialize();

this.ysocketio.on('document-loaded', (doc: Y.Doc) => {
this.logger.log(`Document loaded: ${doc.guid}`);

const titleMap = doc.getMap('title');
titleMap.observe(() => {
console.log(titleMap.toString());
});
// const toggleMap = doc.getMap('toggleMap');
// toggleMap.observe(() => {
// const toggleState = toggleMap.get('toggle') || false;
// this.logger.log('🐰 토글 상태 변경', {
// toggleState,
// });
// });
});
}

handleConnection() {
this.logger.log('접속');
}

this.logger.log('WebSocket server initialized on port 1234');
handleDisconnect() {
this.logger.log('접속 해제');
}
}
1 change: 1 addition & 0 deletions apps/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"use-debounce": "^10.0.4",
"y-prosemirror": "^1.2.12",
"y-protocols": "^1.0.6",
"y-socket.io": "^1.1.3",
"y-websocket": "^2.0.4",
"yjs": "^13.6.20",
"zustand": "^5.0.1"
Expand Down
13 changes: 11 additions & 2 deletions apps/frontend/src/components/EditorView.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useMemo, useState } from "react";
import { EditorInstance } from "novel";
import { useDebouncedCallback } from "use-debounce";
import { WebsocketProvider } from "y-websocket";
import * as Y from "yjs";
import { SocketIOProvider } from "y-socket.io";

import Editor from "./editor";
import usePageStore from "@/store/usePageStore";
Expand All @@ -21,10 +21,19 @@ export default function EditorView() {
}, [currentPage]);

const provider = useMemo(() => {
return new WebsocketProvider(
return new SocketIOProvider(
import.meta.env.VITE_WS_URL,
`document-${currentPage}`,
ydoc,
{
autoConnect: true,
disableBc: false,
},
{
reconnectionDelayMax: 10000,
timeout: 5000,
transports: ["websocket", "polling"],
},
);
}, [currentPage]);

Expand Down
18 changes: 14 additions & 4 deletions apps/frontend/src/components/canvas/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ import "@xyflow/react/dist/style.css";
import { usePages } from "@/hooks/usePages";
import { NoteNode } from "./NoteNode";
import * as Y from "yjs";
import { WebsocketProvider } from "y-websocket";
// import { WebsocketProvider } from "y-websocket";
import { SocketIOProvider } from "y-socket.io";
import { cn } from "@/lib/utils";
import { useQueryClient } from "@tanstack/react-query";
import useYDocStore from "@/store/useYDocStore";
Expand Down Expand Up @@ -48,7 +49,7 @@ function Flow({ className }: CanvasProps) {
roomName: "flow-room",
});

const provider = useRef<WebsocketProvider>();
const provider = useRef<SocketIOProvider>();
const existingPageIds = useRef(new Set<string>());

useEffect(() => {
Expand All @@ -69,10 +70,19 @@ function Flow({ className }: CanvasProps) {
useEffect(() => {
if (!ydoc) return;

const wsProvider = new WebsocketProvider(
const wsProvider = new SocketIOProvider(
import.meta.env.VITE_WS_URL,
"flow-room",
`flow-room`,
ydoc,
{
autoConnect: true,
disableBc: false,
},
{
reconnectionDelayMax: 10000,
timeout: 5000,
transports: ["websocket", "polling"],
},
);

provider.current = wsProvider;
Expand Down
4 changes: 2 additions & 2 deletions apps/frontend/src/components/editor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import {
import { ImageResizer, handleCommandNavigation } from "novel/extensions";
import Collaboration from "@tiptap/extension-collaboration";
import CollaborationCursor from "@tiptap/extension-collaboration-cursor";
import { WebsocketProvider } from "y-websocket";
import * as Y from "yjs";
import { SocketIOProvider } from "y-socket.io";

import "./prosemirror.css";
import { slashCommand, suggestionItems } from "./slash-commands";
Expand All @@ -36,7 +36,7 @@ interface EditorProp {
initialContent?: JSONContent;
onEditorUpdate?: (event: EditorUpdateEvent) => void;
ydoc: Y.Doc;
provider: WebsocketProvider;
provider: SocketIOProvider;
}

const Editor = ({
Expand Down
17 changes: 13 additions & 4 deletions apps/frontend/src/hooks/useCursor.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useReactFlow, type XYPosition } from "@xyflow/react";
import * as Y from "yjs";
import { useCallback, useEffect, useRef, useState } from "react";
import { WebsocketProvider } from "y-websocket";
import { SocketIOProvider } from "y-socket.io";

const CURSOR_COLORS = [
"#7d7b94",
Expand Down Expand Up @@ -29,7 +29,7 @@ export function useCollaborativeCursors({
roomName = "cursor-room",
}: CollaborativeCursorsProps) {
const flowInstance = useReactFlow();
const provider = useRef<WebsocketProvider>();
const provider = useRef<SocketIOProvider>();
const [cursors, setCursors] = useState<Map<number, AwarenessState>>(
new Map(),
);
Expand All @@ -39,10 +39,19 @@ export function useCollaborativeCursors({
);

useEffect(() => {
const wsProvider = new WebsocketProvider(
const wsProvider = new SocketIOProvider(
import.meta.env.VITE_WS_URL,
roomName,
`flow-room`,
ydoc,
{
autoConnect: true,
disableBc: false,
},
{
reconnectionDelayMax: 10000,
timeout: 5000,
transports: ["websocket", "polling"],
},
);

provider.current = wsProvider;
Expand Down
Loading

0 comments on commit 773d59b

Please sign in to comment.