status-im/status-go

View on GitHub
protocol/messenger_emoji_reactions.go

Summary

Maintainability
A
0 mins
Test Coverage
D
62%
package protocol

import (
    "context"

    "github.com/pkg/errors"

    "github.com/status-im/status-go/eth-node/crypto"
    "github.com/status-im/status-go/eth-node/types"
    "github.com/status-im/status-go/protocol/common"
    "github.com/status-im/status-go/protocol/protobuf"
)

func (m *Messenger) SendEmojiReaction(ctx context.Context, chatID, messageID string, emojiID protobuf.EmojiReaction_Type) (*MessengerResponse, error) {
    var response MessengerResponse

    chat, ok := m.allChats.Load(chatID)
    if !ok {
        return nil, ErrChatNotFound
    }
    clock, _ := chat.NextClockAndTimestamp(m.getTimesource())

    emojiR := &EmojiReaction{
        EmojiReaction: &protobuf.EmojiReaction{
            Clock:     clock,
            MessageId: messageID,
            ChatId:    chatID,
            Type:      emojiID,
        },
        LocalChatID: chatID,
        From:        types.EncodeHex(crypto.FromECDSAPub(&m.identity.PublicKey)),
    }
    encodedMessage, err := m.encodeChatEntity(chat, emojiR)
    if err != nil {
        return nil, err
    }

    _, err = m.dispatchMessage(ctx, common.RawMessage{
        LocalChatID:          chatID,
        Payload:              encodedMessage,
        SkipGroupMessageWrap: true,
        MessageType:          protobuf.ApplicationMetadataMessage_EMOJI_REACTION,
        // Don't resend using datasync, that would create quite a lot
        // of traffic if clicking too eagelry
        ResendType: common.ResendTypeNone,
    })
    if err != nil {
        return nil, err
    }

    response.AddEmojiReaction(emojiR)
    response.AddChat(chat)

    err = m.persistence.SaveEmojiReaction(emojiR)
    if err != nil {
        return nil, errors.Wrap(err, "Can't save emoji reaction in db")
    }

    return &response, nil
}

func (m *Messenger) EmojiReactionsByChatID(chatID string, cursor string, limit int) ([]*EmojiReaction, error) {
    chat, err := m.persistence.Chat(chatID)
    if err != nil {
        return nil, err
    }

    if chat.Timeline() {
        var chatIDs = []string{"@" + contactIDFromPublicKey(&m.identity.PublicKey)}
        m.allContacts.Range(func(contactID string, contact *Contact) (shouldContinue bool) {
            if contact.added() {
                chatIDs = append(chatIDs, "@"+contact.ID)
            }
            return true
        })
        return m.persistence.EmojiReactionsByChatIDs(chatIDs, cursor, limit)
    }
    return m.persistence.EmojiReactionsByChatID(chatID, cursor, limit)
}

func (m *Messenger) EmojiReactionsByChatIDMessageID(chatID string, messageID string) ([]*EmojiReaction, error) {
    _, err := m.persistence.Chat(chatID)
    if err != nil {
        return nil, err
    }

    return m.persistence.EmojiReactionsByChatIDMessageID(chatID, messageID)
}

func (m *Messenger) SendEmojiReactionRetraction(ctx context.Context, emojiReactionID string) (*MessengerResponse, error) {
    emojiR, err := m.persistence.EmojiReactionByID(emojiReactionID)
    if err != nil {
        return nil, err
    }

    // Check that the sender is the key owner
    pk := types.EncodeHex(crypto.FromECDSAPub(&m.identity.PublicKey))
    if emojiR.From != pk {
        return nil, errors.Errorf("identity mismatch, "+
            "emoji reactions can only be retracted by the reaction sender, "+
            "emoji reaction sent by '%s', current identity '%s'",
            emojiR.From, pk,
        )
    }

    // Get chat and clock
    chat, ok := m.allChats.Load(emojiR.GetChatId())
    if !ok {
        return nil, ErrChatNotFound
    }
    clock, _ := chat.NextClockAndTimestamp(m.getTimesource())

    // Update the relevant fields
    emojiR.Clock = clock
    emojiR.Retracted = true

    encodedMessage, err := m.encodeChatEntity(chat, emojiR)
    if err != nil {
        return nil, err
    }

    // Send the marshalled EmojiReactionRetraction protobuf
    _, err = m.dispatchMessage(ctx, common.RawMessage{
        LocalChatID:          emojiR.GetChatId(),
        Payload:              encodedMessage,
        SkipGroupMessageWrap: true,
        MessageType:          protobuf.ApplicationMetadataMessage_EMOJI_REACTION,
        // Don't resend using datasync, that would create quite a lot
        // of traffic if clicking too eagelry
        ResendType: common.ResendTypeNone,
    })
    if err != nil {
        return nil, err
    }

    // Update MessengerResponse
    response := MessengerResponse{}
    emojiR.Retracted = true
    response.AddEmojiReaction(emojiR)
    response.AddChat(chat)

    // Persist retraction state for emoji reaction
    err = m.persistence.SaveEmojiReaction(emojiR)
    if err != nil {
        return nil, err
    }

    return &response, nil
}