2022-08-22 08:40:14 +02:00
import { AbortSignal } from 'abort-controller' ;
2022-09-30 05:55:38 +02:00
import { getEmojiDataFromNative } from 'emoji-mart' ;
2022-08-22 08:40:14 +02:00
import { Data } from '../../../../data/data' ;
2022-08-30 03:37:20 +02:00
import { ConversationModel } from '../../../../models/conversation' ;
2022-09-30 05:55:38 +02:00
import {
Action ,
FixedBaseEmoji ,
OpenGroupReactionResponse ,
Reaction ,
} from '../../../../types/Reaction' ;
2022-08-30 09:18:22 +02:00
import { Reactions } from '../../../../util/reactions' ;
2022-08-22 08:40:14 +02:00
import { OnionSending } from '../../../onions/onionSend' ;
2022-08-30 03:37:20 +02:00
import { UserUtils } from '../../../utils' ;
2022-08-22 08:40:14 +02:00
import { OpenGroupPollingUtils } from '../opengroupV2/OpenGroupPollingUtils' ;
2022-08-30 03:37:20 +02:00
import { getUsBlindedInThatServer } from './knownBlindedkeys' ;
2022-08-22 08:40:14 +02:00
import { batchGlobalIsSuccess , parseBatchGlobalStatusCode } from './sogsV3BatchPoll' ;
2022-08-26 08:51:48 +02:00
import {
addToMutationCache ,
ChangeType ,
SogsV3Mutation ,
updateMutationCache ,
} from './sogsV3MutationCache' ;
2022-08-22 08:40:14 +02:00
2022-08-30 03:37:20 +02:00
export const hasReactionSupport = async (
serverId : number
) : Promise < { supported : boolean ; conversation : ConversationModel | null } > = > {
2022-08-22 08:40:14 +02:00
const found = await Data . getMessageByServerId ( serverId ) ;
if ( ! found ) {
window . log . warn ( ` Open Group Message ${ serverId } not found in db ` ) ;
2022-08-30 03:37:20 +02:00
return { supported : false , conversation : null } ;
2022-08-22 08:40:14 +02:00
}
const conversationModel = found ? . getConversation ( ) ;
if ( ! conversationModel ) {
window . log . warn ( ` Conversation for ${ serverId } not found in db ` ) ;
2022-08-30 03:37:20 +02:00
return { supported : false , conversation : null } ;
2022-08-22 08:40:14 +02:00
}
if ( ! conversationModel . hasReactions ( ) ) {
window . log . warn ( "This open group doesn't have reaction support. Server Message ID" , serverId ) ;
2022-08-30 03:37:20 +02:00
return { supported : false , conversation : null } ;
2022-08-22 08:40:14 +02:00
}
2022-08-30 03:37:20 +02:00
return { supported : true , conversation : conversationModel } ;
2022-08-22 08:40:14 +02:00
} ;
export const sendSogsReactionOnionV4 = async (
serverUrl : string ,
2022-08-29 08:10:47 +02:00
room : string , // this is the roomId
2022-08-22 08:40:14 +02:00
abortSignal : AbortSignal ,
reaction : Reaction ,
blinded : boolean
) : Promise < boolean > = > {
const allValidRoomInfos = OpenGroupPollingUtils . getAllValidRoomInfos ( serverUrl , new Set ( [ room ] ) ) ;
if ( ! allValidRoomInfos ? . length ) {
window ? . log ? . info ( 'getSendReactionRequest: no valid roominfos got.' ) ;
throw new Error ( ` Could not find sogs pubkey of url: ${ serverUrl } ` ) ;
}
2022-08-30 03:37:20 +02:00
const { supported , conversation } = await hasReactionSupport ( reaction . id ) ;
if ( ! supported ) {
2022-08-22 08:40:14 +02:00
return false ;
}
2022-08-30 09:18:22 +02:00
if ( Reactions . hitRateLimit ( ) ) {
2022-08-25 07:10:12 +02:00
return false ;
}
2022-08-30 03:37:20 +02:00
if ( ! conversation ) {
window . log . warn ( ` Conversation for ${ reaction . id } not found in db ` ) ;
return false ;
}
2022-08-25 07:10:12 +02:00
// The SOGS endpoint supports any text input so we need to make sure we are sending a valid unicode emoji
// for an invalid input we use https://emojipedia.org/frame-with-an-x/ as a replacement since it cannot rendered as an emoji but is valid unicode
2022-09-30 05:55:38 +02:00
// NOTE emoji-mart v5.2.2 types for getEmojiDataFromNative are broken
// @ts-ignore
const emoji = ( getEmojiDataFromNative ( reaction . emoji ) as FixedBaseEmoji ) ? reaction . emoji : '🖾' ;
2022-08-22 08:40:14 +02:00
const endpoint = ` /room/ ${ room } /reaction/ ${ reaction . id } / ${ emoji } ` ;
const method = reaction . action === Action . REACT ? 'PUT' : 'DELETE' ;
const serverPubkey = allValidRoomInfos [ 0 ] . serverPublicKey ;
2022-08-26 08:51:48 +02:00
const cacheEntry : SogsV3Mutation = {
server : serverUrl ,
room : room ,
changeType : ChangeType.REACTIONS ,
seqno : null ,
metadata : {
messageId : reaction.id ,
emoji ,
action : reaction.action === Action . REACT ? 'ADD' : 'REMOVE' ,
} ,
} ;
addToMutationCache ( cacheEntry ) ;
2022-08-30 03:37:20 +02:00
// Since responses can take a long time we immediately update the sender's UI and if there is a problem it is overwritten by handleOpenGroupMessageReactions later.
const me = UserUtils . getOurPubKeyStrFromCache ( ) ;
2022-08-30 09:18:22 +02:00
await Reactions . handleMessageReaction ( {
2022-08-30 03:37:20 +02:00
reaction ,
sender : blinded ? getUsBlindedInThatServer ( conversation ) || me : me ,
you : true ,
isOpenGroup : true ,
} ) ;
2022-08-22 08:40:14 +02:00
// reaction endpoint requires an empty dict {}
const stringifiedBody = null ;
const result = await OnionSending . sendJsonViaOnionV4ToSogs ( {
serverUrl ,
endpoint ,
serverPubkey ,
method ,
abortSignal ,
blinded ,
stringifiedBody ,
headers : null ,
throwErrors : true ,
} ) ;
if ( ! batchGlobalIsSuccess ( result ) ) {
window ? . log ? . warn ( 'sendSogsReactionWithOnionV4 Got unknown status code; res:' , result ) ;
throw new Error (
` sendSogsReactionOnionV4: invalid status code: ${ parseBatchGlobalStatusCode ( result ) } `
) ;
}
if ( ! result ) {
throw new Error ( 'Could not putReaction, res is invalid' ) ;
}
const rawMessage = result . body as OpenGroupReactionResponse ;
if ( ! rawMessage ) {
throw new Error ( 'putReaction parsing failed' ) ;
}
const success = Boolean ( reaction . action === Action . REACT ? rawMessage.added : rawMessage.removed ) ;
2022-08-26 08:51:48 +02:00
2022-08-29 08:10:47 +02:00
if ( success ) {
updateMutationCache ( cacheEntry , rawMessage . seqno ) ;
2022-08-26 08:51:48 +02:00
}
2022-08-22 08:40:14 +02:00
return success ;
} ;