Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…into Feature/#119_모달_공통_컴포넌트_구현
  • Loading branch information
pipisebastian committed Nov 15, 2024
2 parents 7d3bd6c + 778ec9a commit 8266ba9
Show file tree
Hide file tree
Showing 14 changed files with 303 additions and 367 deletions.
113 changes: 44 additions & 69 deletions @noctaCrdt/Crdt.ts
Original file line number Diff line number Diff line change
@@ -1,136 +1,111 @@
import { LinkedList } from "./LinkedList";
import { NodeId, Node } from "./Node";
import {
RemoteInsertOperation,
RemoteDeleteOperation,
SerializedProps,
Block,
Char,
CRDT as CRDTClassProps,
} from "./Interfaces";

export class CRDT implements CRDTClassProps {
import { CharId, BlockId, NodeId } from "./NodeId";
import { Node, Char, Block } from "./Node";
import { RemoteDeleteOperation, RemoteInsertOperation, SerializedProps } from "./Interfaces";

export class CRDT<T extends Node<NodeId>> {
clock: number;
client: number;
LinkedList: LinkedList;
LinkedList: LinkedList<T>;

constructor(client: number) {
this.clock = 0; // 이 CRDT의 논리적 시간 설정
this.clock = 0;
this.client = client;
this.LinkedList = new LinkedList();
this.LinkedList = new LinkedList<T>();
}

/**
* 로컬에서 삽입 연산을 수행하고, 원격에 전파할 연산 객체를 반환합니다.
* @param index 삽입할 인덱스
* @param value 삽입할 값
* @returns 원격에 전파할 삽입 연산 객체
*/
localInsert(index: number, value: string): RemoteInsertOperation {
const id = new NodeId((this.clock += 1), this.client);
const id =
this instanceof BlockCRDT
? new CharId(this.clock + 1, this.client)
: new BlockId(this.clock + 1, this.client);

const remoteInsertion = this.LinkedList.insertAtIndex(index, value, id);
this.clock += 1;
return { node: remoteInsertion.node };
}

/**
* 로컬에서 삭제 연산을 수행하고, 원격에 전파할 연산 객체를 반환합니다.
* @param index 삭제할 인덱스
* @returns 원격에 전파할 삭제 연산 객체
*/
localDelete(index: number): RemoteDeleteOperation {
// 유효한 인덱스인지 확인
if (index < 0 || index >= this.LinkedList.spread().length) {
throw new Error(`유효하지 않은 인덱스입니다: ${index}`);
throw new Error(`Invalid index: ${index}`);
}

// 삭제할 노드 찾기
const nodeToDelete = this.LinkedList.findByIndex(index);
if (!nodeToDelete) {
throw new Error(`삭제할 노드를 찾을 수 없습니다. 인덱스: ${index}`);
throw new Error(`Node not found at index: ${index}`);
}

// 삭제 연산 객체 생성
const operation: RemoteDeleteOperation = {
targetId: nodeToDelete.id,
clock: this.clock + 1,
};

// 로컬 삭제 수행
this.LinkedList.deleteNode(nodeToDelete.id);

// 클록 업데이트
this.clock += 1;

return operation;
}

/**
* 원격에서 삽입 연산을 수신했을 때 처리합니다.
* @param operation 원격 삽입 연산 객체
*/
remoteInsert(operation: RemoteInsertOperation): void {
const newNodeId = new NodeId(operation.node.id.clock, operation.node.id.client);
const newNode = new Node(operation.node.value, newNodeId);
const NodeIdClass = this instanceof BlockCRDT ? CharId : BlockId;
const NodeClass = this instanceof BlockCRDT ? Char : Block;

const newNodeId = new NodeIdClass(operation.node.id.clock, operation.node.id.client);
const newNode = new NodeClass(operation.node.value, newNodeId) as T;
newNode.next = operation.node.next;
newNode.prev = operation.node.prev;

this.LinkedList.insertById(newNode);
// 동기화 논리적 시간

if (this.clock <= newNode.id.clock) {
this.clock = newNode.id.clock + 1;
}
}

/**
* 원격에서 삭제 연산을 수신했을때 처리합니다.
* @param operation 원격 삭제 연산 객체
*/
remoteDelete(operation: RemoteDeleteOperation): void {
const { targetId, clock } = operation;
if (targetId) {
this.LinkedList.deleteNode(targetId);
}
// 동기화 논리적 시간
if (this.clock <= clock) {
this.clock = clock + 1;
}
}

/**
* 현재 텍스트를 문자열로 반환합니다.
* @returns 현재 텍스트
*/
read(): string {
return this.LinkedList.stringify();
}

/**
* 현재 텍스트를 배열로 반환합니다.
* @returns 현재 텍스트 배열
*/
spread(): Block[] | Char[] {
spread(): T[] {
return this.LinkedList.spread();
}

/**
* textLinkedList를 반환하는 getter 메서드
* @returns LinkedList 인스턴스
*/
public getTextLinkedList(): LinkedList {
return this.LinkedList;
}

/**
* CRDT의 상태를 직렬화 가능한 객체로 반환합니다.
* @returns 직렬화 가능한 CRDT 상태
*/
serialize(): SerializedProps {
serialize(): SerializedProps<T> {
return {
clock: this.clock,
client: this.client,
textLinkedList: {
LinkedList: {
head: this.LinkedList.head,
nodeMap: this.LinkedList.nodeMap,
},
};
}
}

export class EditorCRDT extends CRDT<Block> {
currentBlock: Block | null;

constructor(client: number) {
super(client);
this.currentBlock = null;
}
}

export class BlockCRDT extends CRDT<Char> {
currentCaret: number;

constructor(client: number) {
super(client);
this.currentCaret = 0;
}
}
104 changes: 47 additions & 57 deletions @noctaCrdt/Interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
import { NodeId, Node } from "./Node";
import { NodeId, BlockId, CharId } from "./NodeId";
import { Block, Char } from "./Node";

export type ElementType = "p" | "h1" | "h2" | "h3" | "ul" | "ol" | "li" | "checkbox" | "blockquote";

export interface InsertOperation {
node: Node;
node: Block | Char;
}

export interface DeleteOperation {
targetId: NodeId | null;
targetId: BlockId | CharId;
clock: number;
}

export interface RemoteInsertOperation {
node: Node;
node: Block | Char;
}

export interface RemoteDeleteOperation {
targetId: NodeId | null;
targetId: NodeId;
clock: number;
}

Expand All @@ -24,65 +26,53 @@ export interface CursorPosition {
position: number;
}

export interface SerializedProps {
export interface SerializedProps<T> {
// CRDT 직렬화라서 이름바꿔야함.
clock: number;
client: number;
textLinkedList: {
LinkedList: {
head: NodeId | null;
nodeMap: { [key: string]: Node };
nodeMap: { [key: string]: T };
};
}

export interface WorkSpace {
id: string;
pageList: Page[];
authUser: object;
}

export interface Page {
id: string;
title: string;
icon: string; // 추후 수정
crdt: CRDT;
}

export interface CRDT {
clock: number;
client: number;
LinkedList: LinkedList;
localInsert(index: number, value: string): RemoteInsertOperation;
localDelete(index: number): RemoteDeleteOperation;
remoteInsert(operation: RemoteInsertOperation): void;
remoteDelete(operation: RemoteDeleteOperation): void;
read(): string;
spread(): Block[] | Char[];
}
// export interface WorkSpace {
// id: string;
// pageList: Page[];
// authUser: object;
// }

export interface LinkedList {
head: NodeId | null;
nodeMap: { [key: string]: Block | Char };
}
// export interface Page {
// id: string;
// title: string;
// icon: string; // 추후 수정
// crdt: EditorCRDT;
// }
// export interface LinkedList {
// head: NodeId | null;
// nodeMap: { [key: string]: Block | Char };
// }

export interface Block {
id: BlockId;
icon: string; // 추후 수정
type: ElementType;
animation: string;
crdt: CRDT;
indent: number;
next: NodeId;
prev: NodeId;
style: string[];
}
// export interface Block {
// id: BlockId;
// icon: string; // 추후 수정
// type: ElementType;
// animation: string;
// crdt: BlockCRDT;
// indent: number;
// next: NodeId;
// prev: NodeId;
// style: string[];
// }

export interface Char {
id: NodeId;
value: string;
next: NodeId | null;
prev: NodeId | null;
}
// export interface Char {
// id: NodeId;
// value: string;
// next: NodeId | null;
// prev: NodeId | null;
// }

export interface BlockId {
clock: number;
client: number;
}
// export interface BlockId {
// clock: number;
// client: number;
// }
Loading

0 comments on commit 8266ba9

Please sign in to comment.