Skip to content

Commit

Permalink
Merge branch 'release/0.0.8'
Browse files Browse the repository at this point in the history
  • Loading branch information
pipisebastian committed Nov 21, 2024
2 parents ffb1792 + 95b0f0d commit 2c9c5a0
Show file tree
Hide file tree
Showing 75 changed files with 3,366 additions and 572 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ jobs:
NODE_ENV: production
MONGO_URI: ${{ secrets.MONGO_URI }}
JWT_SECRET: ${{ secrets.JWT_SECRET }}
JWT_REFRESH_SECRET: ${{ secrets.JWT_REFRESH_SECRET }}
VITE_API_URL: ${{ secrets.VITE_API_URL }}
run: |
docker-compose up -d --build
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/lint_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ jobs:
- name: Run Unit Tests
run: pnpm test
env:
NODE_ENV: development
JWT_SECRET: ${{ secrets.JWT_SECRET }}
JWT_REFRESH_SECRET: ${{ secrets.JWT_REFRESH_SECRET }}
VITE_API_URL: ${{ secrets.VITE_API_URL }}

test_building_docker_image:
name: Test Building Docker Image
Expand Down Expand Up @@ -71,5 +74,7 @@ jobs:
NODE_ENV: production
MONGO_URI: ${{ secrets.MONGO_URI }}
JWT_SECRET: ${{ secrets.JWT_SECRET }}
JWT_REFRESH_SECRET: ${{ secrets.JWT_REFRESH_SECRET }}
VITE_API_URL: ${{ secrets.VITE_API_URL }}
run: |
docker-compose build frontend backend
3 changes: 3 additions & 0 deletions .github/workflows/lint_and_unit_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,7 @@ jobs:
- name: Run Unit Tests
run: pnpm test
env:
NODE_ENV: development
JWT_SECRET: ${{ secrets.JWT_SECRET }}
JWT_REFRESH_SECRET: ${{ secrets.JWT_REFRESH_SECRET }}
VITE_API_URL: ${{ secrets.VITE_API_URL }}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,7 @@
.DS_Store
.env

tsconfig.tsbuildinfo

# Jest globalConfig file
../globalConfig.json
237 changes: 188 additions & 49 deletions @noctaCrdt/Crdt.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,87 @@
import { LinkedList } from "./LinkedList";
import { LinkedList, BlockLinkedList, TextLinkedList } from "./LinkedList";
import { CharId, BlockId, NodeId } from "./NodeId";
import { Node, Char, Block } from "./Node";
import {
RemoteDeleteOperation,
RemoteInsertOperation,
SerializedProps,
RemoteBlockDeleteOperation,
RemoteCharDeleteOperation,
RemoteBlockInsertOperation,
RemoteCharInsertOperation,
CRDTSerializedProps,
RemoteReorderOperation,
RemoteBlockUpdateOperation,
} from "./Interfaces";

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

