feat: enhance DocumentSchema and DocumentService with Redis integration and background processing

- Updated DocumentSchema to include RedisService for improved background processing of grammar checks.
- Refactored checkGrammarForPage method in DocumentService to utilize Promise.all for parallel processing and error handling.
- Introduced background grammar check functionality with a low probability trigger, enhancing performance and user experience.
- Added new utility methods for better time management and error logging.

These changes improve the efficiency and responsiveness of the grammar checking feature, leveraging Redis for state management and background processing.
This commit is contained in:
2024-12-14 21:54:43 +07:00
parent 114998ea7e
commit c886d9a02f
9 changed files with 340 additions and 163 deletions

View File

@@ -1,67 +1,72 @@
import { Inject, Injectable, Logger } from '@nestjs/common'
import { Pothos, PothosRef, PothosSchema, SchemaBuilderToken } from '@smatch-corp/nestjs-pothos'
import { Builder, SchemaContext } from 'src/Graphql/graphql.builder'
import { LiveKitService } from 'src/LiveKit/livekit.service'
import { MinioService } from 'src/Minio/minio.service'
import { PrismaService } from 'src/Prisma/prisma.service'
import { Inject, Injectable, Logger } from "@nestjs/common";
import {
Pothos,
PothosRef,
PothosSchema,
SchemaBuilderToken,
} from "@smatch-corp/nestjs-pothos";
import { Builder, SchemaContext } from "src/Graphql/graphql.builder";
import { LiveKitService } from "src/LiveKit/livekit.service";
import { MinioService } from "src/Minio/minio.service";
import { PrismaService } from "src/Prisma/prisma.service";
@Injectable()
export class MeetingRoomSchema extends PothosSchema {
constructor(
@Inject(SchemaBuilderToken) private readonly builder: Builder,
private readonly prisma: PrismaService,
private readonly livekitService: LiveKitService,
private readonly minioService: MinioService,
private readonly minioService: MinioService
) {
super()
super();
}
@PothosRef()
meetingRoom() {
return this.builder.prismaObject('MeetingRoom', {
return this.builder.prismaObject("MeetingRoom", {
fields: (t) => ({
id: t.exposeID('id'),
collaborationSessionId: t.exposeString('collaborationSessionId'),
collaborationSession: t.relation('collaborationSession'),
collaborators: t.relation('collaborators'),
createdAt: t.expose('createdAt', { type: 'DateTime' }),
updatedAt: t.expose('updatedAt', { type: 'DateTime' }),
id: t.exposeID("id"),
collaborationSessionId: t.exposeString("collaborationSessionId"),
collaborationSession: t.relation("collaborationSession"),
collaborators: t.relation("collaborators"),
createdAt: t.expose("createdAt", { type: "DateTime" }),
updatedAt: t.expose("updatedAt", { type: "DateTime" }),
recordUrl: t.string({
nullable: true,
resolve: async (meetingRoom) => {
return await this.minioService.getRoomRecordUrl(meetingRoom.id)
return await this.minioService.getRoomRecordUrl(meetingRoom.id);
},
}),
}),
})
});
}
@PothosRef()
meetingRoomJoinInfo() {
return this.builder.simpleObject('MeetingRoomJoinInfo', {
return this.builder.simpleObject("MeetingRoomJoinInfo", {
fields: (t) => ({
id: t.string({
description: 'The ID of the meeting room.',
description: "The ID of the meeting room.",
}),
token: t.string({
description: 'The token to join the meeting room.',
description: "The token to join the meeting room.",
}),
serverUrl: t.string({
description: 'The URL of the server.',
description: "The URL of the server.",
}),
}),
})
});
}
@PothosRef()
meetingRoomCollaborator() {
return this.builder.prismaObject('MeetingRoomCollaborator', {
return this.builder.prismaObject("MeetingRoomCollaborator", {
fields: (t) => ({
id: t.exposeID('id'),
meetingRoomId: t.exposeString('meetingRoomId'),
meetingRoom: t.relation('meetingRoom'),
userId: t.exposeString('userId'),
user: t.relation('user'),
id: t.exposeID("id"),
meetingRoomId: t.exposeString("meetingRoomId"),
meetingRoom: t.relation("meetingRoom"),
userId: t.exposeString("userId"),
user: t.relation("user"),
}),
})
});
}
@Pothos()
@@ -77,29 +82,30 @@ export class MeetingRoomSchema extends PothosSchema {
},
resolve: async (_query, _parent, args, ctx: SchemaContext) => {
if (ctx.isSubscription) {
throw new Error('Not allowed')
throw new Error("Not allowed");
}
const collaborationSession = await this.prisma.collaborationSession.findUnique({
where: {
scheduleDateId: args.scheduleDateId,
},
})
const collaborationSession =
await this.prisma.collaborationSession.findUnique({
where: {
scheduleDateId: args.scheduleDateId,
},
});
if (!collaborationSession) {
throw new Error('Collaboration session not found')
throw new Error("Collaboration session not found");
}
const meetingRoom = await this.prisma.meetingRoom.findUnique({
where: {
collaborationSessionId: collaborationSession.id,
},
})
});
if (meetingRoom) {
return meetingRoom
return meetingRoom;
}
return await this.prisma.meetingRoom.create({
data: {
collaborationSessionId: collaborationSession.id,
},
})
});
},
}),
// get meeting room info by room id and check if user is collaborator of collaboration session then create new token and return it,
@@ -113,62 +119,91 @@ export class MeetingRoomSchema extends PothosSchema {
},
resolve: async (_, args, ctx: SchemaContext) => {
if (ctx.isSubscription) {
throw new Error('Not allowed')
throw new Error("Not allowed");
}
if (!ctx.http.me) {
throw new Error('Unauthorized')
throw new Error("Unauthorized");
}
const meetingRoom = await this.prisma.meetingRoom.findUnique({
where: { collaborationSessionId: args.collaborationSessionId },
})
});
if (!meetingRoom) {
throw new Error('Meeting room not found')
throw new Error("Meeting room not found");
}
// check if user is collaborator of collaboration session
const collaborationSession = await this.prisma.collaborationSession.findUnique({
where: { id: meetingRoom.collaborationSessionId },
})
const collaborationSession =
await this.prisma.collaborationSession.findUnique({
where: { id: meetingRoom.collaborationSessionId },
});
if (!collaborationSession) {
throw new Error('Collaboration session not found')
throw new Error("Collaboration session not found");
}
if (!collaborationSession.collaboratorsIds.includes(ctx.http.me.id)) {
throw new Error('User is not collaborator')
throw new Error("User is not collaborator");
}
// create new token
const token = await this.livekitService.createToken(ctx.http.me, meetingRoom.id)
const token = await this.livekitService.createToken(
ctx.http.me,
meetingRoom.id
);
return {
id: meetingRoom.id,
token,
serverUrl: this.livekitService.getServerUrl(),
}
};
},
}),
}))
interviewJoinInfo: t.field({
type: this.meetingRoomJoinInfo(),
args: {
scheduleId: t.arg.string({
required: true,
}),
},
resolve: async (_, args, ctx: SchemaContext) => {
if (ctx.isSubscription) {
throw new Error("Not allowed");
}
if (!ctx.http.me) {
throw new Error("Unauthorized");
}
const token = await this.livekitService.createToken(
ctx.http.me,
args.scheduleId
);
return {
id: args.scheduleId,
token,
serverUrl: this.livekitService.getServerUrl(),
};
},
}),
}));
this.builder.mutationFields((t) => ({
createMeetingRoom: t.prismaField({
type: this.meetingRoom(),
args: {
input: t.arg({
type: this.builder.generator.getCreateInput('MeetingRoom', [
'id',
'createdAt',
'updatedAt',
'collaborators',
type: this.builder.generator.getCreateInput("MeetingRoom", [
"id",
"createdAt",
"updatedAt",
"collaborators",
]),
required: true,
}),
},
resolve: async (query, _parent, args, ctx: SchemaContext) => {
if (ctx.isSubscription) {
throw new Error('Not allowed')
throw new Error("Not allowed");
}
if (!ctx.http.me) {
throw new Error('Unauthorized')
throw new Error("Unauthorized");
}
return await this.prisma.meetingRoom.create({
...query,
data: args.input,
})
});
},
}),
updateMeetingRoomCollaborators: t.prismaField({
@@ -186,10 +221,10 @@ export class MeetingRoomSchema extends PothosSchema {
},
resolve: async (query, _parent, args, ctx: SchemaContext) => {
if (ctx.isSubscription) {
throw new Error('Not allowed')
throw new Error("Not allowed");
}
if (!ctx.http.me) {
throw new Error('Unauthorized')
throw new Error("Unauthorized");
}
return await this.prisma.meetingRoom.update({
...query,
@@ -199,7 +234,9 @@ export class MeetingRoomSchema extends PothosSchema {
data: {
collaborators: {
createMany: {
data: args.addCollaborators ? args.addCollaborators.map((id) => ({ userId: id })) : [],
data: args.addCollaborators
? args.addCollaborators.map((id) => ({ userId: id }))
: [],
},
deleteMany: {
userId: {
@@ -208,9 +245,9 @@ export class MeetingRoomSchema extends PothosSchema {
},
},
},
})
});
},
}),
}))
}));
}
}