import type { Conversation , UserClients } from '@wireapp/api-client/src/conversation' ; import { CONVERSATION_TYPING } from '@wireapp/api-client/src/conversation/data' ; import type { ConversationEvent , TeamEvent , UserEvent } from '@wireapp/api-client/src/event' ; import type { User } from '@wireapp/api-client/src/user/' ; import type { Account } from '@wireapp/core' ; import type { PayloadBundle , ReactionType } from '@wireapp/core/src/main/conversation/' ; import type { ButtonActionConfirmationContent , CallingContent , FileContent , FileMetaDataContent , ImageContent , LinkPreviewContent , LocationContent , MentionContent , } from '@wireapp/core/src/main/conversation/content/' ; import type { QuotableMessage } from '@wireapp/core/src/main/conversation/message/OtrMessage' ; import { Asset , Confirmation , Text } from '@wireapp/protocol-messaging' ; import { promisify } from 'util' ; import fs from 'fs' ; import path from 'path' ; import FileType = require ( 'file-type' ) ; import { DefaultConversationRoleName } from '@wireapp/api-client/src/conversation' ; import { MessageBuilder } from '@wireapp/core/src/main/conversation/message/MessageBuilder' ; export abstract class MessageHandler { account : Account | undefined = undefined ; abstract handleEvent ( payload ) ; async addUser ( conversationId , userId ) { if ( this . account ?. service ) { await this . account . service . conversation . addUser ( conversationId , userId ) ; } } async clearConversation ( conversationId ) { if ( this . account ?. service ) { await this . account . service . conversation . clearConversation ( conversationId ) ; } } getConversation ( conversationId ) { return this . account ! . service ! . conversation . getConversations ( conversationId ) ; } getConversations ( conversationIds ? ) { return this . account ! . service ! . conversation . getConversations ( conversationIds ) ; } async getUser ( userId ) { return this . account ! . service ! . user . getUser ( userId ) ; } async getUsers ( userIds ) { return this . account ! . service ! . user . getUsers ( userIds ) ; } async removeUser ( conversationId , userId ) { if ( this . account ?. service ) { await this . account . service . conversation . removeUser ( conversationId , userId ) ; } } public async setAdminRole ( conversationId , userId ) { return this . account ! . service ! . conversation . setMemberConversationRole ( conversationId , userId , DefaultConversationRoleName . WIRE_ADMIN ) ; } public async setMemberRole ( conversationId , userId ) { return this . account ! . service ! . conversation . setMemberConversationRole ( conversationId , userId , DefaultConversationRoleName . WIRE_MEMBER ) ; } async sendButtonActionConfirmation ( conversationId , userId , referenceMessageId , buttonId ) { if ( this . account ?. service ) { const buttonActionConfirmationContent = { buttonId , referenceMessageId , } ; const buttonActionConfirmationMessage = MessageBuilder . createButtonActionConfirmationMessage ( { conversationId , from : this . account . userId , content : buttonActionConfirmationContent , } ) ; await this . account . service . conversation . send ( { payloadBundle : buttonActionConfirmationMessage , userIds : [ userId ] } ) ; } } param userIds async sendCall ( conversationId , content , userIds ? ) { if ( this . account ?. service ) { const callPayload = MessageBuilder . createCall ( { conversationId , from : this . account . userId , content } ) ; await this . account . service . conversation . send ( { payloadBundle : callPayload , userIds } ) ; } } param userIds async sendPoll ( conversationId , text , buttons , userIds ? ) { if ( this . account ?. service ) { const message = MessageBuilder . createComposite ( { conversationId , from : this . account . userId } ) . addText ( Text . create ( { content : text } ) ) ; buttons . forEach ( button => message . addButton ( button ) ) ; await this . account . service . conversation . send ( { payloadBundle : message . build ( ) , userIds } ) ; } } param userIds async sendConfirmation ( conversationId , firstMessageId , userIds ? ) { if ( this . account ?. service ) { const confirmationPayload = MessageBuilder . createConfirmation ( { conversationId , from : this . account . userId , firstMessageId , type : Confirmation . Type . DELIVERED , } ) ; await this . account . service . conversation . send ( { payloadBundle : confirmationPayload , userIds } ) ; } } async sendConnectionRequest ( userId ) { if ( this . account ?. service ) { await this . account . service . connection . createConnection ( userId ) ; } } async sendConnectionResponse ( userId , accept ) { if ( this . account ?. service ) { if ( accept ) { await this . account . service . connection . acceptConnection ( userId ) ; } else { await this . account . service . connection . ignoreConnection ( userId ) ; } } } param userIds async sendEditedText ( conversationId , originalMessageId , newMessageText , newMentions ? , newLinkPreview ? , userIds ? ) { if ( this . account ?. service ) { const editedPayload = MessageBuilder . createEditedText ( { conversationId , from : this . account . userId , newMessageText , originalMessageId , } ) . withMentions ( newMentions ) . build ( ) ; const editedMessage = await this . account . service . conversation . send ( { payloadBundle : editedPayload , userIds } ) ; if ( newLinkPreview ) { const editedWithPreviewPayload = MessageBuilder . createEditedText ( { from : this . account . userId , conversationId , newMessageText , originalMessageId , messageId : editedMessage . id , } ) . withLinkPreviews ( [ await this . account . service . linkPreview . uploadLinkPreviewImage ( newLinkPreview ) ] ) . withMentions ( newMentions ) . build ( ) ; await this . account . service . conversation . send ( { payloadBundle : editedWithPreviewPayload , userIds } ) ; } } } async sendFileByPath ( conversationId , filePath , userIds ? ) { const data = await promisify ( fs . readFile ) ( filePath ) ; const fileType = await FileType . fromBuffer ( data ) ; const metadata = { length : data . length , name : path . basename ( filePath ) , type : fileType ? fileType . mime : 'text/plain' , } ; return this . sendFile ( conversationId , { data , } , metadata , userIds ) ; } param userIds async sendFile ( conversationId , file , metadata , userIds ? ) { if ( this . account ?. service ) { const metadataPayload = MessageBuilder . createFileMetadata ( { conversationId , metaData : metadata , from : this . account . userId , } ) ; await this . account . service . conversation . send ( { payloadBundle : metadataPayload , userIds } ) ; try { const filePayload = MessageBuilder . createFileData ( { conversationId , from : this . account . userId , file , asset : await ( await this . account . service ! . asset . uploadAsset ( file . data ) ) . response , originalMessageId : metadataPayload . id , } ) ; await this . account . service . conversation . send ( { payloadBundle : filePayload , userIds } ) ; } catch ( error ) { const abortPayload = await MessageBuilder . createFileAbort ( { conversationId , from : this . account . userId , reason : Asset . NotUploaded . FAILED , originalMessageId : metadataPayload . id , } ) ; await this . account . service . conversation . send ( { payloadBundle : abortPayload , userIds } ) ; } } } param userIds async sendImage ( conversationId , image , userIds ? ) { if ( this . account ?. service ) { const imagePayload = MessageBuilder . createImage ( { conversationId , from : this . account . userId , image , asset : await ( await this . account . service ! . asset . uploadAsset ( image . data ) ) . response , } ) ; await this . account . service . conversation . send ( { payloadBundle : imagePayload , userIds } ) ; } } param userIds async sendLocation ( conversationId , location , userIds ? ) { if ( this . account ?. service ) { const locationPayload = MessageBuilder . createLocation ( { conversationId , from : this . account . userId , location , } ) ; await this . account . service . conversation . send ( { payloadBundle : locationPayload , userIds } ) ; } } param userIds async sendPing ( conversationId , userIds ? ) { if ( this . account ?. service ) { const pingPayload = MessageBuilder . createPing ( { conversationId , from : this . account . userId } ) ; await this . account . service . conversation . send ( { payloadBundle : pingPayload , userIds } ) ; } } param userIds async sendReaction ( conversationId , originalMessageId , type , userIds ? ) { if ( this . account ?. service ) { const reactionPayload = MessageBuilder . createReaction ( { conversationId , from : this . account . userId , reaction : { originalMessageId , type , } , } ) ; await this . account . service . conversation . send ( { payloadBundle : reactionPayload , userIds } ) ; } } async sendQuote ( conversationId , quotedMessage , text , userIds ? ) { if ( this . account ?. service ) { const replyPayload = MessageBuilder . createText ( { conversationId , text , from : this . account . userId } ) . withQuote ( quotedMessage ) . build ( ) ; await this . account . service . conversation . send ( { payloadBundle : replyPayload , userIds } ) ; } } param userIds sendReply ( conversationId , quotedMessage , text , userIds ? ) { return this . sendQuote ( conversationId , quotedMessage , text , userIds ) ; } param userIds async sendText ( conversationId , text , mentions ? , linkPreview ? , userIds ? ) { if ( this . account ?. service ) { const payload = MessageBuilder . createText ( { conversationId , text , from : this . account . userId } ) . withMentions ( mentions ) . build ( ) ; const sentMessage = await this . account . service . conversation . send ( { payloadBundle : payload , userIds } ) ; if ( linkPreview ) { const editedWithPreviewPayload = MessageBuilder . createText ( { conversationId , text , from : this . account . userId , messageId : sentMessage . id , } ) . withLinkPreviews ( [ await this . account . service ! . linkPreview . uploadLinkPreviewImage ( linkPreview ) ] ) . withMentions ( mentions ) . build ( ) ; await this . account . service . conversation . send ( { payloadBundle : editedWithPreviewPayload , userIds } ) ; } } } async sendTyping ( conversationId , status ) { if ( this . account ?. service ) { if ( status === CONVERSATION_TYPING . STARTED ) { await this . account . service . conversation . sendTypingStart ( conversationId ) ; } else { await this . account . service . conversation . sendTypingStop ( conversationId ) ; } } } }