Use same message with flag for emoji retraction and use compound id

This commit is contained in:
Andrea Maria Piana 2020-07-27 14:27:48 +02:00
parent 2bf1991190
commit 5a178939de
No known key found for this signature in database
GPG Key ID: AA6CCA6DE0E06424
13 changed files with 381 additions and 201 deletions

View File

@ -2,9 +2,13 @@ package protocol
import (
"crypto/ecdsa"
"encoding/json"
"fmt"
"github.com/golang/protobuf/proto"
"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/protobuf"
)
@ -13,19 +17,18 @@ import (
type EmojiReaction struct {
protobuf.EmojiReaction
// ID calculated as keccak256(compressedAuthorPubKey, data) where data is unencrypted payload.
ID string
// From is a public key of the author of the emoji reaction.
From string
// Retracted represents whether the user has chosen to remove a previously given reaction
Retracted bool
From string `json:"from,omitempty"`
// SigPubKey is the ecdsa encoded public key of the emoji reaction author
SigPubKey *ecdsa.PublicKey `json:"-"`
}
// ID is the Keccak256() contatenation of From-ChatID-MessageID-EmojiType
func (e EmojiReaction) ID() string {
return types.EncodeHex(crypto.Keccak256([]byte(fmt.Sprintf("%s%s%s%d", e.From, e.ChatId, e.MessageId, e.Type))))
}
// GetSigPubKey returns an ecdsa encoded public key
// this function is required to implement the ChatEntity interface
func (e EmojiReaction) GetSigPubKey() *ecdsa.PublicKey {
@ -43,3 +46,16 @@ func (e EmojiReaction) GetProtobuf() proto.Message {
func (e *EmojiReaction) SetMessageType(messageType protobuf.MessageType) {
e.MessageType = messageType
}
func (e *EmojiReaction) MarshalJSON() ([]byte, error) {
type EmojiAlias EmojiReaction
item := struct {
*EmojiAlias
ID string `json:"id"`
}{
EmojiAlias: (*EmojiAlias)(e),
ID: e.ID(),
}
return json.Marshal(item)
}

View File

@ -670,10 +670,22 @@ func (m *MessageHandler) messageExists(messageID string, existingMessagesMap map
func (m *MessageHandler) HandleEmojiReaction(state *ReceivedMessageState, pbEmojiR protobuf.EmojiReaction) error {
logger := m.logger.With(zap.String("site", "HandleEmojiReaction"))
from := state.CurrentMessageState.Contact.ID
// check that the user can actually send an emoji for this message
existingEmoji, err := m.persistence.EmojiReactionByFromMessageIDAndType(from, pbEmojiR.MessageId, pbEmojiR.Type)
if err != errRecordNotFound && err != nil {
return err
}
if existingEmoji != nil && existingEmoji.Clock >= pbEmojiR.Clock {
// this is not a valid emoji, ignoring
return nil
}
emojiReaction := &EmojiReaction{
EmojiReaction: pbEmojiR,
ID: state.CurrentMessageState.MessageID,
From: state.CurrentMessageState.Contact.ID,
From: from,
SigPubKey: state.CurrentMessageState.PublicKey,
}
chat, err := m.matchChatEntity(emojiReaction, state.AllChats, state.Timesource)
@ -681,6 +693,7 @@ func (m *MessageHandler) HandleEmojiReaction(state *ReceivedMessageState, pbEmoj
return err // matchChatEntity returns a descriptive error message
}
// TODO: make sure the user can actualy send an emoji for this chat.
logger.Info("Handling emoji reaction")
if chat.LastClockValue < pbEmojiR.Clock {
@ -690,9 +703,13 @@ func (m *MessageHandler) HandleEmojiReaction(state *ReceivedMessageState, pbEmoj
state.ModifiedChats[chat.ID] = true
state.AllChats[chat.ID] = chat
return nil
}
// save emoji reaction
err = m.persistence.SaveEmojiReaction(emojiReaction)
if err != nil {
return err
}
state.EmojiReactions[emojiReaction.ID()] = emojiReaction
func (m *MessageHandler) HandleEmojiReactionRetraction(state *ReceivedMessageState, pbEmojiR protobuf.EmojiReactionRetraction) error {
return nil
}

View File

@ -707,56 +707,25 @@ func (db sqlitePersistence) BlockContact(contact *Contact) ([]*Chat, error) {
}
func (db sqlitePersistence) SaveEmojiReaction(emojiReaction *EmojiReaction) (err error) {
tx, err := db.db.BeginTx(context.Background(), &sql.TxOptions{})
if err != nil {
return
}
defer func() {
if err == nil {
err = tx.Commit()
return
}
// don't shadow original error
_ = tx.Rollback()
}()
allFields := db.tableEmojiReactionsAllFields()
valuesVector := strings.Repeat("?, ", db.tableEmojiReactionsAllFieldsCount()-1) + "?"
query := "INSERT INTO emoji_reactions(" + allFields + ") VALUES (" + valuesVector + ")" // nolint: gosec
stmt, err := tx.Prepare(query)
query := "INSERT INTO emoji_reactions(id,clock_value,source,emoji_id,message_id,chat_id,retracted) VALUES (?,?,?,?,?,?,?)"
stmt, err := db.db.Prepare(query)
if err != nil {
return
}
allValues := []interface{}{
emojiReaction.ID,
_, err = stmt.Exec(
emojiReaction.ID(),
emojiReaction.Clock,
emojiReaction.From,
emojiReaction.Type,
emojiReaction.MessageId,
emojiReaction.ChatId,
emojiReaction.Retracted,
}
_, err = stmt.Exec(allValues...)
)
return
}
func (db sqlitePersistence) tableEmojiReactionsAllFields() string {
return `id,
clock_value,
source,
emoji_id,
message_id,
chat_id,
retracted`
}
func (db sqlitePersistence) tableEmojiReactionsAllFieldsCount() int {
return strings.Count(db.tableEmojiReactionsAllFields(), ",") + 1
}
func (db sqlitePersistence) EmojiReactionByID(id string) (*EmojiReaction, error) {
tx, err := db.db.BeginTx(context.Background(), &sql.TxOptions{})
if err != nil {
@ -772,20 +741,21 @@ func (db sqlitePersistence) EmojiReactionByID(id string) (*EmojiReaction, error)
}()
row := tx.QueryRow(
fmt.Sprintf(`
SELECT
%s
`SELECT
clock_value,
source,
emoji_id,
message_id,
chat_id,
retracted
FROM
emoji_reactions
WHERE
emoji_reactions.id = ?
`, db.tableEmojiReactionsAllFields()),
id,
)
`, id)
emojiReaction := new(EmojiReaction)
args := []interface{}{
&emojiReaction.ID,
&emojiReaction.Clock,
&emojiReaction.From,
&emojiReaction.Type,
@ -805,6 +775,61 @@ func (db sqlitePersistence) EmojiReactionByID(id string) (*EmojiReaction, error)
}
}
func (db sqlitePersistence) EmojiReactionByFromMessageIDAndType(from string, messageID string, emojiType protobuf.EmojiReaction_Type) (*EmojiReaction, error) {
tx, err := db.db.BeginTx(context.Background(), &sql.TxOptions{})
if err != nil {
return nil, err
}
defer func() {
if err == nil {
err = tx.Commit()
return
}
// don't shadow original error
_ = tx.Rollback()
}()
row := tx.QueryRow(
`SELECT
clock_value,
source,
emoji_id,
message_id,
chat_id,
retracted
FROM
emoji_reactions
WHERE
emoji_reactions.source = ?
AND
emoji_reactions.message_id = ?
AND
emoji_reactions.emoji_id = ?
`,
from,
messageID,
emojiType,
)
emojiReaction := new(EmojiReaction)
err = row.Scan(&emojiReaction.Clock,
&emojiReaction.From,
&emojiReaction.Type,
&emojiReaction.MessageId,
&emojiReaction.ChatId,
&emojiReaction.Retracted)
switch err {
case sql.ErrNoRows:
return nil, errRecordNotFound
case nil:
return emojiReaction, nil
default:
return nil, err
}
}
func (db sqlitePersistence) RetractEmojiReaction(id string) error {
_, err := db.db.Exec(`UPDATE emoji_reactions SET retracted = 1 WHERE id = ?`, id)
return err

View File

@ -1778,6 +1778,9 @@ type ReceivedMessageState struct {
ModifiedInstallations map[string]bool
// Map of existing messages
ExistingMessagesMap map[string]bool
// EmojiReactions is a list of emoji reactions for the current batch
// indexed by from-message-id-emoji-type
EmojiReactions map[string]*EmojiReaction
// Response to the client
Response *MessengerResponse
// Timesource is a time source for clock values/timestamps.
@ -1795,6 +1798,7 @@ func (m *Messenger) handleRetrievedMessages(chatWithMessages map[transport.Filte
AllInstallations: m.allInstallations,
ModifiedInstallations: m.modifiedInstallations,
ExistingMessagesMap: make(map[string]bool),
EmojiReactions: make(map[string]*EmojiReaction),
Response: &MessengerResponse{},
Timesource: m.getTimesource(),
}
@ -2040,13 +2044,6 @@ func (m *Messenger) handleRetrievedMessages(chatWithMessages map[transport.Filte
continue
}
case protobuf.EmojiReactionRetraction:
logger.Debug("Handling EmojiReactionRetraction")
err = m.handler.HandleEmojiReactionRetraction(messageState, msg.ParsedMessage.Interface().(protobuf.EmojiReactionRetraction))
if err != nil {
logger.Warn("failed to handle EmojiReactionRetraction", zap.Error(err))
continue
}
default:
// Check if is an encrypted PushNotificationRegistration
if msg.Type == protobuf.ApplicationMetadataMessage_PUSH_NOTIFICATION_REGISTRATION {
@ -2122,6 +2119,10 @@ func (m *Messenger) handleRetrievedMessages(chatWithMessages map[transport.Filte
}
}
for _, emojiReaction := range messageState.EmojiReactions {
messageState.Response.EmojiReactions = append(messageState.Response.EmojiReactions, emojiReaction)
}
if len(contactsToSave) > 0 {
err = m.persistence.SaveContacts(contactsToSave)
if err != nil {
@ -3227,7 +3228,7 @@ func generateAliasAndIdenticon(pk string) (string, string, error) {
}
func (m *Messenger) SendEmojiReaction(ctx context.Context, chatID, messageID string, emojiID int) (*MessengerResponse, error) {
func (m *Messenger) SendEmojiReaction(ctx context.Context, chatID, messageID string, emojiID protobuf.EmojiReaction_Type) (*MessengerResponse, error) {
m.mutex.Lock()
defer m.mutex.Unlock()
@ -3246,26 +3247,25 @@ func (m *Messenger) SendEmojiReaction(ctx context.Context, chatID, messageID str
ChatId: chatID,
Type: protobuf.EmojiReaction_Type(emojiID),
},
From: types.EncodeHex(crypto.FromECDSAPub(&m.identity.PublicKey)),
Retracted: false,
From: types.EncodeHex(crypto.FromECDSAPub(&m.identity.PublicKey)),
}
encodedMessage, err := m.encodeChatEntity(chat, emojiR)
if err != nil {
return nil, err
}
id, err := m.dispatchMessage(ctx, &common.RawMessage{
LocalChatID: chatID,
Payload: encodedMessage,
MessageType: protobuf.ApplicationMetadataMessage_EMOJI_REACTION,
ResendAutomatically: true,
_, err = m.dispatchMessage(ctx, &common.RawMessage{
LocalChatID: chatID,
Payload: encodedMessage,
MessageType: protobuf.ApplicationMetadataMessage_EMOJI_REACTION,
// Don't resend using datasync, that would create quite a lot
// of traffic if clicking too eagelry
ResendAutomatically: false,
})
if err != nil {
return nil, err
}
emojiR.ID = types.EncodeHex(id)
response.EmojiReactions = []*EmojiReaction{emojiR}
response.Chats = []*Chat{chat}
@ -3281,44 +3281,45 @@ func (m *Messenger) SendEmojiReactionRetraction(ctx context.Context, emojiReacti
m.mutex.Lock()
defer m.mutex.Unlock()
emojiReaction, err := m.persistence.EmojiReactionByID(emojiReactionID)
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 emojiReaction.From != pk {
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'",
emojiReaction.From, pk,
emojiR.From, pk,
)
}
// Get chat and clock
chat, ok := m.allChats[emojiReaction.GetChatId()]
chat, ok := m.allChats[emojiR.GetChatId()]
if !ok {
return nil, ErrChatNotFound
}
clock, _ := chat.NextClockAndTimestamp(m.getTimesource())
// Build the EmojiReactionRetraction protobuf struct
emojiRR := &protobuf.EmojiReactionRetraction{
Clock: clock,
EmojiReactionId: emojiReactionID,
}
encodedMessage, err := proto.Marshal(emojiRR)
// 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: emojiReaction.GetChatId(),
Payload: encodedMessage,
MessageType: protobuf.ApplicationMetadataMessage_EMOJI_REACTION_RETRACTION,
ResendAutomatically: true,
LocalChatID: emojiR.GetChatId(),
Payload: encodedMessage,
MessageType: protobuf.ApplicationMetadataMessage_EMOJI_REACTION,
// Don't resend using datasync, that would create quite a lot
// of traffic if clicking too eagelry
ResendAutomatically: false,
})
if err != nil {
return nil, err
@ -3326,8 +3327,8 @@ func (m *Messenger) SendEmojiReactionRetraction(ctx context.Context, emojiReacti
// Update MessengerResponse
response := MessengerResponse{}
emojiReaction.Retracted = true
response.EmojiReactions = []*EmojiReaction{emojiReaction}
emojiR.Retracted = true
response.EmojiReactions = []*EmojiReaction{emojiR}
response.Chats = []*Chat{chat}
// Persist retraction state for emoji reaction

View File

@ -0,0 +1,165 @@
package protocol
import (
"context"
"crypto/ecdsa"
"io/ioutil"
"os"
"testing"
"github.com/google/uuid"
"github.com/stretchr/testify/suite"
"go.uber.org/zap"
gethbridge "github.com/status-im/status-go/eth-node/bridge/geth"
"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/protobuf"
"github.com/status-im/status-go/protocol/tt"
"github.com/status-im/status-go/waku"
)
func TestMessengerEmojiSuite(t *testing.T) {
suite.Run(t, new(MessengerEmojiSuite))
}
type MessengerEmojiSuite struct {
suite.Suite
m *Messenger // main instance of Messenger
privateKey *ecdsa.PrivateKey // private key for the main instance of Messenger
// If one wants to send messages between different instances of Messenger,
// a single Waku service should be shared.
shh types.Waku
tmpFiles []*os.File // files to clean up
logger *zap.Logger
}
func (s *MessengerEmojiSuite) SetupTest() {
s.logger = tt.MustCreateTestLogger()
config := waku.DefaultConfig
config.MinimumAcceptedPoW = 0
shh := waku.New(&config, s.logger)
s.shh = gethbridge.NewGethWakuWrapper(shh)
s.Require().NoError(shh.Start(nil))
s.m = s.newMessenger(s.shh)
s.privateKey = s.m.identity
}
func (s *MessengerEmojiSuite) newMessengerWithKey(shh types.Waku, privateKey *ecdsa.PrivateKey) *Messenger {
tmpFile, err := ioutil.TempFile("", "")
s.Require().NoError(err)
options := []Option{
WithCustomLogger(s.logger),
WithMessagesPersistenceEnabled(),
WithDatabaseConfig(tmpFile.Name(), "some-key"),
WithDatasync(),
}
installationID := uuid.New().String()
m, err := NewMessenger(
privateKey,
&testNode{shh: shh},
installationID,
options...,
)
s.Require().NoError(err)
err = m.Init()
s.Require().NoError(err)
s.tmpFiles = append(s.tmpFiles, tmpFile)
return m
}
func (s *MessengerEmojiSuite) newMessenger(shh types.Waku) *Messenger {
privateKey, err := crypto.GenerateKey()
s.Require().NoError(err)
return s.newMessengerWithKey(s.shh, privateKey)
}
func (s *MessengerEmojiSuite) TestSendEmoji() {
alice := s.m
key, err := crypto.GenerateKey()
s.Require().NoError(err)
bob := s.newMessengerWithKey(s.shh, key)
chatID := "status"
chat := CreatePublicChat(chatID, alice.transport)
err = alice.SaveChat(&chat)
s.Require().NoError(err)
err = alice.Join(chat)
s.Require().NoError(err)
err = bob.SaveChat(&chat)
s.Require().NoError(err)
err = bob.Join(chat)
s.Require().NoError(err)
// Send chat message from bob to alice
message := buildTestMessage(chat)
_, err = alice.SendChatMessage(context.Background(), message)
s.NoError(err)
// Wait for message to arrive to bob
response, err := WaitOnMessengerResponse(
bob,
func(r *MessengerResponse) bool { return len(r.Messages) > 0 },
"no messages",
)
s.Require().NoError(err)
s.Require().Len(response.Messages, 1)
messageID := response.Messages[0].ID
// Respond with an emoji, donald trump style
response, err = bob.SendEmojiReaction(context.Background(), chat.ID, messageID, protobuf.EmojiReaction_SAD)
s.Require().NoError(err)
s.Require().Len(response.EmojiReactions, 1)
emojiID := response.EmojiReactions[0].ID()
// Wait for the emoji to arrive to alice
response, err = WaitOnMessengerResponse(
alice,
func(r *MessengerResponse) bool { return len(r.EmojiReactions) > 0 },
"no emoji",
)
s.Require().NoError(err)
s.Require().Len(response.EmojiReactions, 1)
s.Require().Equal(response.EmojiReactions[0].ID(), emojiID)
s.Require().Equal(response.EmojiReactions[0].Type, protobuf.EmojiReaction_SAD)
// Retract the emoji
response, err = bob.SendEmojiReactionRetraction(context.Background(), emojiID)
s.Require().NoError(err)
s.Require().Len(response.EmojiReactions, 1)
s.Require().True(response.EmojiReactions[0].Retracted)
// Wait for the emoji to arrive to alice
response, err = WaitOnMessengerResponse(
alice,
func(r *MessengerResponse) bool { return len(r.EmojiReactions) > 0 },
"no emoji",
)
s.Require().NoError(err)
s.Require().Len(response.EmojiReactions, 1)
s.Require().Equal(response.EmojiReactions[0].ID(), emojiID)
s.Require().Equal(response.EmojiReactions[0].Type, protobuf.EmojiReaction_SAD)
s.Require().True(response.EmojiReactions[0].Retracted)
}

View File

@ -14,14 +14,10 @@
// 1591277220_add_index_messages.up.sql (240B)
// 1593087212_add_mute_chat_and_raw_message_fields.down.sql (0)
// 1593087212_add_mute_chat_and_raw_message_fields.up.sql (215B)
// 1594390919_create_emoji_reaction_table.down.sql (27B)
<<<<<<< HEAD
// 1594390919_create_emoji_reactions_table.up.sql (234B)
// 1594390919_create_emoji_reactions_table.down.sql (27B)
// 1594390919_create_emoji_reactions_table.up.sql (265B)
// 1595862781_add_audio_data.down.sql (0)
// 1595862781_add_audio_data.up.sql (246B)
=======
// 1594390919_create_emoji_reactions_table.up.sql (263B)
>>>>>>> 350ce45aa... make generate
// doc.go (850B)
package migrations
@ -371,27 +367,27 @@ func _1593087212_add_mute_chat_and_raw_message_fieldsUpSql() (*asset, error) {
return a, nil
}
var __1594390919_create_emoji_reaction_tableDownSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\x09\xf2\x0f\x50\x08\x71\x74\xf2\x71\x55\x48\xcd\xcd\xcf\xca\x8c\x2f\x4a\x4d\x4c\x2e\xc9\xcc\xcf\x2b\xb6\x06\x04\x00\x00\xff\xff\x54\xc5\xdd\x49\x1b\x00\x00\x00")
var __1594390919_create_emoji_reactions_tableDownSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x72\x09\xf2\x0f\x50\x08\x71\x74\xf2\x71\x55\x48\xcd\xcd\xcf\xca\x8c\x2f\x4a\x4d\x4c\x2e\xc9\xcc\xcf\x2b\xb6\x06\x04\x00\x00\xff\xff\x54\xc5\xdd\x49\x1b\x00\x00\x00")
func _1594390919_create_emoji_reaction_tableDownSqlBytes() ([]byte, error) {
func _1594390919_create_emoji_reactions_tableDownSqlBytes() ([]byte, error) {
return bindataRead(
__1594390919_create_emoji_reaction_tableDownSql,
"1594390919_create_emoji_reaction_table.down.sql",
__1594390919_create_emoji_reactions_tableDownSql,
"1594390919_create_emoji_reactions_table.down.sql",
)
}
func _1594390919_create_emoji_reaction_tableDownSql() (*asset, error) {
bytes, err := _1594390919_create_emoji_reaction_tableDownSqlBytes()
func _1594390919_create_emoji_reactions_tableDownSql() (*asset, error) {
bytes, err := _1594390919_create_emoji_reactions_tableDownSqlBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "1594390919_create_emoji_reaction_table.down.sql", size: 27, mode: os.FileMode(0644), modTime: time.Unix(1595864971, 0)}
info := bindataFileInfo{name: "1594390919_create_emoji_reactions_table.down.sql", size: 27, mode: os.FileMode(0644), modTime: time.Unix(1595865239, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x6f, 0xbb, 0xdb, 0x8c, 0xd1, 0x17, 0x1b, 0x19, 0x2a, 0x80, 0xc6, 0xb1, 0xc5, 0x47, 0x74, 0x97, 0x32, 0x30, 0x5, 0xa9, 0x9c, 0xa7, 0x60, 0xa, 0xfe, 0xfb, 0x41, 0x6b, 0x25, 0xad, 0x84, 0x20}}
return a, nil
}
var __1594390919_create_emoji_reactions_tableUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x74\xce\xbf\x4e\xc3\x30\x10\xc7\xf1\xbd\x52\xdf\xe1\x37\x82\xc4\xc0\xce\x64\xcc\x45\x58\x18\xa7\x72\xaf\xa8\x9d\x22\xcb\x3d\x81\x21\xc1\x92\xed\xf0\xfc\x88\x64\xe1\x8f\x98\x3f\x77\xdf\x3b\xed\x49\x31\x81\xd5\xad\x25\x98\x0e\xae\x67\xd0\xd1\xec\x79\x0f\x99\xf2\x6b\x1a\x8a\x84\xd8\x52\x7e\xaf\xb8\xd8\x6e\x80\x74\xc6\x93\xf2\xfa\x5e\x79\xec\xbc\x79\x54\xfe\x84\x07\x3a\xa1\x77\xd0\xbd\xeb\xac\xd1\x0c\x4f\x3b\xab\x34\x5d\x7d\x8d\xc7\x31\xc7\xb7\xe1\x23\x8c\xb3\xc0\x38\x5e\xf2\xee\x60\xed\x82\x35\xcf\x25\x0a\x98\x8e\xbf\x60\xbd\x9c\xce\x7f\x57\x26\xa9\x35\x3c\xcb\xf0\xed\x8d\x1f\x1e\x5f\x42\xfb\x17\x8b\xb4\x12\x62\x93\xb5\x7b\x47\x9d\x3a\x58\xc6\xf5\x76\x73\x79\xf3\x19\x00\x00\xff\xff\x66\x93\x81\x54\x07\x01\x00\x00")
var __1594390919_create_emoji_reactions_tableUpSql = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x74\xce\xbf\x4e\xc3\x30\x10\xc7\xf1\x3d\x52\xde\xe1\x37\x82\xc4\xc0\xce\x64\xcc\x45\x58\x18\xa7\x72\xaf\xa8\x9d\x22\xcb\x3d\x81\xa1\xc5\x92\xed\xf0\xfc\x88\x64\xe1\x8f\x98\x3f\x77\xdf\x3b\xed\x49\x31\x81\xd5\xad\x25\x98\x01\x6e\x64\xd0\xde\x6c\x79\x0b\x39\xe7\xd7\x34\x15\x09\xb1\xa5\xfc\x5e\x71\xd1\x77\x40\x3a\xe2\x49\x79\x7d\xaf\x3c\x36\xde\x3c\x2a\x7f\xc0\x03\x1d\x30\x3a\xe8\xd1\x0d\xd6\x68\x86\xa7\x8d\x55\x9a\xae\xbe\xc6\xe3\x29\xc7\xb7\xe9\x23\x9c\x66\x81\x71\xbc\xe4\xdd\xce\xda\x05\x6b\x9e\x4b\x14\x30\xed\x7f\xc1\x7a\x39\x1d\xff\xae\x9c\xa5\xd6\xf0\x2c\xd3\xb7\x37\x7e\x78\x7c\x09\xed\x5f\x2c\xd2\x4a\x88\x4d\xd6\xee\x1d\x0d\x6a\x67\x19\xd7\x7d\x77\x79\xd3\x77\x9f\x01\x00\x00\xff\xff\xf2\xdf\x03\x4e\x09\x01\x00\x00")
func _1594390919_create_emoji_reactions_tableUpSqlBytes() ([]byte, error) {
return bindataRead(
@ -406,20 +402,8 @@ func _1594390919_create_emoji_reactions_tableUpSql() (*asset, error) {
return nil, err
}
<<<<<<< HEAD
<<<<<<< HEAD
info := bindataFileInfo{name: "1594390919_create_emoji_reactions_table.up.sql", size: 234, mode: os.FileMode(0644), modTime: time.Unix(1595864971, 0)}
=======
<<<<<<< HEAD
info := bindataFileInfo{name: "1594390919_create_emoji_reactions_table.up.sql", size: 234, mode: os.FileMode(0644), modTime: time.Unix(1595840825, 0)}
>>>>>>> 350ce45aa... make generate
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x5f, 0xcb, 0xf0, 0xaf, 0xa8, 0x82, 0xec, 0x10, 0xd0, 0xae, 0x83, 0x78, 0xa7, 0x90, 0x84, 0x3d, 0xc0, 0xfe, 0x6, 0xe6, 0xc8, 0x8b, 0xda, 0xe0, 0x1a, 0x81, 0x86, 0x61, 0xe9, 0xb0, 0xa2, 0x31}}
=======
info := bindataFileInfo{name: "1594390919_create_emoji_reactions_table.up.sql", size: 263, mode: os.FileMode(0644), modTime: time.Unix(1595339114, 0)}
=======
info := bindataFileInfo{name: "1594390919_create_emoji_reactions_table.up.sql", size: 263, mode: os.FileMode(0644), modTime: time.Unix(1595840951, 0)}
>>>>>>> 546b68df9... Added general protobuf umarshaller function
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x60, 0xab, 0x81, 0xa6, 0x1a, 0x5a, 0x9, 0xee, 0x72, 0x18, 0x5d, 0xe7, 0xf1, 0x94, 0x66, 0x2d, 0x38, 0x29, 0x57, 0xf8, 0xec, 0x1c, 0x1b, 0x1f, 0xc6, 0x1d, 0xb5, 0x2e, 0xe8, 0x15, 0x8, 0x74}}
info := bindataFileInfo{name: "1594390919_create_emoji_reactions_table.up.sql", size: 265, mode: os.FileMode(0644), modTime: time.Unix(1595865239, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x13, 0x28, 0xa4, 0x70, 0xf0, 0xfe, 0xd, 0xc2, 0x16, 0xc3, 0x1d, 0xbb, 0x3c, 0x1, 0xf6, 0x58, 0x69, 0x2a, 0x27, 0x21, 0xbc, 0x8b, 0xc8, 0x1a, 0xd, 0x36, 0x2d, 0x29, 0x0, 0xc3, 0xfa, 0xad}}
return a, nil
}
@ -602,7 +586,7 @@ var _bindata = map[string]func() (*asset, error){
"1593087212_add_mute_chat_and_raw_message_fields.up.sql": _1593087212_add_mute_chat_and_raw_message_fieldsUpSql,
"1594390919_create_emoji_reaction_table.down.sql": _1594390919_create_emoji_reaction_tableDownSql,
"1594390919_create_emoji_reactions_table.down.sql": _1594390919_create_emoji_reactions_tableDownSql,
"1594390919_create_emoji_reactions_table.up.sql": _1594390919_create_emoji_reactions_tableUpSql,
@ -668,7 +652,7 @@ var _bintree = &bintree{nil, map[string]*bintree{
"1591277220_add_index_messages.up.sql": &bintree{_1591277220_add_index_messagesUpSql, map[string]*bintree{}},
"1593087212_add_mute_chat_and_raw_message_fields.down.sql": &bintree{_1593087212_add_mute_chat_and_raw_message_fieldsDownSql, map[string]*bintree{}},
"1593087212_add_mute_chat_and_raw_message_fields.up.sql": &bintree{_1593087212_add_mute_chat_and_raw_message_fieldsUpSql, map[string]*bintree{}},
"1594390919_create_emoji_reaction_table.down.sql": &bintree{_1594390919_create_emoji_reaction_tableDownSql, map[string]*bintree{}},
"1594390919_create_emoji_reactions_table.down.sql": &bintree{_1594390919_create_emoji_reactions_tableDownSql, map[string]*bintree{}},
"1594390919_create_emoji_reactions_table.up.sql": &bintree{_1594390919_create_emoji_reactions_tableUpSql, map[string]*bintree{}},
"1595862781_add_audio_data.down.sql": &bintree{_1595862781_add_audio_dataDownSql, map[string]*bintree{}},
"1595862781_add_audio_data.up.sql": &bintree{_1595862781_add_audio_dataUpSql, map[string]*bintree{}},

View File

@ -6,4 +6,4 @@ CREATE TABLE IF NOT EXISTS emoji_reactions (
message_id VARCHAR NOT NULL,
chat_id VARCHAR NOT NULL,
retracted INT DEFAULT 0
);
);

View File

@ -61,14 +61,22 @@ func (EmojiReaction_Type) EnumDescriptor() ([]byte, []int) {
}
type EmojiReaction struct {
Clock uint64 `protobuf:"varint,1,opt,name=clock,proto3" json:"clock,omitempty"`
ChatId string `protobuf:"bytes,2,opt,name=chat_id,json=chatId,proto3" json:"chat_id,omitempty"`
MessageId string `protobuf:"bytes,3,opt,name=message_id,json=messageId,proto3" json:"message_id,omitempty"`
MessageType MessageType `protobuf:"varint,4,opt,name=message_type,json=messageType,proto3,enum=protobuf.MessageType" json:"message_type,omitempty"`
Type EmojiReaction_Type `protobuf:"varint,5,opt,name=type,proto3,enum=protobuf.EmojiReaction_Type" json:"type,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
// clock Lamport timestamp of the chat message
Clock uint64 `protobuf:"varint,1,opt,name=clock,proto3" json:"clock,omitempty"`
// chat_id the ID of the chat the message belongs to, for query efficiency the chat_id is stored in the db even though the
// target message also stores the chat_id
ChatId string `protobuf:"bytes,2,opt,name=chat_id,json=chatId,proto3" json:"chat_id,omitempty"`
// message_id the ID of the target message that the user wishes to react to
MessageId string `protobuf:"bytes,3,opt,name=message_id,json=messageId,proto3" json:"message_id,omitempty"`
// message_type is (somewhat confusingly) the ID of the type of chat the message belongs to
MessageType MessageType `protobuf:"varint,4,opt,name=message_type,json=messageType,proto3,enum=protobuf.MessageType" json:"message_type,omitempty"`
// type the ID of the emoji the user wishes to react with
Type EmojiReaction_Type `protobuf:"varint,5,opt,name=type,proto3,enum=protobuf.EmojiReaction_Type" json:"type,omitempty"`
// whether this is a rectraction of a previously sent emoji
Retracted bool `protobuf:"varint,6,opt,name=retracted,proto3" json:"retracted,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *EmojiReaction) Reset() { *m = EmojiReaction{} }
@ -131,81 +139,40 @@ func (m *EmojiReaction) GetType() EmojiReaction_Type {
return EmojiReaction_UNKNOWN_EMOJI_REACTION_TYPE
}
type EmojiReactionRetraction struct {
Clock uint64 `protobuf:"varint,1,opt,name=clock,proto3" json:"clock,omitempty"`
EmojiReactionId string `protobuf:"bytes,2,opt,name=emoji_reaction_id,json=emojiReactionId,proto3" json:"emoji_reaction_id,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *EmojiReactionRetraction) Reset() { *m = EmojiReactionRetraction{} }
func (m *EmojiReactionRetraction) String() string { return proto.CompactTextString(m) }
func (*EmojiReactionRetraction) ProtoMessage() {}
func (*EmojiReactionRetraction) Descriptor() ([]byte, []int) {
return fileDescriptor_0a088c907bbc7ed6, []int{1}
}
func (m *EmojiReactionRetraction) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_EmojiReactionRetraction.Unmarshal(m, b)
}
func (m *EmojiReactionRetraction) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_EmojiReactionRetraction.Marshal(b, m, deterministic)
}
func (m *EmojiReactionRetraction) XXX_Merge(src proto.Message) {
xxx_messageInfo_EmojiReactionRetraction.Merge(m, src)
}
func (m *EmojiReactionRetraction) XXX_Size() int {
return xxx_messageInfo_EmojiReactionRetraction.Size(m)
}
func (m *EmojiReactionRetraction) XXX_DiscardUnknown() {
xxx_messageInfo_EmojiReactionRetraction.DiscardUnknown(m)
}
var xxx_messageInfo_EmojiReactionRetraction proto.InternalMessageInfo
func (m *EmojiReactionRetraction) GetClock() uint64 {
func (m *EmojiReaction) GetRetracted() bool {
if m != nil {
return m.Clock
return m.Retracted
}
return 0
}
func (m *EmojiReactionRetraction) GetEmojiReactionId() string {
if m != nil {
return m.EmojiReactionId
}
return ""
return false
}
func init() {
proto.RegisterEnum("protobuf.EmojiReaction_Type", EmojiReaction_Type_name, EmojiReaction_Type_value)
proto.RegisterType((*EmojiReaction)(nil), "protobuf.EmojiReaction")
proto.RegisterType((*EmojiReactionRetraction)(nil), "protobuf.EmojiReactionRetraction")
}
func init() { proto.RegisterFile("emoji_reaction.proto", fileDescriptor_0a088c907bbc7ed6) }
var fileDescriptor_0a088c907bbc7ed6 = []byte{
// 320 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x91, 0xcf, 0x4e, 0xf2, 0x40,
0x14, 0xc5, 0xbf, 0xc2, 0x14, 0xe8, 0xe5, 0x43, 0xc6, 0x09, 0x06, 0xe2, 0x9f, 0x48, 0x58, 0x11,
0x17, 0x8d, 0xd1, 0x8d, 0xdb, 0x2a, 0x0d, 0x54, 0x61, 0x4a, 0x86, 0x56, 0x42, 0x5c, 0x4c, 0xa0,
0x1d, 0x15, 0xb5, 0xb4, 0x81, 0xb2, 0xe0, 0xd9, 0x7c, 0x39, 0xd3, 0xa1, 0xa4, 0x76, 0xe3, 0x6a,
0x72, 0xee, 0x39, 0xbf, 0xc9, 0x99, 0x3b, 0xd0, 0x10, 0x41, 0xf8, 0xb1, 0xe4, 0x6b, 0x31, 0xf7,
0xe2, 0x65, 0xb8, 0xd2, 0xa3, 0x75, 0x18, 0x87, 0xa4, 0x22, 0x8f, 0xc5, 0xf6, 0xf5, 0xb4, 0x2a,
0x56, 0xdb, 0x60, 0xb3, 0x1f, 0x77, 0xbe, 0x0b, 0x50, 0x33, 0x93, 0x3c, 0x4b, 0xe3, 0xa4, 0x01,
0xaa, 0xf7, 0x15, 0x7a, 0x9f, 0x2d, 0xa5, 0xad, 0x74, 0x11, 0xdb, 0x0b, 0xd2, 0x84, 0xb2, 0xf7,
0x3e, 0x8f, 0xf9, 0xd2, 0x6f, 0x15, 0xda, 0x4a, 0x57, 0x63, 0xa5, 0x44, 0x5a, 0x3e, 0xb9, 0x00,
0x08, 0xc4, 0x66, 0x33, 0x7f, 0x13, 0x89, 0x57, 0x94, 0x9e, 0x96, 0x4e, 0x2c, 0x9f, 0xdc, 0xc1,
0xff, 0x83, 0x1d, 0xef, 0x22, 0xd1, 0x42, 0x6d, 0xa5, 0x7b, 0x74, 0x73, 0xa2, 0x1f, 0xda, 0xe8,
0xa3, 0xbd, 0xeb, 0xec, 0x22, 0xc1, 0xaa, 0x41, 0x26, 0xc8, 0x35, 0x20, 0x49, 0xa8, 0x92, 0x38,
0xcf, 0x88, 0x5c, 0x5d, 0x5d, 0x82, 0x32, 0xd9, 0x89, 0x00, 0x49, 0xf2, 0x12, 0xce, 0x5c, 0xfa,
0x44, 0xed, 0x29, 0xe5, 0xe6, 0xc8, 0x7e, 0xb4, 0x38, 0x33, 0x8d, 0x07, 0xc7, 0xb2, 0x29, 0x77,
0x66, 0x63, 0x13, 0xff, 0x23, 0x15, 0x40, 0x43, 0xfb, 0xd9, 0xc4, 0x0a, 0xa9, 0x81, 0xe6, 0x0c,
0xdc, 0xd1, 0xfd, 0x84, 0xbb, 0x63, 0x5c, 0x20, 0x75, 0xa8, 0xa6, 0xb2, 0x67, 0x4f, 0x29, 0x2e,
0x12, 0x0d, 0xd4, 0xa1, 0xe1, 0xf6, 0x07, 0x18, 0x91, 0x32, 0x14, 0x27, 0x46, 0x0f, 0xab, 0xc9,
0xcc, 0xa0, 0x7d, 0x36, 0xc3, 0xa5, 0xce, 0x0b, 0x34, 0x73, 0x6d, 0x98, 0x88, 0xd7, 0x7f, 0xae,
0xf1, 0x0a, 0x8e, 0xf3, 0xbf, 0x93, 0x2d, 0xb4, 0x2e, 0x7e, 0xdf, 0x64, 0xf9, 0x8b, 0x92, 0x7c,
0xf1, 0xed, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x18, 0x16, 0x6b, 0xcc, 0xd0, 0x01, 0x00, 0x00,
// 305 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x54, 0x8e, 0xdf, 0x4f, 0x82, 0x50,
0x14, 0xc7, 0x43, 0x01, 0xe5, 0x98, 0x75, 0x77, 0x66, 0x8b, 0x95, 0x2d, 0xe6, 0x13, 0x4f, 0xac,
0xd5, 0x4b, 0xaf, 0x94, 0x4c, 0x29, 0x05, 0x77, 0x85, 0x9c, 0x4f, 0x0c, 0xe1, 0x56, 0x56, 0x08,
0xc3, 0xeb, 0x83, 0x7f, 0x6a, 0xff, 0x4d, 0xe3, 0xaa, 0x73, 0x3d, 0x9d, 0x7d, 0x7f, 0x7c, 0xce,
0xbe, 0xd0, 0x61, 0x59, 0xfe, 0xb5, 0x8c, 0x4a, 0x16, 0x27, 0x7c, 0x99, 0xaf, 0xac, 0xa2, 0xcc,
0x79, 0x8e, 0x4d, 0x71, 0x16, 0x9b, 0xf7, 0xab, 0x16, 0x5b, 0x6d, 0xb2, 0xf5, 0xce, 0xee, 0xfd,
0xd6, 0xa0, 0xed, 0x54, 0x7d, 0xba, 0xaf, 0x63, 0x07, 0x94, 0xe4, 0x27, 0x4f, 0xbe, 0x75, 0xc9,
0x90, 0x4c, 0x99, 0xee, 0x04, 0x5e, 0x42, 0x23, 0xf9, 0x8c, 0x79, 0xb4, 0x4c, 0xf5, 0x9a, 0x21,
0x99, 0x1a, 0x55, 0x2b, 0xe9, 0xa6, 0x78, 0x03, 0x90, 0xb1, 0xf5, 0x3a, 0xfe, 0x60, 0x55, 0x56,
0x17, 0x99, 0xb6, 0x77, 0xdc, 0x14, 0x1f, 0xe1, 0xf4, 0x10, 0xf3, 0x6d, 0xc1, 0x74, 0xd9, 0x90,
0xcc, 0xb3, 0xfb, 0x0b, 0xeb, 0xb0, 0xc6, 0x1a, 0xef, 0xd2, 0x60, 0x5b, 0x30, 0xda, 0xca, 0x8e,
0x02, 0xef, 0x40, 0x16, 0x84, 0x22, 0x88, 0xee, 0x91, 0xf8, 0x37, 0xd7, 0x12, 0xa0, 0x68, 0x62,
0x17, 0xb4, 0x92, 0xf1, 0x32, 0x4e, 0x38, 0x4b, 0x75, 0xd5, 0x90, 0xcc, 0x26, 0x3d, 0x1a, 0xbd,
0x02, 0x64, 0xf1, 0xf7, 0x16, 0xae, 0x43, 0xef, 0xd5, 0xf3, 0x67, 0x5e, 0xe4, 0x8c, 0xfd, 0x17,
0x37, 0xa2, 0x8e, 0xfd, 0x1c, 0xb8, 0xbe, 0x17, 0x05, 0xf3, 0x89, 0x43, 0x4e, 0xb0, 0x09, 0xf2,
0xc8, 0x7f, 0x73, 0x88, 0x84, 0x6d, 0xd0, 0x82, 0x61, 0x38, 0x7e, 0x9a, 0x46, 0xe1, 0x84, 0xd4,
0xf0, 0x1c, 0x5a, 0x7b, 0xd9, 0xf7, 0x67, 0x1e, 0xa9, 0xa3, 0x06, 0xca, 0xc8, 0x0e, 0x07, 0x43,
0x22, 0x63, 0x03, 0xea, 0x53, 0xbb, 0x4f, 0x94, 0xca, 0xb3, 0xbd, 0x01, 0x9d, 0x13, 0x75, 0xa1,
0x8a, 0xc9, 0x0f, 0x7f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x03, 0x65, 0x6e, 0x92, 0x91, 0x01, 0x00,
0x00,
}

View File

@ -30,9 +30,7 @@ message EmojiReaction {
SAD = 5;
ANGRY = 6;
}
}
message EmojiReactionRetraction {
uint64 clock = 1;
string emoji_reaction_id = 2;
// whether this is a rectraction of a previously sent emoji
bool retracted = 6;
}

View File

@ -240,9 +240,7 @@ func init() {
proto.RegisterType((*MembershipUpdateMessage)(nil), "protobuf.MembershipUpdateMessage")
}
func init() {
proto.RegisterFile("membership_update_message.proto", fileDescriptor_8d37dd0dc857a6be)
}
func init() { proto.RegisterFile("membership_update_message.proto", fileDescriptor_8d37dd0dc857a6be) }
var fileDescriptor_8d37dd0dc857a6be = []byte{
// 393 bytes of a gzipped FileDescriptorProto

View File

@ -232,8 +232,6 @@ func (m *StatusMessage) HandleApplication() error {
return m.unmarshalProtobufData(new(protobuf.PushNotificationResponse))
case protobuf.ApplicationMetadataMessage_EMOJI_REACTION:
return m.unmarshalProtobufData(new(protobuf.EmojiReaction))
case protobuf.ApplicationMetadataMessage_EMOJI_REACTION_RETRACTION:
return m.unmarshalProtobufData(new(protobuf.EmojiReactionRetraction))
case protobuf.ApplicationMetadataMessage_PUSH_NOTIFICATION_REGISTRATION:
// This message is a bit different as it's encrypted, so we pass it straight through
v := reflect.ValueOf(m.DecryptedPayload)

View File

@ -17,6 +17,7 @@ import (
"github.com/status-im/status-go/mailserver"
"github.com/status-im/status-go/protocol"
"github.com/status-im/status-go/protocol/encryption/multidevice"
"github.com/status-im/status-go/protocol/protobuf"
"github.com/status-im/status-go/protocol/pushnotificationclient"
"github.com/status-im/status-go/protocol/transport"
"github.com/status-im/status-go/services/ext/mailservers"
@ -511,6 +512,16 @@ func (api *PublicAPI) RegisteredForPushNotifications() (bool, error) {
return api.service.messenger.RegisteredForPushNotifications()
}
// Emoji
func (api *PublicAPI) SendEmojiReaction(ctx context.Context, chatID, messageID string, emojiID protobuf.EmojiReaction_Type) (*protocol.MessengerResponse, error) {
return api.service.messenger.SendEmojiReaction(ctx, chatID, messageID, emojiID)
}
func (api *PublicAPI) SendEmojiReactionRetraction(ctx context.Context, emojiReactionID string) (*protocol.MessengerResponse, error) {
return api.service.messenger.SendEmojiReactionRetraction(ctx, emojiReactionID)
}
// Echo is a method for testing purposes.
func (api *PublicAPI) Echo(ctx context.Context, message string) (string, error) {
return message, nil