import { Injectable } from '@angular/core'; import { MessageEntity, MessageEntitySchema, } from '../entity/message'; import { AttachmentLocalDataSource } from "src/app/module/chat/data/repository/attachment-local-repository.service"; import { z } from 'zod'; import { v4 as uuidv4 } from 'uuid'; import { InstanceId } from '../chat-service.service'; import { createDataURL } from 'src/app/utils/ToBase64'; import { zodSafeValidation } from 'src/app/utils/zodValidation'; import { Logger } from 'src/app/services/logger/main/service'; import { MessageAttachmentSource, MessageOutPutDataDTO } from '../../data/dto/message/messageOutputDTO'; import { MessageLocalDataSourceService } from '../../data/repository/message/message-local-data-source.service'; import { MessageSocketRepositoryService } from '../../data/repository/message/message-live-signalr-data-source.service'; import { err, Result } from 'neverthrow'; import { MessageTable } from '../../infra/database/dexie/schema/message'; import { MessageMapper } from '../mapper/messageMapper'; import { SignalRService } from '../../infra/socket/signal-r.service'; import { RoomType } from "src/app/module/chat/domain/entity/group"; import { TracingType, XTracerAsync } from 'src/app/services/monitoring/opentelemetry/tracer'; import { MemberListLocalRepository } from 'src/app/module/chat/data/repository/member-list-local-repository.service' import { SessionStore } from 'src/app/store/session.service'; const MessageInputUseCaseSchema = z.object({ memberId: z.number(), roomId: z.string(), message: z.string() }) export enum MessageEnum { Direct = 1, group = 2 } export type MessageInputUseCase = z.infer< typeof MessageInputUseCaseSchema> @Injectable({ providedIn: 'root' }) export class MessageCreateUseCaseService { constructor( private AttachmentLocalRepositoryService: AttachmentLocalDataSource, private messageLocalDataSourceService: MessageLocalDataSourceService, private MessageSocketRepositoryService: MessageSocketRepositoryService, private messageSocketRepositoryService: MessageSocketRepositoryService, private MemberListLocalRepository: MemberListLocalRepository ) { } @XTracerAsync({name:'MessageCreateUseCaseService', module:'chat', bugPrint: true, waitNThrow: 5000}) async execute(message: MessageEntity, messageEnum: RoomType, tracing?: TracingType) { const validation = zodSafeValidation(MessageEntitySchema, message) if(validation.isOk()) { message.sendAttemp++; message.requestId = InstanceId +'@'+ uuidv4(); const createMessageLocally = await this.messageLocalDataSourceService.sendMessage(message) if(createMessageLocally.isOk()) { message.$id = createMessageLocally.value if(message.hasAttachment) { for (const attachment of message.attachments) { if(attachment.source != MessageAttachmentSource.Webtrix) { this.AttachmentLocalRepositoryService.insert({ $messageId: createMessageLocally.value, file: createDataURL(attachment.file, attachment.mimeType), fileType: attachment.fileType, source: attachment.source, fileName: attachment.fileName, applicationId: attachment.applicationId, docId: attachment.docId, mimeType: attachment.mimeType, }).then((e) => { if(e.isErr()) { Logger.error('failed to create attachment locally on send message', { error: e.error, data: createDataURL(attachment.file, attachment.mimeType).slice(0, 100) +'...' }) } }) attachment.safeFile = createDataURL(attachment.file, attachment.mimeType) } } } //==================== message.sending = true let sendMessageResult: Result if(messageEnum == RoomType.Group) { const DTO = MessageMapper.fromDomain(message, message.requestId) sendMessageResult = await this.MessageSocketRepositoryService.sendGroupMessage(DTO) } else { if(message.receiverId) { const DTO = MessageMapper.fromDomain(message, message.requestId) sendMessageResult = await this.messageSocketRepositoryService.sendDirectMessage(DTO) } else { const getRoomMembers = await this.MemberListLocalRepository.directMember({ roomId:message.roomId, currentUserId: SessionStore.user.UserId }) if(getRoomMembers.isOk()) { message.receiverId = getRoomMembers.value.wxUserId const DTO = MessageMapper.fromDomain(message, message.requestId) sendMessageResult = await this.messageSocketRepositoryService.sendGroupMessage(DTO) } else { console.log('not found direct users', getRoomMembers.error) } } } // return this sendMessageResult if(sendMessageResult.isOk()) { if(sendMessageResult.value.sender == undefined || sendMessageResult.value.sender == null) { delete sendMessageResult.value.sender } let clone: MessageTable = { ...sendMessageResult.value, id: sendMessageResult.value.id, $id : message.$id } this.messageLocalDataSourceService.update(message.$id, {...clone, sending: false, roomId: message.roomId}) return sendMessageResult } else { Logger.error('failed to send message to the server', { error: sendMessageResult.error }) await this.messageLocalDataSourceService.update(message.$id, {sending: false, $id: message.$id}) return err('no connection') } } } else { if(validation.error.formErrors.fieldErrors.attachments) { Logger.error('failed to send message doe to invalid attachment', { zodErrorList: validation.error.errors, data: message.attachments }) } else { Logger.error('failed to send message, validation failed', { zodErrorList: validation.error.errors, data: message }) } } } }