diff --git a/nestjs-BE/server/src/board-trees/board-trees.gateway.ts b/nestjs-BE/server/src/board-trees/board-trees.gateway.ts index d54c2e45..6d8a896a 100644 --- a/nestjs-BE/server/src/board-trees/board-trees.gateway.ts +++ b/nestjs-BE/server/src/board-trees/board-trees.gateway.ts @@ -60,10 +60,10 @@ export class BoardTreesGateway implements OnGatewayConnection { const { boardId, operation: serializedOperation } = payloadObject; const operationTypeMap = { - add: OperationAdd.parse, - delete: OperationDelete.parse, - move: OperationMove.parse, - update: OperationUpdate.parse, + add: OperationAdd.parse, + delete: OperationDelete.parse, + move: OperationMove.parse, + update: OperationUpdate.parse, }; const operation = diff --git a/nestjs-BE/server/src/board-trees/board-trees.service.ts b/nestjs-BE/server/src/board-trees/board-trees.service.ts index c115eef5..d8f39d1e 100644 --- a/nestjs-BE/server/src/board-trees/board-trees.service.ts +++ b/nestjs-BE/server/src/board-trees/board-trees.service.ts @@ -11,7 +11,7 @@ export class BoardTreesService { @InjectModel(BoardTree.name) private boardTreeModel: Model, ) {} - private boardTrees = new Map>(); + private boardTrees = new Map(); async create(boardId: string, tree: string) { const createdTree = new this.boardTreeModel({ @@ -33,16 +33,16 @@ export class BoardTreesService { async initBoardTree(boardId: string, boardName: string) { const existingTree = await this.findByBoardId(boardId); if (existingTree) { - this.boardTrees.set(boardId, CrdtTree.parse(existingTree.tree)); + this.boardTrees.set(boardId, CrdtTree.parse(existingTree.tree)); } else { - const newTree = new CrdtTree(boardId); + const newTree = new CrdtTree(boardId); newTree.tree.get('root').description = boardName; this.create(boardId, JSON.stringify(newTree)); this.boardTrees.set(boardId, newTree); } } - applyOperation(boardId: string, operation: Operation) { + applyOperation(boardId: string, operation: Operation) { const boardTree = this.boardTrees.get(boardId); boardTree.applyOperation(operation); } diff --git a/nestjs-BE/server/src/crdt/crdt-tree.spec.ts b/nestjs-BE/server/src/crdt/crdt-tree.spec.ts index 7adf6936..d3f7edb8 100644 --- a/nestjs-BE/server/src/crdt/crdt-tree.spec.ts +++ b/nestjs-BE/server/src/crdt/crdt-tree.spec.ts @@ -2,8 +2,8 @@ import { CrdtTree } from './crdt-tree'; import { Node } from './node'; it('crdt tree 동기화', () => { - const tree1 = new CrdtTree('1'); - const tree2 = new CrdtTree('2'); + const tree1 = new CrdtTree('1'); + const tree2 = new CrdtTree('2'); const op_1_1 = tree1.generateOperationAdd('a', 'root', 'hello'); const op_1_2 = tree1.generateOperationAdd('b', 'root', 'hi'); @@ -45,7 +45,7 @@ it('crdt tree 동기화', () => { }); it('crdt tree 역직렬화', () => { - const tree = new CrdtTree('1'); + const tree = new CrdtTree('1'); const op1 = tree.generateOperationAdd('a', 'root', 'hello'); const op2 = tree.generateOperationAdd('b', 'root', 'hi'); @@ -56,13 +56,13 @@ it('crdt tree 역직렬화', () => { expect(JSON.stringify(tree)); - const parsedTree = CrdtTree.parse(JSON.stringify(tree)); + const parsedTree = CrdtTree.parse(JSON.stringify(tree)); expect(JSON.stringify(tree)).toEqual(JSON.stringify(parsedTree)); }); it('crdt tree 순환', () => { - const tree = new CrdtTree('1'); + const tree = new CrdtTree('1'); const op1 = tree.generateOperationAdd('a', 'root', 'hello'); const op2 = tree.generateOperationAdd('b', 'root', 'hi'); @@ -72,5 +72,5 @@ it('crdt tree 순환', () => { const op6 = tree.generateOperationMove('b', 'a'); tree.applyOperations([op1, op2, op3, op4, op5, op6]); - expect((tree.tree.get('b') as Node).parentId).toEqual('root'); + expect((tree.tree.get('b') as Node).parentId).toEqual('root'); }); diff --git a/nestjs-BE/server/src/crdt/crdt-tree.ts b/nestjs-BE/server/src/crdt/crdt-tree.ts index 4400f116..2c0422ed 100644 --- a/nestjs-BE/server/src/crdt/crdt-tree.ts +++ b/nestjs-BE/server/src/crdt/crdt-tree.ts @@ -14,50 +14,50 @@ import { import { Tree } from './tree'; import { Node } from './node'; -export class CrdtTree { - operationLogs: OperationLog[] = []; +export class CrdtTree { + operationLogs: OperationLog[] = []; clock: Clock; - tree = new Tree(); + tree = new Tree(); constructor(id: string) { this.clock = new Clock(id); } - get(id: string): Node | undefined { + get(id: string): Node | undefined { return this.tree.get(id); } - addLog(log: OperationLog) { + addLog(log: OperationLog) { this.operationLogs.push(log); } generateOperationAdd( targetId: string, parentId: string, - description: T, - ): OperationAdd { + description: string, + ): OperationAdd { this.clock.increment(); const clock = this.clock.copy(); - const input: OperationAddInput = { + const input: OperationAddInput = { id: targetId, parentId, description, clock, }; - return new OperationAdd(input); + return new OperationAdd(input); } - generateOperationDelete(targetId: string): OperationDelete { + generateOperationDelete(targetId: string): OperationDelete { this.clock.increment(); const clock = this.clock.copy(); const input: OperationInput = { id: targetId, clock, }; - return new OperationDelete(input); + return new OperationDelete(input); } - generateOperationMove(targetId: string, parentId: string): OperationMove { + generateOperationMove(targetId: string, parentId: string): OperationMove { this.clock.increment(); const clock = this.clock.copy(); const input: OperationMoveInput = { @@ -65,24 +65,24 @@ export class CrdtTree { parentId, clock, }; - return new OperationMove(input); + return new OperationMove(input); } generateOperationUpdate( targetId: string, - description: T, - ): OperationUpdate { + description: string, + ): OperationUpdate { this.clock.increment(); const clock = this.clock.copy(); - const input: OperationUpdateInput = { + const input: OperationUpdateInput = { id: targetId, description, clock, }; - return new OperationUpdate(input); + return new OperationUpdate(input); } - applyOperation(operation: Operation) { + applyOperation(operation: Operation) { this.clock = this.clock.merge(operation.clock); if (this.operationLogs.length === 0) { @@ -94,7 +94,7 @@ export class CrdtTree { const lastOperation = this.operationLogs[this.operationLogs.length - 1].operation; if (operation.clock.compare(lastOperation.clock) === COMPARE.LESS) { - const prevLog = this.operationLogs.pop() as OperationLog; + const prevLog = this.operationLogs.pop() as OperationLog; prevLog.operation.undoOperation(this.tree, prevLog); this.applyOperation(operation); const redoLog = prevLog.operation.redoOperation(this.tree, prevLog); @@ -105,25 +105,25 @@ export class CrdtTree { } } - applyOperations(operations: Operation[]) { + applyOperations(operations: Operation[]) { for (const operation of operations) this.applyOperation(operation); } - static parse(json: string) { + static parse(json: string) { const parsedJson = JSON.parse(json); - const crdtTree = new CrdtTree('0'); + const crdtTree = new CrdtTree('0'); crdtTree.clock = Clock.parse(JSON.stringify(parsedJson.clock)); - crdtTree.tree = Tree.parse(JSON.stringify(parsedJson.tree)); + crdtTree.tree = Tree.parse(JSON.stringify(parsedJson.tree)); const operationTypeMap = { - add: OperationAdd.parse, - delete: OperationDelete.parse, - move: OperationMove.parse, - update: OperationUpdate.parse, + add: OperationAdd.parse, + delete: OperationDelete.parse, + move: OperationMove.parse, + update: OperationUpdate.parse, }; const parsedOperationLogs = parsedJson.operationLogs.map( - (operationLog: OperationLog) => { + (operationLog: OperationLog) => { const operationType = operationLog.operation.operationType; operationLog.operation = operationTypeMap[operationType]( operationLog.operation, diff --git a/nestjs-BE/server/src/crdt/node.spec.ts b/nestjs-BE/server/src/crdt/node.spec.ts index 61e6c470..20c4c9ae 100644 --- a/nestjs-BE/server/src/crdt/node.spec.ts +++ b/nestjs-BE/server/src/crdt/node.spec.ts @@ -1,8 +1,8 @@ import { Node } from './node'; it('node 역직렬화', () => { - const node = new Node('1', 'root', 'hello'); - const parsedNode = Node.parse(JSON.stringify(node)); + const node = new Node('1', 'root', 'hello'); + const parsedNode = Node.parse(JSON.stringify(node)); expect(JSON.stringify(node)).toEqual(JSON.stringify(parsedNode)); }); diff --git a/nestjs-BE/server/src/crdt/node.ts b/nestjs-BE/server/src/crdt/node.ts index 7e0303cb..66b76450 100644 --- a/nestjs-BE/server/src/crdt/node.ts +++ b/nestjs-BE/server/src/crdt/node.ts @@ -1,22 +1,22 @@ -export class Node { +export class Node { targetId: string; parentId: string; - description: T | null; + description?: string; children = new Array(); constructor( targetId: string, parentId: string = '0', - description: T | null = null, + description: string = null, ) { this.targetId = targetId; this.parentId = parentId; this.description = description; } - static parse(json: string) { + static parse(json: string) { const parsedJson = JSON.parse(json); - const node = new Node( + const node = new Node( parsedJson.targetId, parsedJson.parentId, parsedJson.description, diff --git a/nestjs-BE/server/src/crdt/operation.ts b/nestjs-BE/server/src/crdt/operation.ts index 42836c8e..f742c0e4 100644 --- a/nestjs-BE/server/src/crdt/operation.ts +++ b/nestjs-BE/server/src/crdt/operation.ts @@ -2,10 +2,10 @@ import { Clock } from './clock'; import { Node } from './node'; import { Tree } from './tree'; -export interface OperationLog { - operation: Operation; +export interface OperationLog { + operation: Operation; oldParentId?: string; - oldDescription?: T | null; + oldDescription?: string | null; } export interface OperationInput { @@ -13,8 +13,8 @@ export interface OperationInput { clock: Clock; } -export interface OperationAddInput extends OperationInput { - description: T; +export interface OperationAddInput extends OperationInput { + description: string; parentId: string; } @@ -22,8 +22,8 @@ export interface OperationMoveInput extends OperationInput { parentId: string; } -export interface OperationUpdateInput extends OperationInput { - description: T; +export interface OperationUpdateInput extends OperationInput { + description: string; } interface ClockInterface { @@ -31,15 +31,15 @@ interface ClockInterface { counter: number; } -export interface SerializedOperation { +export interface SerializedOperation { operationType: string; id: string; clock: ClockInterface; - description?: T; + description?: string; parentId?: string; } -export abstract class Operation { +export abstract class Operation { operationType: string; id: string; clock: Clock; @@ -50,75 +50,71 @@ export abstract class Operation { this.clock = clock; } - abstract doOperation(tree: Tree): OperationLog; - abstract undoOperation(tree: Tree, log: OperationLog): void; - abstract redoOperation(tree: Tree, log: OperationLog): OperationLog; + abstract doOperation(tree: Tree): OperationLog; + abstract undoOperation(tree: Tree, log: OperationLog): void; + abstract redoOperation(tree: Tree, log: OperationLog): OperationLog; } -export class OperationAdd extends Operation { - description: T; +export class OperationAdd extends Operation { + description: string; parentId: string; - constructor(input: OperationAddInput) { + constructor(input: OperationAddInput) { super('add', input.id, input.clock); this.description = input.description; this.parentId = input.parentId; } - doOperation(tree: Tree): OperationLog { + doOperation(tree: Tree): OperationLog { tree.addNode(this.id, this.parentId, this.description); return { operation: this }; } - undoOperation(tree: Tree, log: OperationLog): void { + undoOperation(tree: Tree, log: OperationLog): void { tree.removeNode(log.operation.id); } - redoOperation(tree: Tree, log: OperationLog): OperationLog { + redoOperation(tree: Tree, log: OperationLog): OperationLog { tree.attachNode(log.operation.id, this.parentId); return { operation: this }; } - static parse( - serializedOperation: SerializedOperation, - ): OperationAdd { - const input: OperationAddInput = { + static parse(serializedOperation: SerializedOperation): OperationAdd { + const input: OperationAddInput = { id: serializedOperation.id, parentId: serializedOperation.parentId as string, - description: serializedOperation.description as T, + description: serializedOperation.description as string, clock: new Clock( serializedOperation.clock.id, serializedOperation.clock.counter, ), }; - return new OperationAdd(input); + return new OperationAdd(input); } } -export class OperationDelete extends Operation { +export class OperationDelete extends Operation { constructor(input: OperationInput) { super('delete', input.id, input.clock); } - doOperation(tree: Tree): OperationLog { - const node = tree.get(this.id) as Node; + doOperation(tree: Tree): OperationLog { + const node = tree.get(this.id) as Node; const oldParentId = node.parentId; tree.removeNode(this.id); return { operation: this, oldParentId: oldParentId }; } - undoOperation(tree: Tree, log: OperationLog): void { + undoOperation(tree: Tree, log: OperationLog): void { tree.attachNode(log.operation.id, log.oldParentId as string); } - redoOperation(tree: Tree, log: OperationLog): OperationLog { + redoOperation(tree: Tree, log: OperationLog): OperationLog { const redoLog = log.operation.doOperation(tree); return redoLog; } - static parse( - serializedOperation: SerializedOperation, - ): OperationDelete { + static parse(serializedOperation: SerializedOperation): OperationDelete { const input: OperationInput = { id: serializedOperation.id, clock: new Clock( @@ -126,11 +122,11 @@ export class OperationDelete extends Operation { serializedOperation.clock.counter, ), }; - return new OperationDelete(input); + return new OperationDelete(input); } } -export class OperationMove extends Operation { +export class OperationMove extends Operation { parentId: string; constructor(input: OperationMoveInput) { @@ -138,8 +134,8 @@ export class OperationMove extends Operation { this.parentId = input.parentId; } - doOperation(tree: Tree): OperationLog { - const node = tree.get(this.id) as Node; + doOperation(tree: Tree): OperationLog { + const node = tree.get(this.id) as Node; const oldParentId = node.parentId; if (tree.isAncestor(this.parentId, this.id)) { @@ -151,19 +147,17 @@ export class OperationMove extends Operation { return { operation: this, oldParentId }; } - undoOperation(tree: Tree, log: OperationLog): void { + undoOperation(tree: Tree, log: OperationLog): void { tree.removeNode(log.operation.id); tree.attachNode(log.operation.id, log.oldParentId as string); } - redoOperation(tree: Tree, log: OperationLog): OperationLog { + redoOperation(tree: Tree, log: OperationLog): OperationLog { const redoLog = log.operation.doOperation(tree); return redoLog; } - static parse( - serializedOperation: SerializedOperation, - ): OperationMove { + static parse(serializedOperation: SerializedOperation): OperationMove { const input: OperationMoveInput = { id: serializedOperation.id, parentId: serializedOperation.parentId as string, @@ -172,45 +166,43 @@ export class OperationMove extends Operation { serializedOperation.clock.counter, ), }; - return new OperationMove(input); + return new OperationMove(input); } } -export class OperationUpdate extends Operation { - description: T; +export class OperationUpdate extends Operation { + description: string; - constructor(input: OperationUpdateInput) { + constructor(input: OperationUpdateInput) { super('update', input.id, input.clock); this.description = input.description; } - doOperation(tree: Tree): OperationLog { - const node = tree.get(this.id) as Node; + doOperation(tree: Tree): OperationLog { + const node = tree.get(this.id) as Node; const oldDescription = node.description; tree.updateNode(this.id, this.description); return { operation: this, oldDescription: oldDescription }; } - undoOperation(tree: Tree, log: OperationLog): void { - tree.updateNode(log.operation.id, log.oldDescription as T); + undoOperation(tree: Tree, log: OperationLog): void { + tree.updateNode(log.operation.id, log.oldDescription as string); } - redoOperation(tree: Tree, log: OperationLog): OperationLog { + redoOperation(tree: Tree, log: OperationLog): OperationLog { const redoLog = log.operation.doOperation(tree); return redoLog; } - static parse( - serializedOperation: SerializedOperation, - ): OperationUpdate { - const input: OperationUpdateInput = { + static parse(serializedOperation: SerializedOperation): OperationUpdate { + const input: OperationUpdateInput = { id: serializedOperation.id, - description: serializedOperation.description as T, + description: serializedOperation.description as string, clock: new Clock( serializedOperation.clock.id, serializedOperation.clock.counter, ), }; - return new OperationUpdate(input); + return new OperationUpdate(input); } } diff --git a/nestjs-BE/server/src/crdt/tree.spec.ts b/nestjs-BE/server/src/crdt/tree.spec.ts index cf9da0ce..d8fe2c3e 100644 --- a/nestjs-BE/server/src/crdt/tree.spec.ts +++ b/nestjs-BE/server/src/crdt/tree.spec.ts @@ -1,7 +1,7 @@ import { Tree } from './tree'; it('isAncestor', () => { - const tree = new Tree(); + const tree = new Tree(); tree.addNode('a', 'root', 'test'); tree.addNode('b', 'a', 'test'); diff --git a/nestjs-BE/server/src/crdt/tree.ts b/nestjs-BE/server/src/crdt/tree.ts index a39cc063..7938f148 100644 --- a/nestjs-BE/server/src/crdt/tree.ts +++ b/nestjs-BE/server/src/crdt/tree.ts @@ -1,18 +1,18 @@ import { Node } from './node'; -export class Tree { - nodes = new Map>(); +export class Tree { + nodes = new Map(); constructor() { - this.nodes.set('root', new Node('root')); + this.nodes.set('root', new Node('root')); } - get(id: string): Node | undefined { + get(id: string): Node | undefined { return this.nodes.get(id); } - addNode(targetId: string, parentId: string, description: T) { - const newNode = new Node(targetId, parentId, description); + addNode(targetId: string, parentId: string, description: string) { + const newNode = new Node(targetId, parentId, description); const parentNode = this.nodes.get(parentId); if (!parentNode) return; @@ -32,7 +32,7 @@ export class Tree { targetNode.parentId = parentId; } - removeNode(targetId: string): Node | undefined { + removeNode(targetId: string): Node | undefined { const targetNode = this.nodes.get(targetId); if (!targetNode) return; @@ -46,7 +46,7 @@ export class Tree { return this.nodes.get(targetId); } - updateNode(targetId: string, description: T) { + updateNode(targetId: string, description: string) { const targetNode = this.nodes.get(targetId); if (!targetNode) return; @@ -66,12 +66,12 @@ export class Tree { return false; } - static parse(json: string) { + static parse(json: string) { const { nodes } = JSON.parse(json); - const tree = new Tree(); - tree.nodes = new Map>(); + const tree = new Tree(); + tree.nodes = new Map(); nodes.forEach((nodeJson) => { - const node = Node.parse(JSON.stringify(nodeJson)); + const node = Node.parse(JSON.stringify(nodeJson)); tree.nodes.set(node.targetId, node); }); return tree;