constructor(client: number) {
constructor(client: number, LinkedListClass: new () => LinkedList<T>) {
this.clock = 0;
this.client = client;
this.LinkedList = new LinkedList<T>();
this.LinkedList = new LinkedListClass();
}

localInsert(index: number, value: string, blockId?: BlockId, pageId?: string): any {

Check warning on line 25 in @noctaCrdt/Crdt.ts

View workflow job for this annotation

GitHub Actions / Lint and Unit Test

'index' is defined but never used. Allowed unused args must match /^_/u

Check warning on line 25 in @noctaCrdt/Crdt.ts

View workflow job for this annotation

GitHub Actions / Lint and Unit Test

'value' is defined but never used. Allowed unused args must match /^_/u

Check warning on line 25 in @noctaCrdt/Crdt.ts

View workflow job for this annotation

GitHub Actions / Lint and Unit Test

'blockId' is defined but never used. Allowed unused args must match /^_/u

Check warning on line 25 in @noctaCrdt/Crdt.ts

View workflow job for this annotation

GitHub Actions / Lint and Unit Test

'pageId' is defined but never used. Allowed unused args must match /^_/u

Check warning on line 25 in @noctaCrdt/Crdt.ts

View workflow job for this annotation

GitHub Actions / Lint and Unit Test

Unexpected any. Specify a different type
// ๊ธฐ๋ณธ CRDT์—์„œ๋Š” ๊ตฌํ˜„ํ•˜์ง€ ์•Š๊ณ , ํ•˜์œ„ ํด๋ž˜์Šค์—์„œ ๊ตฌํ˜„
throw new Error("Method not implemented.");
}

localDelete(index: number, blockId?: BlockId, pageId?: string): any {

Check warning on line 30 in @noctaCrdt/Crdt.ts

View workflow job for this annotation

GitHub Actions / Lint and Unit Test

'index' is defined but never used. Allowed unused args must match /^_/u

Check warning on line 30 in @noctaCrdt/Crdt.ts

View workflow job for this annotation

GitHub Actions / Lint and Unit Test

'blockId' is defined but never used. Allowed unused args must match /^_/u

Check warning on line 30 in @noctaCrdt/Crdt.ts

View workflow job for this annotation

GitHub Actions / Lint and Unit Test

'pageId' is defined but never used. Allowed unused args must match /^_/u

Check warning on line 30 in @noctaCrdt/Crdt.ts

View workflow job for this annotation

GitHub Actions / Lint and Unit Test

Unexpected any. Specify a different type
// ๊ธฐ๋ณธ CRDT์—์„œ๋Š” ๊ตฌํ˜„ํ•˜์ง€ ์•Š๊ณ , ํ•˜์œ„ ํด๋ž˜์Šค์—์„œ ๊ตฌํ˜„
throw new Error("Method not implemented.");
}

remoteInsert(operation: any): void {

Check warning on line 35 in @noctaCrdt/Crdt.ts

View workflow job for this annotation

GitHub Actions / Lint and Unit Test

'operation' is defined but never used. Allowed unused args must match /^_/u
// ๊ธฐ๋ณธ CRDT์—์„œ๋Š” ๊ตฌํ˜„ํ•˜์ง€ ์•Š๊ณ , ํ•˜์œ„ ํด๋ž˜์Šค์—์„œ ๊ตฌํ˜„
throw new Error("Method not implemented.");
}

remoteDelete(operation: any): void {
// ๊ธฐ๋ณธ CRDT์—์„œ๋Š” ๊ตฌํ˜„ํ•˜์ง€ ์•Š๊ณ , ํ•˜์œ„ ํด๋ž˜์Šค์—์„œ ๊ตฌํ˜„
throw new Error("Method not implemented.");
}

read(): string {
return this.LinkedList.stringify();
}

localInsert(index: number, value: string): RemoteInsertOperation {
const id =
this instanceof BlockCRDT
? new CharId(this.clock + 1, this.client)
: new BlockId(this.clock + 1, this.client);
spread(): T[] {
return this.LinkedList.spread();
}

serialize(): CRDTSerializedProps<T> {
return {
clock: this.clock,
client: this.client,
LinkedList: this.LinkedList.serialize(),
};
}

deserialize(data: any): void {
this.clock = data.clock;
this.client = data.client;
this.LinkedList.deserialize(data.LinkedList);
}
}

// EditorCRDT ํด๋ž˜์Šค: ๋ธ”๋ก์„ ๊ด€๋ฆฌ
export class EditorCRDT extends CRDT<Block> {
currentBlock: Block | null;

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

localInsert(index: number, value: string): RemoteBlockInsertOperation {
const id = new BlockId(this.clock + 1, this.client);
const remoteInsertion = this.LinkedList.insertAtIndex(index, value, id);
this.clock += 1;
return { node: remoteInsertion.node };
return { node: remoteInsertion.node } as RemoteBlockInsertOperation;
}

localDelete(index: number): RemoteDeleteOperation {
localDelete(index: number, blockId: undefined, pageId: string): RemoteBlockDeleteOperation {
if (index < 0 || index >= this.LinkedList.spread().length) {
throw new Error(`Invalid index: ${index}`);
}
Expand All @@ -40,9 +91,10 @@ export class CRDT<T extends Node<NodeId>> {
throw new Error(`Node not found at index: ${index}`);
}

const operation: RemoteDeleteOperation = {
const operation: RemoteBlockDeleteOperation = {
targetId: nodeToDelete.id,
clock: this.clock + 1,
clock: this.clock,
pageId,
};

this.LinkedList.deleteNode(nodeToDelete.id);
Expand All @@ -51,40 +103,56 @@ export class CRDT<T extends Node<NodeId>> {
return operation;
}

remoteInsert(operation: RemoteInsertOperation): void {
const NodeIdClass = this instanceof BlockCRDT ? CharId : BlockId;
const NodeClass = this instanceof BlockCRDT ? Char : Block;
remoteUpdate(block: Block, pageId: string): RemoteBlockUpdateOperation {
const updatedBlock = this.LinkedList.nodeMap[JSON.stringify(block.id)];
updatedBlock.animation = block.animation;
updatedBlock.icon = block.icon;
updatedBlock.indent = block.indent;
updatedBlock.style = block.style;
updatedBlock.type = block.type;
// this.LinkedList.nodeMap[JSON.stringify(block.id)] = block;
return { node: updatedBlock, pageId };
}

remoteInsert(operation: RemoteBlockInsertOperation): void {
const newNodeId = new BlockId(operation.node.id.clock, operation.node.id.client);
const newNode = new Block(operation.node.value, newNodeId);

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);

this.clock = Math.max(this.clock, operation.node.id.clock) + 1;
/*
if (this.clock <= newNode.id.clock) {
this.clock = newNode.id.clock + 1;
}
*/
}

remoteDelete(operation: RemoteDeleteOperation): void {
remoteDelete(operation: RemoteBlockDeleteOperation): void {
const { targetId, clock } = operation;
if (targetId) {
this.LinkedList.deleteNode(targetId);
const targetNodeId = new BlockId(operation.targetId.clock, operation.targetId.client);
this.LinkedList.deleteNode(targetNodeId);
}
this.clock = Math.max(this.clock, clock) + 1;
/*
if (this.clock <= clock) {
this.clock = clock + 1;
}
*/
}

localReorder(params: {
targetId: NodeId;
beforeId: NodeId | null;
afterId: NodeId | null;
targetId: BlockId;
beforeId: BlockId | null;
afterId: BlockId | null;
}): RemoteReorderOperation {
const operation: RemoteReorderOperation = {
...params,
clock: this.clock + 1,
clock: this.clock,
client: this.client,
};

Expand All @@ -108,40 +176,111 @@ export class CRDT<T extends Node<NodeId>> {
}
}

read(): string {
return this.LinkedList.stringify();
}

spread(): T[] {
return this.LinkedList.spread();
}

serialize(): SerializedProps<T> {
serialize(): CRDTSerializedProps<Block> {
return {
clock: this.clock,
client: this.client,
LinkedList: {
head: this.LinkedList.head,
nodeMap: this.LinkedList.nodeMap || {},
},
...super.serialize(),
currentBlock: this.currentBlock ? this.currentBlock.serialize() : null,
};
}
}

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

constructor(client: number) {
super(client);
this.currentBlock = null;
deserialize(data: any): void {
super.deserialize(data);
this.currentBlock = data.currentBlock ? Block.deserialize(data.currentBlock) : null;
}
}

// BlockCRDT ํด๋ž˜์Šค: ๋ฌธ์ž(Char)๋ฅผ ๊ด€๋ฆฌ
export class BlockCRDT extends CRDT<Char> {
currentCaret: number;

constructor(client: number) {
super(client);
super(client, TextLinkedList);
this.currentCaret = 0;
}

localInsert(
index: number,
value: string,
blockId: BlockId,
pageId: string,
): RemoteCharInsertOperation {
const id = new CharId(this.clock + 1, this.client);
const { node } = this.LinkedList.insertAtIndex(index, value, id);
this.clock += 1;
const operation: RemoteCharInsertOperation = {
node,
blockId,
pageId,
};

return operation;
}

localDelete(index: number, blockId: BlockId, pageId: string): RemoteCharDeleteOperation {
if (index < 0 || index >= this.LinkedList.spread().length) {
throw new Error(`Invalid index: ${index}`);
}

const nodeToDelete = this.LinkedList.findByIndex(index);
if (!nodeToDelete) {
throw new Error(`Node not found at index: ${index}`);
}

const operation: RemoteCharDeleteOperation = {
targetId: nodeToDelete.id,
clock: this.clock,
blockId,
pageId,
};

this.LinkedList.deleteNode(nodeToDelete.id);
this.clock += 1;

return operation;
}

remoteInsert(operation: RemoteCharInsertOperation): void {
const newNodeId = new CharId(operation.node.id.clock, operation.node.id.client);
const newNode = new Char(operation.node.value, newNodeId);

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;
}
}

remoteDelete(operation: RemoteCharDeleteOperation): void {
const { targetId, clock } = operation;
if (targetId) {
const targetNodeId = new CharId(operation.targetId.clock, operation.targetId.client);
this.LinkedList.deleteNode(targetNodeId);
}
if (this.clock <= clock) {
this.clock = clock + 1;
}
}

serialize(): CRDTSerializedProps<Char> {
return {
...super.serialize(),
currentCaret: this.currentCaret,
};
}

static deserialize(data: any): BlockCRDT {
const crdt = new BlockCRDT(data.client);
crdt.clock = data.clock;
crdt.LinkedList.deserialize(data.LinkedList);
crdt.currentCaret = data.currentCaret;
return crdt;
}

deserialize(data: any): void {
super.deserialize(data);
this.currentCaret = data.currentCaret;
}
}
Loading

0 comments on commit 2c9c5a0

Please sign in to comment.