Skip to content

Commit

Permalink
refactor: 병합을 위한 변경 사항 저장 방식을 Project 단위에서 Task 단위로 변경
Browse files Browse the repository at this point in the history
  • Loading branch information
yangchef1 committed Nov 20, 2024
1 parent a60064a commit 1c55fde
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 60 deletions.
15 changes: 1 addition & 14 deletions apps/server/src/task/dto/task-event-response.dto.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,9 @@
import { EventType } from '@/task/domain/eventType.enum';
import { TaskEvent } from '@/task/dto/task-event.dto';

export class TaskEventResponse {
taskId: number;

event: EventType;

static from(taskEvent: TaskEvent) {
const response = new TaskEventResponse();
response.taskId = taskEvent.taskId;
response.event = taskEvent.event;
return response;
}

static of(taskId: number, taskEvent: TaskEvent) {
static from(taskId: number) {
const response = new TaskEventResponse();
response.taskId = taskId;
response.event = taskEvent.event;
return response;
}
}
88 changes: 42 additions & 46 deletions apps/server/src/task/service/task.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,12 @@ import { MoveTaskResponse } from '@/task/dto/move-task-response.dto';
import { TaskResponse } from '@/task/dto/task-response.dto';
import { DeleteTaskResponse } from '@/task/dto/delete-task-response.dto';
import { CreateTaskResponse } from '@/task/dto/create-task-response.dto';
import { Project } from '@/project/entity/project.entity';
import { TaskEvent } from '@/task/dto/task-event.dto';
import { EventType } from '@/task/domain/eventType.enum';
import { Contributor } from '@/project/entity/contributor.entity';
import { BroadcastService } from '@/task/service/broadcast.service';
import { ContributorStatus } from '@/project/enum/contributor-status.enum';
import { TaskEventResponse } from '@/task/dto/task-event-response.dto';
import { UpdateInformation } from '@/task/domain/update-information.type';

const { defaultType: json0 } = ShareDB.types;

Expand All @@ -34,8 +32,6 @@ export class TaskService {
private taskRepository: Repository<Task>,
@InjectRepository(Section)
private sectionRepository: Repository<Section>,
@InjectRepository(Project)
private projectRepository: Repository<Project>,
@InjectRepository(Contributor)
private contributorRepository: Repository<Contributor>,
private broadcastService: BroadcastService,
Expand All @@ -44,58 +40,53 @@ export class TaskService {
this.eventEmitter.on('broadcast', (userId: number, projectId: number, event: TaskEvent) => {
this.broadcastService.sendConnection(userId, projectId, event);
});
this.eventEmitter.on('operationAdded', async (userId: number, projectId: number) => {
await this.dequeue(userId, projectId);
});
this.eventEmitter.on(
'operationAdded',
async (userId: number, projectId: number, taskId: number) => {
await this.dequeue(userId, projectId, taskId);
}
);
}

async enqueue(userId: number, projectId: number, taskEvent: TaskEvent) {
const key = projectId;
const taskId = taskEvent.taskId;
const contributor = await this.contributorRepository.findOneBy({ projectId, userId });
if (!contributor || contributor.status !== ContributorStatus.ACCEPTED) {
throw new ForbiddenException('Permission denied');
}
const currentEvents = this.operations.get(key) || [];
this.operations.set(key, [...currentEvents, taskEvent]);
this.eventEmitter.emit('operationAdded', userId, projectId);
const currentEvents = this.operations.get(taskId) || [];
this.operations.set(taskId, [...currentEvents, taskEvent]);
this.eventEmitter.emit('operationAdded', userId, projectId, taskId);
}

private async dequeue(userId: number, projectId: number) {
const key = projectId;
const taskEvents = this.operations.get(key);
if (!taskEvents) {
private async dequeue(userId: number, projectId: number, taskId: number) {
const taskEventQueue = this.operations.get(taskId);
if (!taskEventQueue) {
return;
}

let lastOp = [];
while (taskEvents.length) {
const taskEvent = taskEvents.shift();
const existing = await this.findTaskOrThrow(taskEvent.taskId);
const result = this.merge(taskEvent, existing);

const transformedOp = lastOp.length ? json0.transform(result, lastOp, 'right') : result;
const initialTask = this.taskRepository.findOneBy({ id: taskId });
let accumulateOperations = [];
while (taskEventQueue.length) {
const taskEvent = taskEventQueue.shift();
const operation = this.convertToOperation(taskEvent);

this.taskRepository.save(result);
const transformedOperation = accumulateOperations.length
? json0.transform(operation, accumulateOperations, 'right')
: operation;

this.eventEmitter.emit('broadcast', userId, projectId, TaskEventResponse.from(taskEvent));

lastOp = json0.compose(lastOp, transformedOp);
accumulateOperations = json0.compose(accumulateOperations, transformedOperation);
}
}

private merge(change: TaskEvent, existing: Task) {
const updateTitle = change.title;
const existingTitle = existing.title;
const { event } = change;
const op = this.convertToShareDbOp(event, updateTitle);

const newTitle = json0.apply(existingTitle, op);

return { ...existing, title: newTitle };
const newText = json0.apply(initialTask, accumulateOperations);
const result = { ...initialTask, title: newText };
this.taskRepository.save(result);
this.eventEmitter.emit('broadcast', userId, projectId, TaskEventResponse.from(taskId));
}

private convertToShareDbOp(event: EventType, updateTitle: UpdateInformation) {
const { content, position } = updateTitle;
private convertToOperation(taskEvent: TaskEvent) {
const { event } = taskEvent;
const { content, position } = taskEvent.title;

switch (event) {
case EventType.INSERT_TITLE:
Expand Down Expand Up @@ -124,12 +115,7 @@ export class TaskService {
section,
});

this.eventEmitter.emit(
'broadcast',
userId,
projectId,
TaskEventResponse.of(task.id, taskEvent)
);
this.eventEmitter.emit('broadcast', userId, projectId, TaskEventResponse.from(task.id));
return new CreateTaskResponse(task);
}

Expand Down Expand Up @@ -180,7 +166,12 @@ export class TaskService {
task.section = section;
await this.taskRepository.save(task);

this.eventEmitter.emit('broadcast', userId, projectId, TaskEventResponse.from(taskEvent));
this.eventEmitter.emit(
'broadcast',
userId,
projectId,
TaskEventResponse.from(taskEvent.taskId)
);
return new MoveTaskResponse(task);
}

Expand Down Expand Up @@ -210,7 +201,12 @@ export class TaskService {
}
await this.taskRepository.delete(taskEvent.taskId);

this.eventEmitter.emit('broadcast', userId, projectId, TaskEventResponse.from(taskEvent));
this.eventEmitter.emit(
'broadcast',
userId,
projectId,
TaskEventResponse.from(taskEvent.taskId)
);
return new DeleteTaskResponse(taskEvent.taskId);
}

Expand Down

0 comments on commit 1c55fde

Please sign in to comment.