import { ChatClient , ChatMessageReadReceipt , ChatMessageType } from '@azure/communication-chat' ; import { ChatMessageDeletedEvent , ChatMessageEditedEvent , ChatMessageReceivedEvent , ChatThreadCreatedEvent , ChatThreadDeletedEvent , ChatThreadPropertiesUpdatedEvent , ParticipantsAddedEvent , ParticipantsRemovedEvent , ReadReceiptReceivedEvent , TypingIndicatorReceivedEvent } from '@azure/communication-signaling' ; import { ChatContext } from './ChatContext' ; import { convertChatMessage } from './convertChatMessage' ; import { ChatMessageWithStatus } from './types/ChatMessageWithStatus' ; const maxSyncTimeInMs = 10 * 1000 ; private export class EventSubscriber { private chatClient : ChatClient ; private chatContext : ChatContext ; constructor ( chatClient , chatContext ) { this . chatClient = chatClient ; this . chatContext = chatContext ; this . subscribe ( ) ; } private convertEventToChatMessage = ( event ) : ChatMessageWithStatus => { return convertChatMessage ( { id : event . id , version : event . version , content : { message : event . message } , type : this . convertEventType ( event . type ) , sender : event . sender , senderDisplayName : event . senderDisplayName , sequenceId : '' , createdOn : new Date ( event . createdOn ) , editedOn : 'editedOn' in event ? event . editedOn : undefined } ) ; } ; private convertEventType = ( type ) : ChatMessageType => { const lowerCaseType = type . toLowerCase ( ) ; if ( lowerCaseType === 'richtext/html' || lowerCaseType === 'html' ) { return 'html' ; } else { return 'text' ; } } ; private onChatMessageReceived = ( event ) : void => { const messageEventType = event . type . toLowerCase ( ) ; if ( messageEventType !== 'text' && messageEventType !== 'richtext/html' && messageEventType !== 'html' ) { return ; } const newMessage = this . convertEventToChatMessage ( event ) ; const existingMessage = this . chatContext . getState ( ) . threads [ event . threadId ] ?. chatMessages [ event . id ] ; if ( existingMessage ) { newMessage . sequenceId = existingMessage . sequenceId ; } this . chatContext . batch ( ( ) => { this . chatContext . createThreadIfNotExist ( event . threadId ) ; this . chatContext . setChatMessage ( event . threadId , newMessage ) ; } ) ; } ; private onChatMessageDeleted = ( event ) : void => { this . chatContext . deleteMessage ( event . threadId , event . id ) ; } ; private onChatMessageEdited = ( event ) : void => { const editedMessage = this . convertEventToChatMessage ( event ) ; this . chatContext . setChatMessage ( event . threadId , convertChatMessage ( editedMessage ) ) ; } ; private onParticipantsAdded = ( event ) : void => { const participantsToAdd = event . participantsAdded . map ( ( participant ) => ( { ... participant , shareHistoryTime : participant . shareHistoryTime ? new Date ( participant . shareHistoryTime ) : undefined } ) ) ; this . chatContext . batch ( ( ) => { this . chatContext . createThreadIfNotExist ( event . threadId ) ; this . chatContext . setParticipants ( event . threadId , participantsToAdd ) ; } ) ; this . fetchLastParticipantMessage ( event . threadId , 'participantAdded' ) ; } ; private fetchLastParticipantMessage = async ( threadId , actionType ) : Promise < void > => { for await ( const message of this . chatClient . getChatThreadClient ( threadId ) . listMessages ( { startTime : new Date ( Date . now ( ) - maxSyncTimeInMs ) } ) ) { if ( message . type === actionType ) { this . chatContext . setChatMessage ( threadId , { ... message , status : 'delivered' } ) ; } } } ; private onParticipantsRemoved = ( event ) : void => { const participantIds = event . participantsRemoved . map ( ( participant ) => { return participant . id ; } ) ; this . chatContext . deleteParticipants ( event . threadId , participantIds ) ; this . fetchLastParticipantMessage ( event . threadId , 'participantRemoved' ) ; } ; private onReadReceiptReceived = ( event ) : void => { const readReceipt = { ... event , sender : event . sender , readOn : new Date ( event . readOn ) } ; this . chatContext . batch ( ( ) => { this . chatContext . createThreadIfNotExist ( event . threadId ) ; this . chatContext . addReadReceipt ( event . threadId , readReceipt ) ; } ) ; } ; private onTypingIndicatorReceived = ( typingIndicator ) : void => { this . chatContext . batch ( ( ) => { this . chatContext . createThreadIfNotExist ( typingIndicator . threadId ) ; this . chatContext . addTypingIndicator ( typingIndicator . threadId , typingIndicator ) ; } ) ; } ; private onChatThreadCreated = ( event ) : void => { const properties = { topic : event . properties . topic } ; if ( ! this . chatContext . createThreadIfNotExist ( event . threadId , properties ) ) { this . chatContext . updateThread ( event . threadId , properties ) ; } } ; private onChatThreadDeleted = ( event ) : void => { this . chatContext . deleteThread ( event . threadId ) ; } ; private onChatThreadPropertiesUpdated = ( event ) : void => { this . chatContext . updateThread ( event . threadId , { topic : event . properties . topic } ) ; } ; public subscribe = ( ) : void => { this . chatClient . on ( 'chatMessageReceived' , this . onChatMessageReceived ) ; this . chatClient . on ( 'chatMessageDeleted' , this . onChatMessageDeleted ) ; this . chatClient . on ( 'chatMessageEdited' , this . onChatMessageEdited ) ; this . chatClient . on ( 'participantsAdded' , this . onParticipantsAdded ) ; this . chatClient . on ( 'participantsRemoved' , this . onParticipantsRemoved ) ; this . chatClient . on ( 'readReceiptReceived' , this . onReadReceiptReceived ) ; this . chatClient . on ( 'typingIndicatorReceived' , this . onTypingIndicatorReceived ) ; this . chatClient . on ( 'chatThreadCreated' , this . onChatThreadCreated ) ; this . chatClient . on ( 'chatThreadDeleted' , this . onChatThreadDeleted ) ; this . chatClient . on ( 'chatThreadPropertiesUpdated' , this . onChatThreadPropertiesUpdated ) ; } ; public unsubscribe = ( ) : void => { this . chatClient . off ( 'chatMessageReceived' , this . onChatMessageReceived ) ; this . chatClient . off ( 'chatMessageDeleted' , this . onChatMessageDeleted ) ; this . chatClient . off ( 'chatMessageEdited' , this . onChatMessageEdited ) ; this . chatClient . off ( 'participantsAdded' , this . onParticipantsAdded ) ; this . chatClient . off ( 'participantsRemoved' , this . onParticipantsRemoved ) ; this . chatClient . off ( 'readReceiptReceived' , this . onReadReceiptReceived ) ; this . chatClient . off ( 'typingIndicatorReceived' , this . onTypingIndicatorReceived ) ; this . chatClient . off ( 'chatThreadCreated' , this . onChatThreadCreated ) ; this . chatClient . off ( 'chatThreadDeleted' , this . onChatThreadDeleted ) ; this . chatClient . off ( 'chatThreadPropertiesUpdated' , this . onChatThreadPropertiesUpdated ) ; } ; }