Skip to content

Commit

Permalink
Merge pull request #169 from boostcampwm-2024/Feature/#168_블록_드래그앤드랍_…
Browse files Browse the repository at this point in the history
…서버_반영

Feature/#168 블록 드래그앤드랍 서버 반영
  • Loading branch information
github-actions[bot] authored Nov 22, 2024
2 parents b1c08f0 + bf8a7f4 commit 10d835f
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 20 deletions.
19 changes: 11 additions & 8 deletions @noctaCrdt/Crdt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
RemoteBlockInsertOperation,
RemoteCharInsertOperation,
CRDTSerializedProps,
RemoteReorderOperation,
RemoteBlockReorderOperation,
RemoteBlockUpdateOperation,
} from "./Interfaces";

Expand Down Expand Up @@ -149,20 +149,25 @@ export class EditorCRDT extends CRDT<Block> {
targetId: BlockId;
beforeId: BlockId | null;
afterId: BlockId | null;
}): RemoteReorderOperation {
const operation: RemoteReorderOperation = {
pageId: string;
}): RemoteBlockReorderOperation {
const operation: RemoteBlockReorderOperation = {
...params,
clock: this.clock,
client: this.client,
};

this.LinkedList.reorderNodes(params);
this.LinkedList.reorderNodes({
targetId: params.targetId,
beforeId: params.beforeId,
afterId: params.afterId,
});
this.clock += 1;

return operation;
}

