diff --git a/src/app/module/chat/data/data-source/message/message-local-data-source.service.ts b/src/app/module/chat/data/data-source/message/message-local-data-source.service.ts index 8c7970e01..24bfc8b38 100644 --- a/src/app/module/chat/data/data-source/message/message-local-data-source.service.ts +++ b/src/app/module/chat/data/data-source/message/message-local-data-source.service.ts @@ -9,7 +9,7 @@ import { MessageEntity } from '../../../domain/entity/message'; const tableSchema = z.object({ - $id: z.any().optional(), + $id: z.number().optional(), id: z.string().optional(), roomId: z.string().uuid(), message: z.string(), @@ -117,7 +117,7 @@ export class MessageLocalDataSourceService { try { const result = await messageDataSource.message.add(data) this.messageSubject.next({roomId: data.roomId}); - return ok(result as string) + return ok(result as number) } catch (e) { return err(false) } @@ -136,7 +136,7 @@ export class MessageLocalDataSourceService { try { const result = await messageDataSource.message.add(data) this.messageSubject.next({roomId: data.roomId}); - return ok(result as string) + return ok(result) } catch (e) { return err(false) } @@ -179,11 +179,11 @@ export class MessageLocalDataSourceService { } + // not used async updateByMessageId(data: TableMessage ) { try { - console.log('update sdfsdfsd') - const result = await messageDataSource.message.update(data.id, data) + const result = await messageDataSource.message.update(data.id as any, data) return ok(result) } catch (e) { return err(false) diff --git a/src/app/module/chat/data/dto/message/messageInputDtO.ts b/src/app/module/chat/data/dto/message/messageInputDtO.ts index 5175a2399..0c1da5a5d 100644 --- a/src/app/module/chat/data/dto/message/messageInputDtO.ts +++ b/src/app/module/chat/data/dto/message/messageInputDtO.ts @@ -8,6 +8,7 @@ export const MessageInputDTOSchema = z.object({ canEdit: z.boolean(), oneShot: z.boolean(), requireUnlock: z.boolean(), + requestId: z.string() }); diff --git a/src/app/module/chat/data/repository/message-respository.service.ts b/src/app/module/chat/data/repository/message-respository.service.ts index 951097877..82bdd1c07 100644 --- a/src/app/module/chat/data/repository/message-respository.service.ts +++ b/src/app/module/chat/data/repository/message-respository.service.ts @@ -1,7 +1,6 @@ import { Injectable } from '@angular/core'; import { MessageRemoteDataSourceService } from '../data-source/message/message-remote-data-source.service'; import { MessageLiveDataSourceService } from '../data-source/message/message-live-data-source.service'; -import { MessageInputDTO } from '../dto/message/messageInputDtO'; import { MessageLocalDataSourceService, TableMessage } from '../data-source/message/message-local-data-source.service'; import { SessionStore } from 'src/app/store/session.service'; import { SignalRService } from '../../infra/socket/signal-r.service'; @@ -10,8 +9,10 @@ import { err, ok } from 'neverthrow'; import { MessageDeleteInputDTO } from '../../domain/use-case/message-delete-live-use-case.service'; import { MessageUpdateInput } from '../../domain/use-case/message-update-use-case.service'; import { messageListDetermineChanges } from '../async/list/rooms/messageListChangedetector'; +import { MessageEntity } from '../../domain/entity/message'; +import { InstanceId } from '../../domain/chat-service.service'; +import { MessageMapper } from '../../domain/mapper/messageMapper'; -export const InstanceId = uuidv4(); @Injectable({ providedIn: 'root' @@ -25,36 +26,21 @@ export class MessageRepositoryService { private messageLocalDataSourceService: MessageLocalDataSourceService ) {} - async sendMessage(data: MessageInputDTO) { + async sendMessage(entity: MessageEntity) { - (data as TableMessage).sender = { - userPhoto: '', - wxeMail: SessionStore.user.Email, - wxFullName: SessionStore.user.FullName, - wxUserId: SessionStore.user.UserId - } + const requestId = InstanceId +'@'+ uuidv4(); + const roomId = entity.roomId - data['requestId'] = InstanceId +'@'+ uuidv4(); - - const localActionResult = await this.messageLocalDataSourceService.sendMessage({...data}) - console.log('create message', data) - - // this.messageLiveDataSourceService.sendMessage({ - // type: 'sendMessage', - // payload: data - // }) + const localActionResult = await this.messageLocalDataSourceService.sendMessage(entity) if(localActionResult.isOk()) { - - const sendMessageResult = await this.messageLiveSignalRDataSourceService.sendMessage(data) - - - //const sendMessageResult = await this.messageRemoteDataSourceService.sendMessage(data) + const DTO = MessageMapper.fromDomain(entity, requestId) + const sendMessageResult = await this.messageLiveSignalRDataSourceService.sendMessage(DTO) if(sendMessageResult.isOk()) { if(sendMessageResult.value.sender == undefined || sendMessageResult.value.sender == null) { - console.log({sendMessageResult}) + delete sendMessageResult.value.sender } @@ -64,12 +50,12 @@ export class MessageRepositoryService { $id : localActionResult.value } - // console.log({clone}) - console.log('update message 11111') - return this.messageLocalDataSourceService.update({...clone, sending: false, roomId: data.roomId}) + return this.messageLocalDataSourceService.update({...clone, sending: false, roomId: entity.roomId}) return ok(true) } else { - console.log('no message to upload') + console.log('no message to upload', sendMessageResult.error) + return this.messageLocalDataSourceService.update({sending: false, $id: localActionResult.value}) + return err(false) } } else { diff --git a/src/app/module/chat/domain/chat-service.service.ts b/src/app/module/chat/domain/chat-service.service.ts index e6e03bf50..a84c5796a 100644 --- a/src/app/module/chat/domain/chat-service.service.ts +++ b/src/app/module/chat/domain/chat-service.service.ts @@ -4,13 +4,19 @@ import { SessionStore } from 'src/app/store/session.service'; import { MessageReactionInput, MessageReactionUseCaseService } from 'src/app/module/chat/domain/use-case/message-reaction-use-case.service'; import { MessageUpdateInput, MessageUpdateUseCaseService } from 'src/app/module/chat/domain/use-case/message-update-use-case.service'; import { MemberAdminUseCaseService, MemberSetAdminDTO } from 'src/app/module/chat/domain/use-case/member-admin-use-case.service'; +import { MessageCreateUseCaseService } from 'src/app/module/chat/domain/use-case/message-create-use-case.service'; import { SignalRService } from '../infra/socket/signal-r.service'; import { SocketMessageDeleteUseCaseService } from 'src/app/module/chat/domain/use-case/socket/socket-message-delete-use-case.service'; import { SocketMessageUpdateUseCaseService } from 'src/app/module/chat/domain/use-case/socket/socket-message-update-use-case.service'; import { SocketMessageCreateUseCaseService } from 'src/app/module/chat/domain/use-case/socket/socket-message-create-use-case.service'; import { MemberListUpdateStatusUseCaseService } from 'src/app/module/chat/domain/use-case/socket/member-list-update-status-use-case.service'; import { filter } from 'rxjs/operators'; -import { InstanceId } from '../data/repository/message-respository.service'; +import { v4 as uuidv4 } from 'uuid' +import { MessageInputDTO } from '../data/dto/message/messageInputDtO'; +import { MessageEntity } from './entity/message'; + +export const InstanceId = uuidv4(); + @Injectable({ providedIn: 'root' @@ -26,7 +32,8 @@ export class ChatServiceService { private SocketMessageUpdateUseCaseService: SocketMessageUpdateUseCaseService, private SocketMessageCreateUseCaseService: SocketMessageCreateUseCaseService, private MemberListUpdateStatusUseCaseService: MemberListUpdateStatusUseCaseService, - private MemberAdminUseCaseService: MemberAdminUseCaseService + private MemberAdminUseCaseService: MemberAdminUseCaseService, + private MessageCreateUseCaseService: MessageCreateUseCaseService ) { this.messageLiveSignalRDataSourceService.getMessageDelete() .pipe() @@ -98,5 +105,10 @@ export class ChatServiceService { setAdmin(input: MemberSetAdminDTO) { return this.MemberAdminUseCaseService.execute(input) } + + + sendMessage(input: MessageEntity) { + return this.MessageCreateUseCaseService.execute(input); + } } diff --git a/src/app/module/chat/domain/entity/message.ts b/src/app/module/chat/domain/entity/message.ts index 5e9e1bbd0..ddae7ba6a 100644 --- a/src/app/module/chat/domain/entity/message.ts +++ b/src/app/module/chat/domain/entity/message.ts @@ -27,18 +27,18 @@ export class MessageEntity implements Message { id: string roomId: string message: string - messageType: number - canEdit: boolean - oneShot: boolean + messageType: number = 0 + canEdit: boolean = false + oneShot: boolean = false sentAt: string - requireUnlock: boolean + requireUnlock: boolean = false sender: { wxUserId: number, wxFullName: string, wxeMail: string, userPhoto: string, } - sending: boolean + sending: boolean = false sendAttemp = 0 constructor() {} diff --git a/src/app/module/chat/domain/mapper/memberLIstMapper.ts b/src/app/module/chat/domain/mapper/memberLIstMapper.ts index 21d67c31e..1d904befe 100644 --- a/src/app/module/chat/domain/mapper/memberLIstMapper.ts +++ b/src/app/module/chat/domain/mapper/memberLIstMapper.ts @@ -11,4 +11,4 @@ export function MemberListMapper(outputDto: RoomByIdMemberItemOutputDTO, roomId: joinAt: outputDto.joinAt, isAdmin: outputDto.isAdmin } -} \ No newline at end of file +} diff --git a/src/app/module/chat/domain/mapper/messageMapper.ts b/src/app/module/chat/domain/mapper/messageMapper.ts new file mode 100644 index 000000000..0b550a11c --- /dev/null +++ b/src/app/module/chat/domain/mapper/messageMapper.ts @@ -0,0 +1,22 @@ +import { MessageInputDTO } from "../../data/dto/message/messageInputDtO"; +import { MessageOutPutDataDTO } from "../../data/dto/message/messageOutputDTO"; +import { MessageEntity } from "../entity/message"; + +export class MessageMapper { + static toDomain(DTO: MessageOutPutDataDTO) : MessageEntity { + return DTO as MessageEntity + } + + static fromDomain(entity:MessageEntity, requestId): MessageInputDTO { + return{ + canEdit: entity.canEdit, + message: entity.message, + messageType: entity.messageType, + oneShot: entity.oneShot, + requireUnlock: entity.requireUnlock, + roomId: entity.roomId, + senderId: entity.sender.wxUserId, + requestId: requestId + } + } +} diff --git a/src/app/module/chat/domain/use-case/message-create-use-case.service.ts b/src/app/module/chat/domain/use-case/message-create-use-case.service.ts new file mode 100644 index 000000000..c8a367c58 --- /dev/null +++ b/src/app/module/chat/domain/use-case/message-create-use-case.service.ts @@ -0,0 +1,33 @@ +import { Injectable } from '@angular/core'; +import { MessageEntity } from '../entity/message'; +import { SessionStore } from 'src/app/store/session.service'; +import { MessageRepositoryService } from "src/app/module/chat/data/repository/message-respository.service" +import { z } from 'zod'; + +const MessageInputUseCaseSchema = z.object({ + memberId: z.number(), + roomId: z.string(), + message: z.string() +}) + +export type MessageInputUseCase = z.infer< typeof MessageInputUseCaseSchema> + +@Injectable({ + providedIn: 'root' +}) +export class MessageCreateUseCaseService { + + constructor( + private MessageRepositoryService: MessageRepositoryService + ) { } + + + async execute(input: MessageEntity) { + + input.sendAttemp++; + + const result = await this.MessageRepositoryService.sendMessage(input) + + return result + } +} diff --git a/src/app/module/chat/infra/socket/signalR.ts b/src/app/module/chat/infra/socket/signalR.ts index 07fd6ff2b..608ff0115 100644 --- a/src/app/module/chat/infra/socket/signalR.ts +++ b/src/app/module/chat/infra/socket/signalR.ts @@ -25,7 +25,7 @@ export class SignalRConnection { private reconnect = true private sendDataSubject: BehaviorSubject<{method: string, data: any}> = new BehaviorSubject<{method: string, data: any}>(null); - + private pendingRequests: Map = new Map(); url: string constructor({url}) { @@ -61,6 +61,13 @@ export class SignalRConnection { console.log('Connection closed'); this.connectionStateSubject.next(false); this.disconnectSubject.next(true) + + this.pendingRequests.forEach((_, requestId) => { + const { reject } = this.pendingRequests.get(requestId); + reject(err('Connection closed================!s')); + this.pendingRequests.delete(requestId); + }); + if(this.reconnect) { this.attempReconnect(); } @@ -98,12 +105,17 @@ export class SignalRConnection { console.log('sendMessage', data) this.hubConnection.invoke("SendMessage", data) + // + this.pendingRequests.set(data.requestId, { resolve, reject: (data) => resolve(data) }); + this.messageSubject.pipe( filter((message: any) => data.requestId == message?.requestId), first() ).subscribe(value => { resolve(ok(value)) console.log('Received valid value:', value); + // + this.pendingRequests.delete(data.requestId); }); } else { diff --git a/src/app/shared/chat/messages/messages.page.ts b/src/app/shared/chat/messages/messages.page.ts index b43ddd5b1..705f58b7a 100644 --- a/src/app/shared/chat/messages/messages.page.ts +++ b/src/app/shared/chat/messages/messages.page.ts @@ -45,6 +45,7 @@ import { UserTypingList } from 'src/app/module/chat/data/data-source/userTyping/ import { ChatServiceService } from 'src/app/module/chat/domain/chat-service.service'; import { EditMessagePage } from 'src/app/modals/edit-message/edit-message.page'; import { tap } from 'rxjs/operators'; +import { MessageEntity } from 'src/app/module/chat/domain/entity/message'; const IMAGE_DIR = 'stored-images'; @@ -517,17 +518,31 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy sendMessage() { - const data: MessageInputDTO = { - roomId: this.roomId, - senderId: SessionStore.user.UserId, - message: this.textField, - messageType: 0, - canEdit: false, - oneShot:false, - requireUnlock: false, + // const data: MessageInputDTO = { + // roomId: this.roomId, + // senderId: SessionStore.user.UserId, + // message: this.textField, + // messageType: 0, + // canEdit: false, + // oneShot:false, + // requireUnlock: false, + // } + + // this.messageRepositoryService.sendMessage(data) + + const message = new MessageEntity(); + message.message = this.textField + message.roomId = this.roomId + + message.sender = { + userPhoto: '', + wxeMail: SessionStore.user.Email, + wxFullName: SessionStore.user.FullName, + wxUserId: SessionStore.user.UserId } - this.messageRepositoryService.sendMessage(data) + this.chatServiceService.sendMessage(message) + this.textField = '' }