Add basic support for incoming reactions
This commit is contained in:
parent
e1603932aa
commit
376f908a03
12 changed files with 404 additions and 234 deletions
|
@ -32,6 +32,7 @@ type Database struct {
|
||||||
Portal *PortalQuery
|
Portal *PortalQuery
|
||||||
Puppet *PuppetQuery
|
Puppet *PuppetQuery
|
||||||
Message *MessageQuery
|
Message *MessageQuery
|
||||||
|
Reaction *ReactionQuery
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(baseDB *dbutil.Database) *Database {
|
func New(baseDB *dbutil.Database) *Database {
|
||||||
|
@ -41,6 +42,7 @@ func New(baseDB *dbutil.Database) *Database {
|
||||||
db.Portal = &PortalQuery{db: db}
|
db.Portal = &PortalQuery{db: db}
|
||||||
db.Puppet = &PuppetQuery{db: db}
|
db.Puppet = &PuppetQuery{db: db}
|
||||||
db.Message = &MessageQuery{db: db}
|
db.Message = &MessageQuery{db: db}
|
||||||
|
db.Reaction = &ReactionQuery{db: db}
|
||||||
return db
|
return db
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,11 +24,10 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
log "maunium.net/go/maulogger/v2"
|
|
||||||
|
|
||||||
"go.mau.fi/mautrix-gmessages/libgm/binary"
|
|
||||||
"maunium.net/go/mautrix/id"
|
"maunium.net/go/mautrix/id"
|
||||||
"maunium.net/go/mautrix/util/dbutil"
|
"maunium.net/go/mautrix/util/dbutil"
|
||||||
|
|
||||||
|
"go.mau.fi/mautrix-gmessages/libgm/binary"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MessageQuery struct {
|
type MessageQuery struct {
|
||||||
|
@ -79,7 +78,6 @@ type MessageStatus struct {
|
||||||
|
|
||||||
type Message struct {
|
type Message struct {
|
||||||
db *Database
|
db *Database
|
||||||
log log.Logger
|
|
||||||
|
|
||||||
Chat Key
|
Chat Key
|
||||||
ID string
|
ID string
|
||||||
|
|
127
database/reaction.go
Normal file
127
database/reaction.go
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
// mautrix-gmessages - A Matrix-Google Messages puppeting bridge.
|
||||||
|
// Copyright (C) 2023 Tulir Asokan
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"maunium.net/go/mautrix/id"
|
||||||
|
"maunium.net/go/mautrix/util/dbutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ReactionQuery struct {
|
||||||
|
db *Database
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rq *ReactionQuery) New() *Reaction {
|
||||||
|
return &Reaction{
|
||||||
|
db: rq.db,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rq *ReactionQuery) getDB() *Database {
|
||||||
|
return rq.db
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
getReactionByIDQuery = `
|
||||||
|
SELECT conv_id, conv_receiver, msg_id, sender, reaction, mxid FROM reaction
|
||||||
|
WHERE conv_id=$1 AND conv_receiver=$2 AND msg_id=$3 AND sender=$4
|
||||||
|
`
|
||||||
|
getReactionByMXIDQuery = `
|
||||||
|
SELECT conv_id, conv_receiver, msg_id, sender, reaction, mxid FROM reaction
|
||||||
|
WHERE mxid=$1
|
||||||
|
`
|
||||||
|
getReactionsByMessageIDQuery = `
|
||||||
|
SELECT conv_id, conv_receiver, msg_id, sender, reaction, mxid FROM reaction
|
||||||
|
WHERE conv_id=$1 AND conv_receiver=$2 AND msg_id=$3
|
||||||
|
`
|
||||||
|
insertReaction = `
|
||||||
|
INSERT INTO reaction (conv_id, conv_receiver, msg_id, sender, reaction, mxid)
|
||||||
|
VALUES ($1, $2, $3, $4, $5, $6)
|
||||||
|
ON CONFLICT (conv_id, conv_receiver, msg_id, sender)
|
||||||
|
DO UPDATE SET reaction=excluded.reaction, mxid=excluded.mxid
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
|
func (rq *ReactionQuery) GetByID(ctx context.Context, chat Key, messageID, sender string) (*Reaction, error) {
|
||||||
|
return get[*Reaction](rq, ctx, getReactionByIDQuery, chat.ID, chat.Receiver, messageID, sender)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rq *ReactionQuery) GetByMXID(ctx context.Context, mxid id.EventID) (*Reaction, error) {
|
||||||
|
return get[*Reaction](rq, ctx, getReactionByMXIDQuery, mxid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rq *ReactionQuery) GetAllByMessage(ctx context.Context, chat Key, messageID string) ([]*Reaction, error) {
|
||||||
|
return getAll[*Reaction](rq, ctx, getReactionsByMessageIDQuery, chat.ID, chat.Receiver, messageID)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Reaction struct {
|
||||||
|
db *Database
|
||||||
|
|
||||||
|
Chat Key
|
||||||
|
MessageID string
|
||||||
|
Sender string
|
||||||
|
Reaction string
|
||||||
|
MXID id.EventID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Reaction) Scan(row dbutil.Scannable) (*Reaction, error) {
|
||||||
|
err := row.Scan(&r.Chat.ID, &r.Chat.Receiver, &r.MessageID, &r.Sender, &r.Reaction, &r.MXID)
|
||||||
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return nil, nil
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Reaction) Insert(ctx context.Context) error {
|
||||||
|
_, err := r.db.Conn(ctx).ExecContext(ctx, insertReaction, r.Chat.ID, r.Chat.Receiver, r.MessageID, r.Sender, r.Reaction, r.MXID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rq *ReactionQuery) MassInsert(ctx context.Context, reactions []*Reaction) error {
|
||||||
|
valueStringFormat := "($1, $2, $%d, $%d, $%d, $%d)"
|
||||||
|
if rq.db.Dialect == dbutil.SQLite {
|
||||||
|
valueStringFormat = strings.ReplaceAll(valueStringFormat, "$", "?")
|
||||||
|
}
|
||||||
|
placeholders := make([]string, len(reactions))
|
||||||
|
params := make([]any, 2+len(reactions)*4)
|
||||||
|
params[0] = reactions[0].Chat.ID
|
||||||
|
params[1] = reactions[0].Chat.Receiver
|
||||||
|
for i, msg := range reactions {
|
||||||
|
baseIndex := 2 + i*4
|
||||||
|
params[baseIndex] = msg.MessageID
|
||||||
|
params[baseIndex+1] = msg.Sender
|
||||||
|
params[baseIndex+2] = msg.Reaction
|
||||||
|
params[baseIndex+3] = msg.MXID
|
||||||
|
placeholders[i] = fmt.Sprintf(valueStringFormat, baseIndex+1, baseIndex+2, baseIndex+3, baseIndex+4)
|
||||||
|
}
|
||||||
|
query := strings.Replace(insertReaction, "($1, $2, $3, $4, $5, $6)", strings.Join(placeholders, ","), 1)
|
||||||
|
_, err := rq.db.Conn(ctx).ExecContext(ctx, query, params...)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Reaction) Delete(ctx context.Context) error {
|
||||||
|
_, err := r.db.Conn(ctx).ExecContext(ctx, "DELETE FROM reaction WHERE conv_id=$1 AND conv_receiver=$2 AND msg_id=$3 AND sender=$4", r.Chat.ID, r.Chat.Receiver, r.MessageID, r.Sender)
|
||||||
|
return err
|
||||||
|
}
|
|
@ -55,11 +55,25 @@ CREATE TABLE message (
|
||||||
conv_id TEXT NOT NULL,
|
conv_id TEXT NOT NULL,
|
||||||
conv_receiver BIGINT NOT NULL,
|
conv_receiver BIGINT NOT NULL,
|
||||||
id TEXT NOT NULL,
|
id TEXT NOT NULL,
|
||||||
mxid TEXT NOT NULL UNIQUE,
|
mxid TEXT NOT NULL,
|
||||||
sender TEXT NOT NULL,
|
sender TEXT NOT NULL,
|
||||||
timestamp BIGINT NOT NULL,
|
timestamp BIGINT NOT NULL,
|
||||||
status jsonb NOT NULL,
|
status jsonb NOT NULL,
|
||||||
|
|
||||||
PRIMARY KEY (conv_id, conv_receiver, id),
|
PRIMARY KEY (conv_id, conv_receiver, id),
|
||||||
CONSTRAINT message_portal_fkey FOREIGN KEY (conv_id, conv_receiver) REFERENCES portal(id, receiver) ON DELETE CASCADE
|
CONSTRAINT message_portal_fkey FOREIGN KEY (conv_id, conv_receiver) REFERENCES portal(id, receiver) ON DELETE CASCADE,
|
||||||
|
CONSTRAINT message_mxid_unique UNIQUE (mxid)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE reaction (
|
||||||
|
conv_id TEXT NOT NULL,
|
||||||
|
conv_receiver BIGINT NOT NULL,
|
||||||
|
msg_id TEXT NOT NULL,
|
||||||
|
sender TEXT NOT NULL,
|
||||||
|
reaction TEXT NOT NULL,
|
||||||
|
mxid TEXT NOT NULL,
|
||||||
|
|
||||||
|
PRIMARY KEY (conv_id, conv_receiver, msg_id, sender),
|
||||||
|
CONSTRAINT reaction_message_fkey FOREIGN KEY (conv_id, conv_receiver, msg_id) REFERENCES message(conv_id, conv_receiver, id) ON DELETE CASCADE,
|
||||||
|
CONSTRAINT reaction_mxid_unique UNIQUE (mxid)
|
||||||
|
)
|
||||||
|
|
|
@ -21,3 +21,61 @@ func DecodeProtoMessage(data []byte, message proto.Message) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (et EmojiType) Unicode() string {
|
||||||
|
switch et {
|
||||||
|
case EmojiType_LIKE:
|
||||||
|
return "👍"
|
||||||
|
case EmojiType_LOVE:
|
||||||
|
return "😍"
|
||||||
|
case EmojiType_LAUGH:
|
||||||
|
return "😂"
|
||||||
|
case EmojiType_SURPRISED:
|
||||||
|
return "😮"
|
||||||
|
case EmojiType_SAD:
|
||||||
|
return "😥"
|
||||||
|
case EmojiType_ANGRY:
|
||||||
|
return "😠"
|
||||||
|
case EmojiType_DISLIKE:
|
||||||
|
return "👎"
|
||||||
|
case EmojiType_QUESTIONING:
|
||||||
|
return "🤔"
|
||||||
|
case EmojiType_CRYING_FACE:
|
||||||
|
return "😢"
|
||||||
|
case EmojiType_POUTING_FACE:
|
||||||
|
return "😡"
|
||||||
|
case EmojiType_RED_HEART:
|
||||||
|
return "❤️"
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func UnicodeToEmojiType(emoji string) EmojiType {
|
||||||
|
switch emoji {
|
||||||
|
case "👍":
|
||||||
|
return EmojiType_LIKE
|
||||||
|
case "😍":
|
||||||
|
return EmojiType_LOVE
|
||||||
|
case "😂":
|
||||||
|
return EmojiType_LAUGH
|
||||||
|
case "😮":
|
||||||
|
return EmojiType_SURPRISED
|
||||||
|
case "😥":
|
||||||
|
return EmojiType_SAD
|
||||||
|
case "😠":
|
||||||
|
return EmojiType_ANGRY
|
||||||
|
case "👎":
|
||||||
|
return EmojiType_DISLIKE
|
||||||
|
case "🤔":
|
||||||
|
return EmojiType_QUESTIONING
|
||||||
|
case "😢":
|
||||||
|
return EmojiType_CRYING_FACE
|
||||||
|
case "😡":
|
||||||
|
return EmojiType_POUTING_FACE
|
||||||
|
case "❤", "❤️":
|
||||||
|
return EmojiType_RED_HEART
|
||||||
|
default:
|
||||||
|
return EmojiType_CUSTOM
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -21,13 +21,13 @@ message SendReactionResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
message ReactionData {
|
message ReactionData {
|
||||||
bytes emojiUnicode = 1;
|
string unicode = 1;
|
||||||
int64 emojiType = 2;
|
EmojiType type = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ReactionResponse {
|
message ReactionResponse {
|
||||||
ReactionData data = 1;
|
ReactionData data = 1;
|
||||||
repeated string reactorParticipantsID = 2; // participants reacted with this emoji
|
repeated string participantIDs = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message EmojiMeta {
|
message EmojiMeta {
|
||||||
|
@ -35,11 +35,11 @@ message EmojiMeta {
|
||||||
}
|
}
|
||||||
|
|
||||||
message EmojiMetaData {
|
message EmojiMetaData {
|
||||||
bytes emojiUnicode = 1;
|
string unicode = 1;
|
||||||
repeated string names = 2;
|
repeated string names = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Emojis {
|
enum EmojiType {
|
||||||
REACTION_TYPE_UNSPECIFIED = 0;
|
REACTION_TYPE_UNSPECIFIED = 0;
|
||||||
LIKE = 1;
|
LIKE = 1;
|
||||||
LOVE = 2;
|
LOVE = 2;
|
||||||
|
|
|
@ -72,27 +72,27 @@ func (Reaction) EnumDescriptor() ([]byte, []int) {
|
||||||
return file_reactions_proto_rawDescGZIP(), []int{0}
|
return file_reactions_proto_rawDescGZIP(), []int{0}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Emojis int32
|
type EmojiType int32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Emojis_REACTION_TYPE_UNSPECIFIED Emojis = 0
|
EmojiType_REACTION_TYPE_UNSPECIFIED EmojiType = 0
|
||||||
Emojis_LIKE Emojis = 1
|
EmojiType_LIKE EmojiType = 1
|
||||||
Emojis_LOVE Emojis = 2
|
EmojiType_LOVE EmojiType = 2
|
||||||
Emojis_LAUGH Emojis = 3
|
EmojiType_LAUGH EmojiType = 3
|
||||||
Emojis_SURPRISED Emojis = 4
|
EmojiType_SURPRISED EmojiType = 4
|
||||||
Emojis_SAD Emojis = 5
|
EmojiType_SAD EmojiType = 5
|
||||||
Emojis_ANGRY Emojis = 6
|
EmojiType_ANGRY EmojiType = 6
|
||||||
Emojis_DISLIKE Emojis = 7
|
EmojiType_DISLIKE EmojiType = 7
|
||||||
Emojis_CUSTOM Emojis = 8
|
EmojiType_CUSTOM EmojiType = 8
|
||||||
Emojis_QUESTIONING Emojis = 9
|
EmojiType_QUESTIONING EmojiType = 9
|
||||||
Emojis_CRYING_FACE Emojis = 10
|
EmojiType_CRYING_FACE EmojiType = 10
|
||||||
Emojis_POUTING_FACE Emojis = 11
|
EmojiType_POUTING_FACE EmojiType = 11
|
||||||
Emojis_RED_HEART Emojis = 12
|
EmojiType_RED_HEART EmojiType = 12
|
||||||
)
|
)
|
||||||
|
|
||||||
// Enum value maps for Emojis.
|
// Enum value maps for EmojiType.
|
||||||
var (
|
var (
|
||||||
Emojis_name = map[int32]string{
|
EmojiType_name = map[int32]string{
|
||||||
0: "REACTION_TYPE_UNSPECIFIED",
|
0: "REACTION_TYPE_UNSPECIFIED",
|
||||||
1: "LIKE",
|
1: "LIKE",
|
||||||
2: "LOVE",
|
2: "LOVE",
|
||||||
|
@ -107,7 +107,7 @@ var (
|
||||||
11: "POUTING_FACE",
|
11: "POUTING_FACE",
|
||||||
12: "RED_HEART",
|
12: "RED_HEART",
|
||||||
}
|
}
|
||||||
Emojis_value = map[string]int32{
|
EmojiType_value = map[string]int32{
|
||||||
"REACTION_TYPE_UNSPECIFIED": 0,
|
"REACTION_TYPE_UNSPECIFIED": 0,
|
||||||
"LIKE": 1,
|
"LIKE": 1,
|
||||||
"LOVE": 2,
|
"LOVE": 2,
|
||||||
|
@ -124,30 +124,30 @@ var (
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func (x Emojis) Enum() *Emojis {
|
func (x EmojiType) Enum() *EmojiType {
|
||||||
p := new(Emojis)
|
p := new(EmojiType)
|
||||||
*p = x
|
*p = x
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x Emojis) String() string {
|
func (x EmojiType) String() string {
|
||||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Emojis) Descriptor() protoreflect.EnumDescriptor {
|
func (EmojiType) Descriptor() protoreflect.EnumDescriptor {
|
||||||
return file_reactions_proto_enumTypes[1].Descriptor()
|
return file_reactions_proto_enumTypes[1].Descriptor()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (Emojis) Type() protoreflect.EnumType {
|
func (EmojiType) Type() protoreflect.EnumType {
|
||||||
return &file_reactions_proto_enumTypes[1]
|
return &file_reactions_proto_enumTypes[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x Emojis) Number() protoreflect.EnumNumber {
|
func (x EmojiType) Number() protoreflect.EnumNumber {
|
||||||
return protoreflect.EnumNumber(x)
|
return protoreflect.EnumNumber(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated: Use Emojis.Descriptor instead.
|
// Deprecated: Use EmojiType.Descriptor instead.
|
||||||
func (Emojis) EnumDescriptor() ([]byte, []int) {
|
func (EmojiType) EnumDescriptor() ([]byte, []int) {
|
||||||
return file_reactions_proto_rawDescGZIP(), []int{1}
|
return file_reactions_proto_rawDescGZIP(), []int{1}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,8 +266,8 @@ type ReactionData struct {
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
EmojiUnicode []byte `protobuf:"bytes,1,opt,name=emojiUnicode,proto3" json:"emojiUnicode,omitempty"`
|
Unicode string `protobuf:"bytes,1,opt,name=unicode,proto3" json:"unicode,omitempty"`
|
||||||
EmojiType int64 `protobuf:"varint,2,opt,name=emojiType,proto3" json:"emojiType,omitempty"`
|
Type EmojiType `protobuf:"varint,2,opt,name=type,proto3,enum=reactions.EmojiType" json:"type,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ReactionData) Reset() {
|
func (x *ReactionData) Reset() {
|
||||||
|
@ -302,18 +302,18 @@ func (*ReactionData) Descriptor() ([]byte, []int) {
|
||||||
return file_reactions_proto_rawDescGZIP(), []int{2}
|
return file_reactions_proto_rawDescGZIP(), []int{2}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ReactionData) GetEmojiUnicode() []byte {
|
func (x *ReactionData) GetUnicode() string {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.EmojiUnicode
|
return x.Unicode
|
||||||
}
|
}
|
||||||
return nil
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ReactionData) GetEmojiType() int64 {
|
func (x *ReactionData) GetType() EmojiType {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.EmojiType
|
return x.Type
|
||||||
}
|
}
|
||||||
return 0
|
return EmojiType_REACTION_TYPE_UNSPECIFIED
|
||||||
}
|
}
|
||||||
|
|
||||||
type ReactionResponse struct {
|
type ReactionResponse struct {
|
||||||
|
@ -322,7 +322,7 @@ type ReactionResponse struct {
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
Data *ReactionData `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
|
Data *ReactionData `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
|
||||||
ReactorParticipantsID []string `protobuf:"bytes,2,rep,name=reactorParticipantsID,proto3" json:"reactorParticipantsID,omitempty"` // participants reacted with this emoji
|
ParticipantIDs []string `protobuf:"bytes,2,rep,name=participantIDs,proto3" json:"participantIDs,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ReactionResponse) Reset() {
|
func (x *ReactionResponse) Reset() {
|
||||||
|
@ -364,9 +364,9 @@ func (x *ReactionResponse) GetData() *ReactionData {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ReactionResponse) GetReactorParticipantsID() []string {
|
func (x *ReactionResponse) GetParticipantIDs() []string {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.ReactorParticipantsID
|
return x.ParticipantIDs
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -423,7 +423,7 @@ type EmojiMetaData struct {
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
EmojiUnicode []byte `protobuf:"bytes,1,opt,name=emojiUnicode,proto3" json:"emojiUnicode,omitempty"`
|
Unicode string `protobuf:"bytes,1,opt,name=unicode,proto3" json:"unicode,omitempty"`
|
||||||
Names []string `protobuf:"bytes,2,rep,name=names,proto3" json:"names,omitempty"`
|
Names []string `protobuf:"bytes,2,rep,name=names,proto3" json:"names,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -459,11 +459,11 @@ func (*EmojiMetaData) Descriptor() ([]byte, []int) {
|
||||||
return file_reactions_proto_rawDescGZIP(), []int{5}
|
return file_reactions_proto_rawDescGZIP(), []int{5}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *EmojiMetaData) GetEmojiUnicode() []byte {
|
func (x *EmojiMetaData) GetUnicode() string {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.EmojiUnicode
|
return x.Unicode
|
||||||
}
|
}
|
||||||
return nil
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *EmojiMetaData) GetNames() []string {
|
func (x *EmojiMetaData) GetNames() []string {
|
||||||
|
@ -490,47 +490,46 @@ var file_reactions_proto_rawDesc = []byte{
|
||||||
0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x30, 0x0a, 0x14,
|
0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x30, 0x0a, 0x14,
|
||||||
0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70,
|
0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70,
|
||||||
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18,
|
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18,
|
||||||
0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x50,
|
0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0x52,
|
||||||
0x0a, 0x0c, 0x52, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x12, 0x22,
|
0x0a, 0x0c, 0x52, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x12, 0x18,
|
||||||
0x0a, 0x0c, 0x65, 0x6d, 0x6f, 0x6a, 0x69, 0x55, 0x6e, 0x69, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01,
|
0x0a, 0x07, 0x75, 0x6e, 0x69, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||||
0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x65, 0x6d, 0x6f, 0x6a, 0x69, 0x55, 0x6e, 0x69, 0x63, 0x6f,
|
0x07, 0x75, 0x6e, 0x69, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x28, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65,
|
||||||
0x64, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x6d, 0x6f, 0x6a, 0x69, 0x54, 0x79, 0x70, 0x65, 0x18,
|
0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x72, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f,
|
||||||
0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x65, 0x6d, 0x6f, 0x6a, 0x69, 0x54, 0x79, 0x70, 0x65,
|
0x6e, 0x73, 0x2e, 0x45, 0x6d, 0x6f, 0x6a, 0x69, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79,
|
||||||
0x22, 0x75, 0x0a, 0x10, 0x52, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70,
|
0x70, 0x65, 0x22, 0x67, 0x0a, 0x10, 0x52, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65,
|
||||||
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01,
|
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01,
|
||||||
0x28, 0x0b, 0x32, 0x17, 0x2e, 0x72, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x52,
|
0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x72, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73,
|
||||||
0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x04, 0x64, 0x61, 0x74,
|
0x2e, 0x52, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x04, 0x64,
|
||||||
0x61, 0x12, 0x34, 0x0a, 0x15, 0x72, 0x65, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x50, 0x61, 0x72, 0x74,
|
0x61, 0x74, 0x61, 0x12, 0x26, 0x0a, 0x0e, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61,
|
||||||
0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, 0x49, 0x44, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09,
|
0x6e, 0x74, 0x49, 0x44, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0e, 0x70, 0x61, 0x72,
|
||||||
0x52, 0x15, 0x72, 0x65, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69,
|
0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x49, 0x44, 0x73, 0x22, 0x4b, 0x0a, 0x09, 0x45,
|
||||||
0x70, 0x61, 0x6e, 0x74, 0x73, 0x49, 0x44, 0x22, 0x4b, 0x0a, 0x09, 0x45, 0x6d, 0x6f, 0x6a, 0x69,
|
0x6d, 0x6f, 0x6a, 0x69, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x3e, 0x0a, 0x0d, 0x65, 0x6d, 0x6f, 0x6a,
|
||||||
0x4d, 0x65, 0x74, 0x61, 0x12, 0x3e, 0x0a, 0x0d, 0x65, 0x6d, 0x6f, 0x6a, 0x69, 0x4d, 0x65, 0x74,
|
0x69, 0x4d, 0x65, 0x74, 0x61, 0x44, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
||||||
0x61, 0x44, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x72, 0x65,
|
0x18, 0x2e, 0x72, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x45, 0x6d, 0x6f, 0x6a,
|
||||||
0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x45, 0x6d, 0x6f, 0x6a, 0x69, 0x4d, 0x65, 0x74,
|
0x69, 0x4d, 0x65, 0x74, 0x61, 0x44, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, 0x6d, 0x6f, 0x6a, 0x69,
|
||||||
0x61, 0x44, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x65, 0x6d, 0x6f, 0x6a, 0x69, 0x4d, 0x65, 0x74, 0x61,
|
0x4d, 0x65, 0x74, 0x61, 0x44, 0x61, 0x74, 0x61, 0x22, 0x3f, 0x0a, 0x0d, 0x45, 0x6d, 0x6f, 0x6a,
|
||||||
0x44, 0x61, 0x74, 0x61, 0x22, 0x49, 0x0a, 0x0d, 0x45, 0x6d, 0x6f, 0x6a, 0x69, 0x4d, 0x65, 0x74,
|
0x69, 0x4d, 0x65, 0x74, 0x61, 0x44, 0x61, 0x74, 0x61, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x6e, 0x69,
|
||||||
0x61, 0x44, 0x61, 0x74, 0x61, 0x12, 0x22, 0x0a, 0x0c, 0x65, 0x6d, 0x6f, 0x6a, 0x69, 0x55, 0x6e,
|
0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x75, 0x6e, 0x69, 0x63,
|
||||||
0x69, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x65, 0x6d, 0x6f,
|
0x6f, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03,
|
||||||
0x6a, 0x69, 0x55, 0x6e, 0x69, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6e, 0x61, 0x6d,
|
0x28, 0x09, 0x52, 0x05, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x2a, 0x3c, 0x0a, 0x08, 0x52, 0x65, 0x61,
|
||||||
0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x2a,
|
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49,
|
||||||
0x3c, 0x0a, 0x08, 0x52, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0f, 0x0a, 0x0b, 0x55,
|
0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x44, 0x44, 0x10, 0x01, 0x12,
|
||||||
0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03,
|
0x0a, 0x0a, 0x06, 0x52, 0x45, 0x4d, 0x4f, 0x56, 0x45, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x53,
|
||||||
0x41, 0x44, 0x44, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x45, 0x4d, 0x4f, 0x56, 0x45, 0x10,
|
0x57, 0x49, 0x54, 0x43, 0x48, 0x10, 0x03, 0x2a, 0xc8, 0x01, 0x0a, 0x09, 0x45, 0x6d, 0x6f, 0x6a,
|
||||||
0x02, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x57, 0x49, 0x54, 0x43, 0x48, 0x10, 0x03, 0x2a, 0xc5, 0x01,
|
0x69, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x19, 0x52, 0x45, 0x41, 0x43, 0x54, 0x49, 0x4f,
|
||||||
0x0a, 0x06, 0x45, 0x6d, 0x6f, 0x6a, 0x69, 0x73, 0x12, 0x1d, 0x0a, 0x19, 0x52, 0x45, 0x41, 0x43,
|
0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49,
|
||||||
0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43,
|
0x45, 0x44, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x4c, 0x49, 0x4b, 0x45, 0x10, 0x01, 0x12, 0x08,
|
||||||
0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x4c, 0x49, 0x4b, 0x45, 0x10,
|
0x0a, 0x04, 0x4c, 0x4f, 0x56, 0x45, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x4c, 0x41, 0x55, 0x47,
|
||||||
0x01, 0x12, 0x08, 0x0a, 0x04, 0x4c, 0x4f, 0x56, 0x45, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x4c,
|
0x48, 0x10, 0x03, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x55, 0x52, 0x50, 0x52, 0x49, 0x53, 0x45, 0x44,
|
||||||
0x41, 0x55, 0x47, 0x48, 0x10, 0x03, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x55, 0x52, 0x50, 0x52, 0x49,
|
0x10, 0x04, 0x12, 0x07, 0x0a, 0x03, 0x53, 0x41, 0x44, 0x10, 0x05, 0x12, 0x09, 0x0a, 0x05, 0x41,
|
||||||
0x53, 0x45, 0x44, 0x10, 0x04, 0x12, 0x07, 0x0a, 0x03, 0x53, 0x41, 0x44, 0x10, 0x05, 0x12, 0x09,
|
0x4e, 0x47, 0x52, 0x59, 0x10, 0x06, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x49, 0x53, 0x4c, 0x49, 0x4b,
|
||||||
0x0a, 0x05, 0x41, 0x4e, 0x47, 0x52, 0x59, 0x10, 0x06, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x49, 0x53,
|
0x45, 0x10, 0x07, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x55, 0x53, 0x54, 0x4f, 0x4d, 0x10, 0x08, 0x12,
|
||||||
0x4c, 0x49, 0x4b, 0x45, 0x10, 0x07, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x55, 0x53, 0x54, 0x4f, 0x4d,
|
0x0f, 0x0a, 0x0b, 0x51, 0x55, 0x45, 0x53, 0x54, 0x49, 0x4f, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x09,
|
||||||
0x10, 0x08, 0x12, 0x0f, 0x0a, 0x0b, 0x51, 0x55, 0x45, 0x53, 0x54, 0x49, 0x4f, 0x4e, 0x49, 0x4e,
|
0x12, 0x0f, 0x0a, 0x0b, 0x43, 0x52, 0x59, 0x49, 0x4e, 0x47, 0x5f, 0x46, 0x41, 0x43, 0x45, 0x10,
|
||||||
0x47, 0x10, 0x09, 0x12, 0x0f, 0x0a, 0x0b, 0x43, 0x52, 0x59, 0x49, 0x4e, 0x47, 0x5f, 0x46, 0x41,
|
0x0a, 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x4f, 0x55, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x46, 0x41, 0x43,
|
||||||
0x43, 0x45, 0x10, 0x0a, 0x12, 0x10, 0x0a, 0x0c, 0x50, 0x4f, 0x55, 0x54, 0x49, 0x4e, 0x47, 0x5f,
|
0x45, 0x10, 0x0b, 0x12, 0x0d, 0x0a, 0x09, 0x52, 0x45, 0x44, 0x5f, 0x48, 0x45, 0x41, 0x52, 0x54,
|
||||||
0x46, 0x41, 0x43, 0x45, 0x10, 0x0b, 0x12, 0x0d, 0x0a, 0x09, 0x52, 0x45, 0x44, 0x5f, 0x48, 0x45,
|
0x10, 0x0c, 0x42, 0x0e, 0x5a, 0x0c, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x62, 0x69, 0x6e, 0x61,
|
||||||
0x41, 0x52, 0x54, 0x10, 0x0c, 0x42, 0x0e, 0x5a, 0x0c, 0x2e, 0x2e, 0x2f, 0x2e, 0x2e, 0x2f, 0x62,
|
0x72, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
0x69, 0x6e, 0x61, 0x72, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -549,7 +548,7 @@ var file_reactions_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
|
||||||
var file_reactions_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
|
var file_reactions_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
|
||||||
var file_reactions_proto_goTypes = []interface{}{
|
var file_reactions_proto_goTypes = []interface{}{
|
||||||
(Reaction)(0), // 0: reactions.Reaction
|
(Reaction)(0), // 0: reactions.Reaction
|
||||||
(Emojis)(0), // 1: reactions.Emojis
|
(EmojiType)(0), // 1: reactions.EmojiType
|
||||||
(*SendReactionPayload)(nil), // 2: reactions.SendReactionPayload
|
(*SendReactionPayload)(nil), // 2: reactions.SendReactionPayload
|
||||||
(*SendReactionResponse)(nil), // 3: reactions.SendReactionResponse
|
(*SendReactionResponse)(nil), // 3: reactions.SendReactionResponse
|
||||||
(*ReactionData)(nil), // 4: reactions.ReactionData
|
(*ReactionData)(nil), // 4: reactions.ReactionData
|
||||||
|
@ -560,13 +559,14 @@ var file_reactions_proto_goTypes = []interface{}{
|
||||||
var file_reactions_proto_depIdxs = []int32{
|
var file_reactions_proto_depIdxs = []int32{
|
||||||
4, // 0: reactions.SendReactionPayload.reactionData:type_name -> reactions.ReactionData
|
4, // 0: reactions.SendReactionPayload.reactionData:type_name -> reactions.ReactionData
|
||||||
0, // 1: reactions.SendReactionPayload.action:type_name -> reactions.Reaction
|
0, // 1: reactions.SendReactionPayload.action:type_name -> reactions.Reaction
|
||||||
4, // 2: reactions.ReactionResponse.data:type_name -> reactions.ReactionData
|
1, // 2: reactions.ReactionData.type:type_name -> reactions.EmojiType
|
||||||
7, // 3: reactions.EmojiMeta.emojiMetaData:type_name -> reactions.EmojiMetaData
|
4, // 3: reactions.ReactionResponse.data:type_name -> reactions.ReactionData
|
||||||
4, // [4:4] is the sub-list for method output_type
|
7, // 4: reactions.EmojiMeta.emojiMetaData:type_name -> reactions.EmojiMetaData
|
||||||
4, // [4:4] is the sub-list for method input_type
|
5, // [5:5] is the sub-list for method output_type
|
||||||
4, // [4:4] is the sub-list for extension type_name
|
5, // [5:5] is the sub-list for method input_type
|
||||||
4, // [4:4] is the sub-list for extension extendee
|
5, // [5:5] is the sub-list for extension type_name
|
||||||
0, // [0:4] is the sub-list for field type_name
|
5, // [5:5] is the sub-list for extension extendee
|
||||||
|
0, // [0:5] is the sub-list for field type_name
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_reactions_proto_init() }
|
func init() { file_reactions_proto_init() }
|
||||||
|
|
|
@ -10,12 +10,7 @@ type Messages struct {
|
||||||
client *Client
|
client *Client
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Messages) React(reactionBuilder *ReactionBuilder) (*binary.SendReactionResponse, error) {
|
func (m *Messages) React(payload *binary.SendReactionPayload) (*binary.SendReactionResponse, error) {
|
||||||
payload, buildErr := reactionBuilder.Build()
|
|
||||||
if buildErr != nil {
|
|
||||||
return nil, buildErr
|
|
||||||
}
|
|
||||||
|
|
||||||
actionType := binary.ActionType_SEND_REACTION
|
actionType := binary.ActionType_SEND_REACTION
|
||||||
|
|
||||||
sentRequestId, sendErr := m.client.sessionHandler.completeSendMessage(actionType, true, payload)
|
sentRequestId, sendErr := m.client.sessionHandler.completeSendMessage(actionType, true, payload)
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
package metadata
|
|
||||||
|
|
||||||
var Emojis = map[string]int64{
|
|
||||||
"\U0001F44D": 1, // 👍
|
|
||||||
"\U0001F60D": 2, // 😍
|
|
||||||
"\U0001F602": 3, // 😂
|
|
||||||
"\U0001F62E": 4, // 😮
|
|
||||||
"\U0001F625": 5, // 😥
|
|
||||||
"\U0001F622": 10, // 😢
|
|
||||||
"\U0001F620": 6, // 😠
|
|
||||||
"\U0001F621": 11, // 😡
|
|
||||||
"\U0001F44E": 7, // 👎
|
|
||||||
"\U00002764": 12, // ❤️
|
|
||||||
}
|
|
|
@ -1,88 +0,0 @@
|
||||||
package libgm
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"go.mau.fi/mautrix-gmessages/libgm/binary"
|
|
||||||
"go.mau.fi/mautrix-gmessages/libgm/metadata"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ReactionBuilderError struct {
|
|
||||||
errMsg string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rbe *ReactionBuilderError) Error() string {
|
|
||||||
return fmt.Sprintf("Failed to build reaction builder: %s", rbe.errMsg)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ReactionBuilder struct {
|
|
||||||
messageID string
|
|
||||||
emoji []byte
|
|
||||||
action binary.Reaction
|
|
||||||
|
|
||||||
emojiType int64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rb *ReactionBuilder) SetAction(action binary.Reaction) *ReactionBuilder {
|
|
||||||
rb.action = action
|
|
||||||
return rb
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Emoji is a unicode string like "\U0001F44D" or a string like "👍"
|
|
||||||
*/
|
|
||||||
func (rb *ReactionBuilder) SetEmoji(emoji string) *ReactionBuilder {
|
|
||||||
emojiType, exists := metadata.Emojis[emoji]
|
|
||||||
if exists {
|
|
||||||
rb.emojiType = emojiType
|
|
||||||
} else {
|
|
||||||
rb.emojiType = 8
|
|
||||||
}
|
|
||||||
|
|
||||||
rb.emoji = []byte(emoji)
|
|
||||||
return rb
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rb *ReactionBuilder) SetMessageID(messageId string) *ReactionBuilder {
|
|
||||||
rb.messageID = messageId
|
|
||||||
return rb
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rb *ReactionBuilder) Build() (*binary.SendReactionPayload, error) {
|
|
||||||
if rb.messageID == "" {
|
|
||||||
return nil, &ReactionBuilderError{
|
|
||||||
errMsg: "messageID can not be empty",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if rb.action == 0 {
|
|
||||||
return nil, &ReactionBuilderError{
|
|
||||||
errMsg: "action can not be empty",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if rb.emojiType == 0 {
|
|
||||||
return nil, &ReactionBuilderError{
|
|
||||||
errMsg: "failed to set emojiType",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if rb.emoji == nil {
|
|
||||||
return nil, &ReactionBuilderError{
|
|
||||||
errMsg: "failed to set emoji",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &binary.SendReactionPayload{
|
|
||||||
MessageID: rb.messageID,
|
|
||||||
ReactionData: &binary.ReactionData{
|
|
||||||
EmojiUnicode: rb.emoji,
|
|
||||||
EmojiType: rb.emojiType,
|
|
||||||
},
|
|
||||||
Action: rb.action,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) NewReactionBuilder() *ReactionBuilder {
|
|
||||||
return &ReactionBuilder{}
|
|
||||||
}
|
|
109
portal.go
109
portal.go
|
@ -30,6 +30,7 @@ import (
|
||||||
"github.com/gabriel-vasile/mimetype"
|
"github.com/gabriel-vasile/mimetype"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"maunium.net/go/maulogger/v2"
|
"maunium.net/go/maulogger/v2"
|
||||||
|
"maunium.net/go/mautrix/util/variationselector"
|
||||||
|
|
||||||
"maunium.net/go/mautrix"
|
"maunium.net/go/mautrix"
|
||||||
"maunium.net/go/mautrix/appservice"
|
"maunium.net/go/mautrix/appservice"
|
||||||
|
@ -358,7 +359,9 @@ func (portal *Portal) handleMessage(source *User, evt *binary.Message) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
eventTS := time.UnixMicro(evt.GetTimestamp())
|
eventTS := time.UnixMicro(evt.GetTimestamp())
|
||||||
|
if eventTS.After(portal.lastMessageTS) {
|
||||||
portal.lastMessageTS = eventTS
|
portal.lastMessageTS = eventTS
|
||||||
|
}
|
||||||
log := portal.zlog.With().
|
log := portal.zlog.With().
|
||||||
Str("message_id", evt.MessageID).
|
Str("message_id", evt.MessageID).
|
||||||
Str("participant_id", evt.ParticipantID).
|
Str("participant_id", evt.ParticipantID).
|
||||||
|
@ -369,6 +372,9 @@ func (portal *Portal) handleMessage(source *User, evt *binary.Message) {
|
||||||
case binary.MessageStatusType_INCOMING_AUTO_DOWNLOADING, binary.MessageStatusType_INCOMING_RETRYING_AUTO_DOWNLOAD:
|
case binary.MessageStatusType_INCOMING_AUTO_DOWNLOADING, binary.MessageStatusType_INCOMING_RETRYING_AUTO_DOWNLOAD:
|
||||||
log.Debug().Msg("Not handling incoming message that is auto downloading")
|
log.Debug().Msg("Not handling incoming message that is auto downloading")
|
||||||
return
|
return
|
||||||
|
case binary.MessageStatusType_MESSAGE_DELETED:
|
||||||
|
// TODO handle deletion
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if hasInProgressMedia(evt) {
|
if hasInProgressMedia(evt) {
|
||||||
log.Debug().Msg("Not handling incoming message that doesn't have full media yet")
|
log.Debug().Msg("Not handling incoming message that doesn't have full media yet")
|
||||||
|
@ -377,15 +383,13 @@ func (portal *Portal) handleMessage(source *User, evt *binary.Message) {
|
||||||
if evtID := portal.isOutgoingMessage(evt); evtID != "" {
|
if evtID := portal.isOutgoingMessage(evt); evtID != "" {
|
||||||
log.Debug().Str("event_id", evtID.String()).Msg("Got echo for outgoing message")
|
log.Debug().Str("event_id", evtID.String()).Msg("Got echo for outgoing message")
|
||||||
return
|
return
|
||||||
} else if portal.isRecentlyHandled(evt.MessageID) {
|
|
||||||
log.Debug().Msg("Not handling recent duplicate message")
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
existingMsg, err := portal.bridge.DB.Message.GetByID(ctx, portal.Key, evt.MessageID)
|
existingMsg, err := portal.bridge.DB.Message.GetByID(ctx, portal.Key, evt.MessageID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Err(err).Msg("Failed to check if message is duplicate")
|
log.Err(err).Msg("Failed to check if message is duplicate")
|
||||||
} else if existingMsg != nil {
|
} else if existingMsg != nil {
|
||||||
log.Debug().Msg("Not handling duplicate message")
|
log.Debug().Msg("Not handling duplicate message")
|
||||||
|
portal.syncReactions(ctx, source, existingMsg, evt.Reactions)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -408,6 +412,73 @@ func (portal *Portal) handleMessage(source *User, evt *binary.Message) {
|
||||||
log.Debug().Interface("event_ids", eventIDs).Msg("Handled message")
|
log.Debug().Interface("event_ids", eventIDs).Msg("Handled message")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (portal *Portal) syncReactions(ctx context.Context, source *User, message *database.Message, reactions []*binary.ReactionResponse) {
|
||||||
|
log := zerolog.Ctx(ctx)
|
||||||
|
existing, err := portal.bridge.DB.Reaction.GetAllByMessage(ctx, portal.Key, message.ID)
|
||||||
|
if err != nil {
|
||||||
|
log.Err(err).Msg("Failed to get existing reactions from db to sync reactions")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
remove := make(map[string]*database.Reaction, len(existing))
|
||||||
|
for _, reaction := range existing {
|
||||||
|
remove[reaction.Sender] = reaction
|
||||||
|
}
|
||||||
|
for _, reaction := range reactions {
|
||||||
|
emoji := reaction.GetData().GetUnicode()
|
||||||
|
if emoji == "" {
|
||||||
|
emoji = reaction.GetData().GetType().Unicode()
|
||||||
|
if emoji == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, participant := range reaction.GetParticipantIDs() {
|
||||||
|
dbReaction, ok := remove[participant]
|
||||||
|
if ok {
|
||||||
|
delete(remove, participant)
|
||||||
|
if dbReaction.Reaction == emoji {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
intent := portal.getIntent(ctx, source, participant)
|
||||||
|
if intent == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var resp *mautrix.RespSendEvent
|
||||||
|
resp, err = intent.SendReaction(portal.MXID, message.MXID, variationselector.Add(emoji))
|
||||||
|
if err != nil {
|
||||||
|
log.Err(err).Str("reaction_sender_id", participant).Msg("Failed to send reaction")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if dbReaction == nil {
|
||||||
|
dbReaction = portal.bridge.DB.Reaction.New()
|
||||||
|
dbReaction.Chat = portal.Key
|
||||||
|
dbReaction.Sender = participant
|
||||||
|
dbReaction.MessageID = message.ID
|
||||||
|
} else if _, err = intent.RedactEvent(portal.MXID, dbReaction.MXID); err != nil {
|
||||||
|
log.Err(err).Str("reaction_sender_id", participant).Msg("Failed to redact old reaction after adding new one")
|
||||||
|
}
|
||||||
|
dbReaction.Reaction = emoji
|
||||||
|
dbReaction.MXID = resp.EventID
|
||||||
|
err = dbReaction.Insert(ctx)
|
||||||
|
if err != nil {
|
||||||
|
log.Err(err).Str("reaction_sender_id", participant).Msg("Failed to insert added reaction into db")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, reaction := range remove {
|
||||||
|
intent := portal.getIntent(ctx, source, reaction.Sender)
|
||||||
|
if intent == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
_, err = intent.RedactEvent(portal.MXID, reaction.MXID)
|
||||||
|
if err != nil {
|
||||||
|
log.Err(err).Str("reaction_sender_id", reaction.Sender).Msg("Failed to redact removed reaction")
|
||||||
|
} else if err = reaction.Delete(ctx); err != nil {
|
||||||
|
log.Err(err).Str("reaction_sender_id", reaction.Sender).Msg("Failed to remove reaction from db")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type ConvertedMessagePart struct {
|
type ConvertedMessagePart struct {
|
||||||
Content *event.MessageEventContent
|
Content *event.MessageEventContent
|
||||||
Extra map[string]any
|
Extra map[string]any
|
||||||
|
@ -423,6 +494,24 @@ type ConvertedMessage struct {
|
||||||
Parts []ConvertedMessagePart
|
Parts []ConvertedMessagePart
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (portal *Portal) getIntent(ctx context.Context, source *User, participant string) *appservice.IntentAPI {
|
||||||
|
if participant == portal.SelfUserID {
|
||||||
|
intent := source.DoublePuppetIntent
|
||||||
|
if intent == nil {
|
||||||
|
zerolog.Ctx(ctx).Debug().Msg("Dropping message from self as double puppeting is not enabled")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return intent
|
||||||
|
} else {
|
||||||
|
puppet := source.GetPuppetByID(participant, "")
|
||||||
|
if puppet == nil {
|
||||||
|
zerolog.Ctx(ctx).Debug().Str("participant_id", participant).Msg("Dropping message from unknown participant")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return puppet.IntentFor(portal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (portal *Portal) convertGoogleMessage(ctx context.Context, source *User, evt *binary.Message, backfill bool) *ConvertedMessage {
|
func (portal *Portal) convertGoogleMessage(ctx context.Context, source *User, evt *binary.Message, backfill bool) *ConvertedMessage {
|
||||||
log := zerolog.Ctx(ctx)
|
log := zerolog.Ctx(ctx)
|
||||||
|
|
||||||
|
@ -430,22 +519,10 @@ func (portal *Portal) convertGoogleMessage(ctx context.Context, source *User, ev
|
||||||
cm.SenderID = evt.ParticipantID
|
cm.SenderID = evt.ParticipantID
|
||||||
cm.ID = evt.MessageID
|
cm.ID = evt.MessageID
|
||||||
cm.Timestamp = time.UnixMicro(evt.Timestamp)
|
cm.Timestamp = time.UnixMicro(evt.Timestamp)
|
||||||
|
cm.Intent = portal.getIntent(ctx, source, evt.ParticipantID)
|
||||||
// TODO is there a fromMe flag?
|
|
||||||
if evt.GetParticipantID() == portal.SelfUserID {
|
|
||||||
cm.Intent = source.DoublePuppetIntent
|
|
||||||
if cm.Intent == nil {
|
if cm.Intent == nil {
|
||||||
log.Debug().Msg("Dropping message from self as double puppeting is not enabled")
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
puppet := source.GetPuppetByID(evt.ParticipantID, "")
|
|
||||||
if puppet == nil {
|
|
||||||
log.Debug().Str("participant_id", evt.ParticipantID).Msg("Dropping message from unknown participant")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
cm.Intent = puppet.IntentFor(portal)
|
|
||||||
}
|
|
||||||
|
|
||||||
var replyTo id.EventID
|
var replyTo id.EventID
|
||||||
if evt.GetReplyMessage() != nil {
|
if evt.GetReplyMessage() != nil {
|
||||||
|
|
1
user.go
1
user.go
|
@ -568,6 +568,7 @@ func (user *User) syncConversation(v *binary.Conversation) {
|
||||||
portal := user.GetPortalByID(v.GetConversationID())
|
portal := user.GetPortalByID(v.GetConversationID())
|
||||||
if portal.MXID != "" {
|
if portal.MXID != "" {
|
||||||
switch updateType {
|
switch updateType {
|
||||||
|
// TODO also delete if blocked?
|
||||||
case binary.ConvUpdateTypes_DELETED:
|
case binary.ConvUpdateTypes_DELETED:
|
||||||
user.zlog.Info().Str("conversation_id", portal.ID).Msg("Got delete event, cleaning up portal")
|
user.zlog.Info().Str("conversation_id", portal.ID).Msg("Got delete event, cleaning up portal")
|
||||||
portal.Delete()
|
portal.Delete()
|
||||||
|
|
Loading…
Reference in a new issue