improve chat

This commit is contained in:
Peter Maquiran
2024-08-17 22:05:57 +01:00
parent eb615d4335
commit 650c772084
43 changed files with 712 additions and 1540 deletions
@@ -16,6 +16,7 @@ import { ListenMessageDeleteByRoomIdService } from './use-case/listene-message-d
import { ListenMessageUpdateByRoomIdUseCase } from './use-case/listen-message-update-by-roomId.service';
import { SyncAllRoomMessagesService } from './use-case/sync-all-room-messages.service';
import { ListenSendMessageUseCase } from './use-case/listen-send-message.service'
import { GetMessageAttachmentLocallyUseCaseService } from 'src/app/module/chat/domain/use-case/get-message-attachment-localy-use-case.service';
import { filter } from 'rxjs/operators';
import { v4 as uuidv4 } from 'uuid'
import { MessageEntity } from './entity/message';
@@ -46,7 +47,8 @@ export class ChatServiceService {
private ListenSendMessageUseCase: ListenSendMessageUseCase,
private MessageAttachmentByMessageIdService: MessageAttachmentByMessageIdUseCase,
private SyncAllRoomMessagesService: SyncAllRoomMessagesService,
private DownloadMessageAttachmentUserCaseService: DownloadMessageAttachmentUserCaseService
private DownloadMessageAttachmentUserCaseService: DownloadMessageAttachmentUserCaseService,
private GetMessageAttachmentLocallyUseCaseService: GetMessageAttachmentLocallyUseCaseService
) {
this.messageLiveSignalRDataSourceService.getMessageDelete()
.pipe()
@@ -127,7 +129,7 @@ export class ChatServiceService {
return this.SyncAllRoomMessagesService.execute()
}
getMessageAttachmentByMessageId(input: MessageAttachmentByMessageIdInput) {
getMessageAttachmentByMessageId(input: MessageEntity) {
return this.MessageAttachmentByMessageIdService.execute(input)
}
@@ -135,6 +137,10 @@ export class ChatServiceService {
return this.DownloadMessageAttachmentUserCaseService.execute(input)
}
getMessageAttachmentLocallyByMessageId(input: MessageAttachmentByMessageIdInput) {
return this.GetMessageAttachmentLocallyUseCaseService.execute(input)
}
listenToIncomingMessage(roomId:string) {
return this.ListenMessageByRoomIdNewUseCase.execute({roomId})
@@ -0,0 +1,33 @@
import { Injectable } from '@angular/core';
import { MessageAttachmentByMessageIdInput } from './message-attachment-by-message-id.service';
import { AttachmentRemoteDataSourceService } from 'src/app/module/chat/data/data-source/attachment/attachment-remote-data-source.service'
import { AttachmentLocalDataSource } from 'src/app/module/chat/data/data-source/attachment/attachment-local-data-source.service'
import { err, Result } from 'neverthrow';
@Injectable({
providedIn: 'root'
})
export class GetMessageAttachmentLocallyUseCaseService {
constructor(
private AttachmentRemoteDataSourceService: AttachmentRemoteDataSourceService,
private AttachmentLocalDataSource: AttachmentLocalDataSource
) { }
async execute(input: MessageAttachmentByMessageIdInput): Promise<Result<string, any>> {
const getLocalAttachment = await this.AttachmentLocalDataSource.findOne({
$messageId: input.$messageId
})
if(getLocalAttachment.isOk()) {
if(getLocalAttachment.value) {
return getLocalAttachment.map(e => e.file)
}
} else {
return err(getLocalAttachment.error)
}
}
}
@@ -5,6 +5,7 @@ import { AttachmentLocalDataSource } from 'src/app/module/chat/data/data-source/
import { convertBlobToDataURL } from 'src/app/utils/ToBase64';
import { Result } from 'neverthrow';
import { Logger } from 'src/app/services/logger/main/service';
import { MessageEntity } from '../entity/message';
const MessageAttachmentByMessageIdSchema = z.object({
$messageId: z.number(),
@@ -23,10 +24,10 @@ export class MessageAttachmentByMessageIdUseCase {
private AttachmentLocalDataSource: AttachmentLocalDataSource
) { }
async execute(input: MessageAttachmentByMessageIdInput): Promise<Result<string, any>> {
async execute(input: MessageEntity): Promise<Result<string, any>> {
const getLocalAttachment = await this.AttachmentLocalDataSource.findOne({
$messageId: input.$messageId
$messageId: input.$id
})
if(getLocalAttachment.isOk() && getLocalAttachment.value) {
@@ -34,18 +35,40 @@ export class MessageAttachmentByMessageIdUseCase {
return getLocalAttachment.map(e => e.file)
}
} else {
const result = await this.AttachmentRemoteDataSourceService.getAttachment(input.id)
const result = await this.AttachmentRemoteDataSourceService.getAttachment(input.attachments[0].id)
if(result.isErr()) {
Logger.error('failed to download message attachment', {
error: result.error,
data: 'document id '+ input.attachments[0].id,
messageId: input.id,
$messageId: input.$id
})
}
return result.asyncMap(async (e) => {
const dataUrl = await convertBlobToDataURL(e)
Logger.info('downloaded file', {
data: dataUrl.slice(0, 100)+'...'
})
// Logger.info('downloaded file .', {
// data: dataUrl.slice(0, 100)+'...'
// })
this.AttachmentLocalDataSource.insert({
$messageId: input.$messageId,
id: input.id,
file: dataUrl
$messageId: input.$id,
file: dataUrl,
fileType: input.attachments[0].fileType,
source: input.attachments[0].source,
fileName: input.attachments[0].fileName,
applicationId: input.attachments[0].applicationId,
docId: input.attachments[0].docId,
mimeType: input.attachments[0].mimeType,
}).then((e) => {
if(e.isErr()) {
Logger.error('failed to create attachment locally on send message', {
error: e.error,
data: dataUrl.slice(0, 100)+'...'
})
}
})
return dataUrl
@@ -49,7 +49,13 @@ export class MessageCreateUseCaseService {
this.AttachmentRepositoryService.create({
$messageId: createMessageLocally.value.$id,
file: createDataURL(attachment.file, attachment.mimeType)
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', {
@@ -0,0 +1,81 @@
import { Injectable } from '@angular/core';
import { MessageLocalDataSourceService } from '../../data/data-source/message/message-local-data-source.service';
import { MessageOutPutDataDTO } from '../../data/dto/message/messageOutputDTO';
import { MessageTable } from '../../infra/database/dexie/schema/message';
import { SignalRService } from '../../infra/socket/signal-r.service';
import { InstanceId } from '../chat-service.service';
import { MessageMapper } from '../mapper/messageMapper';
import { v4 as uuidv4 } from 'uuid'
import { AttachmentRepositoryService } from "src/app/module/chat/data/repository/attachment-repository.service";
import { AttachmentLocalDataSource } from '../../data/data-source/attachment/attachment-local-data-source.service';
@Injectable({
providedIn: 'root'
})
export class SendLocalMessagesUseCaseService {
constructor(
private messageLiveSignalRDataSourceService: SignalRService,
private messageLocalDataSourceService: MessageLocalDataSourceService,
private AttachmentRepositoryService: AttachmentLocalDataSource,
) { }
async execute() {
const messages = await this.messageLocalDataSourceService.getOfflineMessages()
if(messages.length >= 1) {
for(const message of messages) {
const attachments = await this.AttachmentRepositoryService.find({$messageId: message.$id})
if(attachments.isOk()) {
message.attachments = attachments.value.map(e => ({
fileType: e.fileType,
source: e.source,
fileName: e.fileName,
applicationId: e.applicationId,
docId: e.docId,
id: e.id,
mimeType: e.mimeType,
description: e.description,
file: e.file.split(',')[0]
}))
console.log('to upload', messages)
const requestId = InstanceId +'@'+ uuidv4();
const DTO = MessageMapper.fromDomain(message, requestId)
await this.messageLocalDataSourceService.update(message.$id, { sending: true })
const sendMessageResult = await this.messageLiveSignalRDataSourceService.sendMessage<MessageOutPutDataDTO>(DTO)
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
}
console.log('send message local '+ messages.length)
this.messageLocalDataSourceService.update(message.$id, {...clone, sending: false, roomId: message.roomId})
} else {
console.log('erro send message')
this.messageLocalDataSourceService.update(message.$id, {sending: false})
}
}
}
}
}
}
@@ -1,13 +1,22 @@
import { z } from "zod";
import { EntityTable } from 'Dexie';
import { zodDataUrlSchema } from "src/app/utils/zod";
import { MessageAttachmentFileType, MessageAttachmentSource } from "src/app/module/chat/data/dto/message/messageOutputDTO";
export const AttachmentTableSchema = z.object({
id: z.string().optional(), // attachment id
$id: z.number().optional(), // local id
$messageId: z.number(),
attachmentId: z.string().optional(),
file: zodDataUrlSchema,
//
fileType: z.nativeEnum(MessageAttachmentFileType),
source: z.nativeEnum(MessageAttachmentSource),
fileName: z.string().optional(),
applicationId: z.number().optional(),
docId: z.string().optional(),
mimeType: z.string().optional(),
id: z.string().optional(),
description: z.string().optional(),
})
export type AttachmentTable = z.infer<typeof AttachmentTableSchema>
@@ -1,6 +1,6 @@
import { nativeEnum, z } from "zod";
import { EntityTable } from 'Dexie';
import { MessageAttachmentFileType, MessageAttachmentSource } from "src/app/module/chat/data/dto/message/messageOutputDTO";
import { z } from 'zod';
export const MessageTableSchema = z.object({
$id: z.number().optional(),
@@ -33,6 +33,7 @@ export const MessageTableSchema = z.object({
applicationId: z.number().optional(),
docId: z.string().optional(),
id: z.string().optional(),
description: z.string().optional(),
mimeType: z.string().optional()
})).optional()
})
@@ -5,11 +5,16 @@ import { DexieMembersTableSchema, MemberTableColumn } from './schema/members';
import { DexieRoomsTable, RoomTableColumn } from './schema/room';
import { DexieTypingsTable, TypingTableColumn } from './schema/typing';
import { MessageEntity } from '../../../domain/entity/message';
import { AttachmentTable, AttachmentTableColumn, DexieAttachmentsTableSchema } from './schema/attachment';
// import DexieMemory from 'dexie-in-memory';
import { AttachmentTableColumn, DexieAttachmentsTableSchema } from './schema/attachment';
// import FDBFactory from 'fake-indexeddb/lib/FDBFactory';
// import FDBKeyRange from 'fake-indexeddb/lib/FDBKeyRange';
// Database declaration (move this to its own module also)
export const chatDatabase = new Dexie('chat-database-infra') as Dexie & {
export const chatDatabase = new Dexie('chat-database-infra',{
// indexedDB: new FDBFactory,
// IDBKeyRange: FDBKeyRange, // Mocking IDBKeyRange
}) as Dexie & {
message: DexieMessageTable,
members: DexieMembersTableSchema,
room: DexieRoomsTable,
@@ -26,4 +31,4 @@ chatDatabase.version(1).stores({
});
chatDatabase.message.mapToClass(MessageEntity)
// Apply in-memory storage
// Apply in-memory storage