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  }