github.com/status-im/status-go@v1.1.0/protocol/messenger_emoji_reactions.go (about) 1 package protocol 2 3 import ( 4 "context" 5 6 "github.com/pkg/errors" 7 8 "github.com/status-im/status-go/eth-node/crypto" 9 "github.com/status-im/status-go/eth-node/types" 10 "github.com/status-im/status-go/protocol/common" 11 "github.com/status-im/status-go/protocol/protobuf" 12 ) 13 14 func (m *Messenger) SendEmojiReaction(ctx context.Context, chatID, messageID string, emojiID protobuf.EmojiReaction_Type) (*MessengerResponse, error) { 15 var response MessengerResponse 16 17 chat, ok := m.allChats.Load(chatID) 18 if !ok { 19 return nil, ErrChatNotFound 20 } 21 clock, _ := chat.NextClockAndTimestamp(m.getTimesource()) 22 23 emojiR := &EmojiReaction{ 24 EmojiReaction: &protobuf.EmojiReaction{ 25 Clock: clock, 26 MessageId: messageID, 27 ChatId: chatID, 28 Type: emojiID, 29 }, 30 LocalChatID: chatID, 31 From: types.EncodeHex(crypto.FromECDSAPub(&m.identity.PublicKey)), 32 } 33 encodedMessage, err := m.encodeChatEntity(chat, emojiR) 34 if err != nil { 35 return nil, err 36 } 37 38 _, err = m.dispatchMessage(ctx, common.RawMessage{ 39 LocalChatID: chatID, 40 Payload: encodedMessage, 41 SkipGroupMessageWrap: true, 42 MessageType: protobuf.ApplicationMetadataMessage_EMOJI_REACTION, 43 // Don't resend using datasync, that would create quite a lot 44 // of traffic if clicking too eagelry 45 ResendType: common.ResendTypeNone, 46 }) 47 if err != nil { 48 return nil, err 49 } 50 51 response.AddEmojiReaction(emojiR) 52 response.AddChat(chat) 53 54 err = m.persistence.SaveEmojiReaction(emojiR) 55 if err != nil { 56 return nil, errors.Wrap(err, "Can't save emoji reaction in db") 57 } 58 59 return &response, nil 60 } 61 62 func (m *Messenger) EmojiReactionsByChatID(chatID string, cursor string, limit int) ([]*EmojiReaction, error) { 63 chat, err := m.persistence.Chat(chatID) 64 if err != nil { 65 return nil, err 66 } 67 68 if chat.Timeline() { 69 var chatIDs = []string{"@" + contactIDFromPublicKey(&m.identity.PublicKey)} 70 m.allContacts.Range(func(contactID string, contact *Contact) (shouldContinue bool) { 71 if contact.added() { 72 chatIDs = append(chatIDs, "@"+contact.ID) 73 } 74 return true 75 }) 76 return m.persistence.EmojiReactionsByChatIDs(chatIDs, cursor, limit) 77 } 78 return m.persistence.EmojiReactionsByChatID(chatID, cursor, limit) 79 } 80 81 func (m *Messenger) EmojiReactionsByChatIDMessageID(chatID string, messageID string) ([]*EmojiReaction, error) { 82 _, err := m.persistence.Chat(chatID) 83 if err != nil { 84 return nil, err 85 } 86 87 return m.persistence.EmojiReactionsByChatIDMessageID(chatID, messageID) 88 } 89 90 func (m *Messenger) SendEmojiReactionRetraction(ctx context.Context, emojiReactionID string) (*MessengerResponse, error) { 91 emojiR, err := m.persistence.EmojiReactionByID(emojiReactionID) 92 if err != nil { 93 return nil, err 94 } 95 96 // Check that the sender is the key owner 97 pk := types.EncodeHex(crypto.FromECDSAPub(&m.identity.PublicKey)) 98 if emojiR.From != pk { 99 return nil, errors.Errorf("identity mismatch, "+ 100 "emoji reactions can only be retracted by the reaction sender, "+ 101 "emoji reaction sent by '%s', current identity '%s'", 102 emojiR.From, pk, 103 ) 104 } 105 106 // Get chat and clock 107 chat, ok := m.allChats.Load(emojiR.GetChatId()) 108 if !ok { 109 return nil, ErrChatNotFound 110 } 111 clock, _ := chat.NextClockAndTimestamp(m.getTimesource()) 112 113 // Update the relevant fields 114 emojiR.Clock = clock 115 emojiR.Retracted = true 116 117 encodedMessage, err := m.encodeChatEntity(chat, emojiR) 118 if err != nil { 119 return nil, err 120 } 121 122 // Send the marshalled EmojiReactionRetraction protobuf 123 _, err = m.dispatchMessage(ctx, common.RawMessage{ 124 LocalChatID: emojiR.GetChatId(), 125 Payload: encodedMessage, 126 SkipGroupMessageWrap: true, 127 MessageType: protobuf.ApplicationMetadataMessage_EMOJI_REACTION, 128 // Don't resend using datasync, that would create quite a lot 129 // of traffic if clicking too eagelry 130 ResendType: common.ResendTypeNone, 131 }) 132 if err != nil { 133 return nil, err 134 } 135 136 // Update MessengerResponse 137 response := MessengerResponse{} 138 emojiR.Retracted = true 139 response.AddEmojiReaction(emojiR) 140 response.AddChat(chat) 141 142 // Persist retraction state for emoji reaction 143 err = m.persistence.SaveEmojiReaction(emojiR) 144 if err != nil { 145 return nil, err 146 } 147 148 return &response, nil 149 }