remoteReorder(operation: RemoteReorderOperation): void {
remoteReorder(operation: RemoteBlockReorderOperation): void {
const { targetId, beforeId, afterId, clock } = operation;

this.LinkedList.reorderNodes({
Expand All @@ -171,9 +176,7 @@ export class EditorCRDT extends CRDT<Block> {
afterId,
});

if (this.clock <= clock) {
this.clock = clock + 1;
}
this.clock = Math.max(this.clock, clock) + 1;
}

serialize(): CRDTSerializedProps<Block> {
Expand Down
3 changes: 2 additions & 1 deletion @noctaCrdt/Interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,11 @@ export interface WorkSpaceSerializedProps {
pageList: Page[];
authUser: Map<string, string>;
}
export interface RemoteReorderOperation {
export interface RemoteBlockReorderOperation {
targetId: BlockId;
beforeId: BlockId | null;
afterId: BlockId | null;
clock: number;
client: number;
pageId: string;
}
23 changes: 13 additions & 10 deletions client/src/features/editor/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,6 @@ export interface EditorStateProps {
}
// TODO: pageId, editorCRDT를 props로 받아와야함
export const Editor = ({ onTitleChange, pageId, serializedEditorData }: EditorProps) => {
/*
const {
sendCharInsertOperation,
sendCharDeleteOperation,
subscribeToRemoteOperations,
sendBlockInsertOperation,
sendBlockDeleteOperation,
sendBlockUpdateOperation,
} = useSocket();
*/
const {
sendCharInsertOperation,
sendCharDeleteOperation,
Expand All @@ -62,6 +52,7 @@ export const Editor = ({ onTitleChange, pageId, serializedEditorData }: EditorPr
editorCRDT: editorCRDT.current,
editorState,
setEditorState,
pageId,
});

const { handleKeyDown } = useMarkdownGrammer({
Expand Down Expand Up @@ -222,6 +213,18 @@ export const Editor = ({ onTitleChange, pageId, serializedEditorData }: EditorPr
currentBlock: prev.currentBlock,
}));
},

onRemoteBlockReorder: (operation) => {
console.log(operation, "block : 재정렬 확인합니다이");
if (!editorCRDT.current) return;
editorCRDT.current.remoteReorder(operation);
setEditorState((prev) => ({
clock: editorCRDT.current.clock,
linkedList: editorCRDT.current.LinkedList,
currentBlock: prev.currentBlock,
}));
},

onRemoteCursor: (position) => {
console.log(position, "커서위치 수신");
},
Expand Down
10 changes: 9 additions & 1 deletion client/src/features/editor/hooks/useBlockDragAndDrop.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
// hooks/useBlockDragAndDrop.ts
import { DragEndEvent, PointerSensor, useSensor, useSensors } from "@dnd-kit/core";
import { EditorCRDT } from "@noctaCrdt/Crdt";
import { useSocketStore } from "@src/stores/useSocketStore.ts";
import { EditorStateProps } from "../Editor";

interface UseBlockDragAndDropProps {
editorCRDT: EditorCRDT;
editorState: EditorStateProps;
setEditorState: React.Dispatch<React.SetStateAction<EditorStateProps>>;
pageId: string;
}

export const useBlockDragAndDrop = ({
editorCRDT,
editorState,
setEditorState,
pageId,
}: UseBlockDragAndDropProps) => {
const sensors = useSensors(
useSensor(PointerSensor, {
Expand All @@ -22,6 +25,8 @@ export const useBlockDragAndDrop = ({
}),
);

const { sendBlockReorderOperation } = useSocketStore();

const handleDragEnd = (event: DragEndEvent) => {
const { active, over } = event;

Expand Down Expand Up @@ -73,12 +78,15 @@ export const useBlockDragAndDrop = ({
}

// EditorCRDT의 현재 상태로 작업
editorCRDT.localReorder({
const operation = editorCRDT.localReorder({
targetId: targetNode.id,
beforeId: beforeNode?.id || null,
afterId: afterNode?.id || null,
pageId,
});

sendBlockReorderOperation(operation);

// EditorState 업데이트
setEditorState({
clock: editorCRDT.clock,
Expand Down
10 changes: 10 additions & 0 deletions client/src/stores/useSocketStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
RemoteCharInsertOperation,
RemoteCharDeleteOperation,
RemoteBlockUpdateOperation,
RemoteBlockReorderOperation,
CursorPosition,
WorkSpaceSerializedProps,
} from "@noctaCrdt/Interfaces";
Expand All @@ -24,6 +25,7 @@ interface SocketStore {
sendCharInsertOperation: (operation: RemoteCharInsertOperation) => void;
sendBlockDeleteOperation: (operation: RemoteBlockDeleteOperation) => void;
sendCharDeleteOperation: (operation: RemoteCharDeleteOperation) => void;
sendBlockReorderOperation: (operation: RemoteBlockReorderOperation) => void;
sendCursorPosition: (position: CursorPosition) => void;
subscribeToRemoteOperations: (handlers: RemoteOperationHandlers) => (() => void) | undefined;
subscribeToPageOperations: (handlers: PageOperationsHandlers) => (() => void) | undefined;
Expand All @@ -34,6 +36,7 @@ interface RemoteOperationHandlers {
onRemoteBlockUpdate: (operation: RemoteBlockUpdateOperation) => void;
onRemoteBlockInsert: (operation: RemoteBlockInsertOperation) => void;
onRemoteBlockDelete: (operation: RemoteBlockDeleteOperation) => void;
onRemoteBlockReorder: (operation: RemoteBlockReorderOperation) => void;
onRemoteCharInsert: (operation: RemoteCharInsertOperation) => void;
onRemoteCharDelete: (operation: RemoteCharDeleteOperation) => void;
onRemoteCursor: (position: CursorPosition) => void;
Expand Down Expand Up @@ -146,13 +149,19 @@ export const useSocketStore = create<SocketStore>((set, get) => ({
socket?.emit("cursor", position);
},

sendBlockReorderOperation: (operation: RemoteBlockReorderOperation) => {
const { socket } = get();
socket?.emit("reorder/block", operation);
},

subscribeToRemoteOperations: (handlers: RemoteOperationHandlers) => {
const { socket } = get();
if (!socket) return;

socket.on("update/block", handlers.onRemoteBlockUpdate);
socket.on("insert/block", handlers.onRemoteBlockInsert);
socket.on("delete/block", handlers.onRemoteBlockDelete);
socket.on("reorder/block", handlers.onRemoteBlockReorder);
socket.on("insert/char", handlers.onRemoteCharInsert);
socket.on("delete/char", handlers.onRemoteCharDelete);
socket.on("cursor", handlers.onRemoteCursor);
Expand All @@ -161,6 +170,7 @@ export const useSocketStore = create<SocketStore>((set, get) => ({
socket.off("update/block", handlers.onRemoteBlockUpdate);
socket.off("insert/block", handlers.onRemoteBlockInsert);
socket.off("delete/block", handlers.onRemoteBlockDelete);
socket.off("reorder/block", handlers.onRemoteBlockReorder);
socket.off("insert/char", handlers.onRemoteCharInsert);
socket.off("delete/char", handlers.onRemoteCharDelete);
socket.off("cursor", handlers.onRemoteCursor);
Expand Down
38 changes: 38 additions & 0 deletions server/src/crdt/crdt.gateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
RemoteCharInsertOperation,
RemoteBlockUpdateOperation,
RemotePageCreateOperation,
RemoteBlockReorderOperation,
CursorPosition,
} from "@noctaCrdt/Interfaces";
import { Logger } from "@nestjs/common";
Expand Down Expand Up @@ -362,6 +363,43 @@ export class CrdtGateway implements OnGatewayInit, OnGatewayConnection, OnGatewa
}
}

@SubscribeMessage("reorder/block")
async handleBlockReorder(
@MessageBody() data: RemoteBlockReorderOperation,
@ConnectedSocket() client: Socket,
): Promise<void> {
const clientInfo = this.clientMap.get(client.id);
try {
this.logger.debug(
`블록 Reorder 연산 수신 - Client ID: ${clientInfo?.clientId}, Data:`,
JSON.stringify(data),
);
// 1. 워크스페이스 가져오기
const workspace = this.workSpaceService.getWorkspace();

const currentPage = workspace.pageList.find((p) => p.id === data.pageId);
if (!currentPage) {
throw new Error(`Page with id ${data.pageId} not found`);
}
currentPage.crdt.remoteReorder(data);

// 5. 다른 클라이언트들에게 업데이트된 블록 정보 브로드캐스트
const operation = {
targetId: data.targetId,
beforeId: data.beforeId,
afterId: data.afterId,
pageId: data.pageId,
} as RemoteBlockReorderOperation;
client.broadcast.emit("reorder/block", operation);
} catch (error) {
this.logger.error(
`블록 Reorder 연산 처리 중 오류 발생 - Client ID: ${clientInfo?.clientId}`,
error.stack,
);
throw new WsException(`Update 연산 실패: ${error.message}`);
}
}

/**
* 커서 위치 업데이트 처리
*/
Expand Down

0 comments on commit 10d835f

Please sign in to comment.