From d23ab73cf96d55b80ea58164483b668c097e3272 Mon Sep 17 00:00:00 2001 From: ycc Date: Fri, 6 Mar 2026 11:59:47 +0100 Subject: [PATCH] message ack receice and reactions protobuf --- client/helpers/bgPollHelper.go | 12 ++- client/messagestorage.go | 61 +++++++++++ messages.pb.go | 180 +++++++++++++++++++++------------ pb/messages.proto | 23 +++-- 4 files changed, 204 insertions(+), 72 deletions(-) diff --git a/client/helpers/bgPollHelper.go b/client/helpers/bgPollHelper.go index 77f467a..3ff2424 100644 --- a/client/helpers/bgPollHelper.go +++ b/client/helpers/bgPollHelper.go @@ -148,6 +148,16 @@ func ConsumeInboxFile(messageFilename string) ([]string, []string, string, error return nil, nil, "ReadMessage: ProcessInboundUserMessage", err } + // Check for received or processed already filled => it's an ack for one of our sent messages + if len(usermsg.Data) == 0 && usermsg.Status != nil && usermsg.Status.Uuid != "" && + (usermsg.Status.Received != 0 || usermsg.Status.Processed != 0) { + password, _ := client.GetConfig().GetMemPass() + if ackErr := client.UpdateMessageAck(peer, usermsg.Status.Uuid, usermsg.Status.Received, usermsg.Status.Processed, password); ackErr != nil { + logger.Warn().Err(ackErr).Str("uuid", usermsg.Status.Uuid).Msg("ConsumeInboxFile: UpdateMessageAck") + } + continue + } + //fmt.Println("From:", usermsg.From) //jsonUserMessage, _ := json.Marshal(usermsg) //fmt.Println(string(jsonUserMessage)) @@ -202,7 +212,7 @@ func ConsumeInboxFile(messageFilename string) ([]string, []string, string, error logger.Warn().Err(ackErr).Str("peer", peer.Uid).Msg("ConsumeInboxFile: sendDeliveryAck") } } - } + } } err = os.Remove(messageFilename) diff --git a/client/messagestorage.go b/client/messagestorage.go index 857b4ff..8e67551 100644 --- a/client/messagestorage.go +++ b/client/messagestorage.go @@ -368,6 +368,67 @@ func SetMessageServerDelivery(dbFile string, dbId int64, serverUid string, recei return UpdateDbMessage(dbm, dbFile, dbId, password) } +// FindMessageByUuid scans all DB files for a peer (newest first) and returns +// the dbFile, row ID, and DbMessage for the message whose Status.Uuid matches. +func FindMessageByUuid(peer *Peer, messageUuid string, password string) (string, int64, *meowlib.DbMessage, error) { + cfg := GetConfig() + identity := cfg.GetIdentity() + for i := len(peer.DbIds) - 1; i >= 0; i-- { + dbid := peer.DbIds[i] + db, err := sql.Open("sqlite3", filepath.Join(cfg.StoragePath, identity.Uuid, dbid+GetConfig().DbSuffix)) + if err != nil { + continue + } + rows, err := db.Query("SELECT id, m FROM message ORDER BY id DESC") + if err != nil { + db.Close() + continue + } + for rows.Next() { + var id int64 + var m []byte + if err := rows.Scan(&id, &m); err != nil { + continue + } + decdata, err := meowlib.SymDecrypt(password, m) + if err != nil { + continue + } + var dbm meowlib.DbMessage + if err := proto.Unmarshal(decdata, &dbm); err != nil { + continue + } + if dbm.Status != nil && dbm.Status.Uuid == messageUuid { + rows.Close() + db.Close() + return dbid, id, &dbm, nil + } + } + rows.Close() + db.Close() + } + return "", 0, nil, fmt.Errorf("message with UUID %s not found", messageUuid) +} + +// UpdateMessageAck finds a stored outbound message by UUID and stamps it with +// the received and/or processed timestamps from an inbound ACK message. +func UpdateMessageAck(peer *Peer, messageUuid string, receivedAt uint64, processedAt uint64, password string) error { + dbFile, dbId, dbm, err := FindMessageByUuid(peer, messageUuid, password) + if err != nil { + return err + } + if dbm.Status == nil { + dbm.Status = &meowlib.ConversationStatus{} + } + if receivedAt != 0 { + dbm.Status.Received = receivedAt + } + if processedAt != 0 { + dbm.Status.Processed = processedAt + } + return UpdateDbMessage(dbm, dbFile, dbId, password) +} + func createMessageTable(db *sql.DB) error { createMessageTableSQL := `CREATE TABLE message ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, diff --git a/messages.pb.go b/messages.pb.go index deca035..64a12f1 100644 --- a/messages.pb.go +++ b/messages.pb.go @@ -1108,7 +1108,7 @@ func (x *PackedUserMessage) GetDrHeader() []byte { type ConversationStatus struct { state protoimpl.MessageState `protogen:"open.v1"` Uuid string `protobuf:"bytes,1,opt,name=uuid,proto3" json:"uuid,omitempty"` // uuid of message, or uuid of related message if uuid_action is not empty - UuidAction int32 `protobuf:"varint,2,opt,name=uuid_action,json=uuidAction,proto3" json:"uuid_action,omitempty"` // empty => normal message, 1: receivedack, 2: processedack, 3:reaction + Reactions []*Reaction `protobuf:"bytes,2,rep,name=reactions,proto3" json:"reactions,omitempty"` // empty => normal message, 1: receivedack, 2: processedack, 3:reaction ReplyToUuid string `protobuf:"bytes,3,opt,name=reply_to_uuid,json=replyToUuid,proto3" json:"reply_to_uuid,omitempty"` // this message replies to the specified uuid LocalSequence uint64 `protobuf:"varint,4,opt,name=local_sequence,json=localSequence,proto3" json:"local_sequence,omitempty"` // seq number in local conversation for custom reordering Sent uint64 `protobuf:"varint,5,opt,name=sent,proto3" json:"sent,omitempty"` // timestamp of the message sent @@ -1157,11 +1157,11 @@ func (x *ConversationStatus) GetUuid() string { return "" } -func (x *ConversationStatus) GetUuidAction() int32 { +func (x *ConversationStatus) GetReactions() []*Reaction { if x != nil { - return x.UuidAction + return x.Reactions } - return 0 + return nil } func (x *ConversationStatus) GetReplyToUuid() string { @@ -1213,6 +1213,58 @@ func (x *ConversationStatus) GetPeerNextIdentityAck() int32 { return 0 } +type Reaction struct { + state protoimpl.MessageState `protogen:"open.v1"` + Reaction string `protobuf:"bytes,1,opt,name=reaction,proto3" json:"reaction,omitempty"` + ContactUuid string `protobuf:"bytes,2,opt,name=contact_uuid,json=contactUuid,proto3" json:"contact_uuid,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Reaction) Reset() { + *x = Reaction{} + mi := &file_messages_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Reaction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Reaction) ProtoMessage() {} + +func (x *Reaction) ProtoReflect() protoreflect.Message { + mi := &file_messages_proto_msgTypes[13] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Reaction.ProtoReflect.Descriptor instead. +func (*Reaction) Descriptor() ([]byte, []int) { + return file_messages_proto_rawDescGZIP(), []int{13} +} + +func (x *Reaction) GetReaction() string { + if x != nil { + return x.Reaction + } + return "" +} + +func (x *Reaction) GetContactUuid() string { + if x != nil { + return x.ContactUuid + } + return "" +} + type Group struct { state protoimpl.MessageState `protogen:"open.v1"` Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` @@ -1223,7 +1275,7 @@ type Group struct { func (x *Group) Reset() { *x = Group{} - mi := &file_messages_proto_msgTypes[13] + mi := &file_messages_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1235,7 +1287,7 @@ func (x *Group) String() string { func (*Group) ProtoMessage() {} func (x *Group) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[13] + mi := &file_messages_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1248,7 +1300,7 @@ func (x *Group) ProtoReflect() protoreflect.Message { // Deprecated: Use Group.ProtoReflect.Descriptor instead. func (*Group) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{13} + return file_messages_proto_rawDescGZIP(), []int{14} } func (x *Group) GetName() string { @@ -1287,7 +1339,7 @@ type UserMessage struct { func (x *UserMessage) Reset() { *x = UserMessage{} - mi := &file_messages_proto_msgTypes[14] + mi := &file_messages_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1299,7 +1351,7 @@ func (x *UserMessage) String() string { func (*UserMessage) ProtoMessage() {} func (x *UserMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[14] + mi := &file_messages_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1312,7 +1364,7 @@ func (x *UserMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use UserMessage.ProtoReflect.Descriptor instead. func (*UserMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{14} + return file_messages_proto_rawDescGZIP(), []int{15} } func (x *UserMessage) GetDestination() string { @@ -1418,7 +1470,7 @@ type File struct { func (x *File) Reset() { *x = File{} - mi := &file_messages_proto_msgTypes[15] + mi := &file_messages_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1430,7 +1482,7 @@ func (x *File) String() string { func (*File) ProtoMessage() {} func (x *File) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[15] + mi := &file_messages_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1443,7 +1495,7 @@ func (x *File) ProtoReflect() protoreflect.Message { // Deprecated: Use File.ProtoReflect.Descriptor instead. func (*File) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{15} + return file_messages_proto_rawDescGZIP(), []int{16} } func (x *File) GetFilename() string { @@ -1486,7 +1538,7 @@ type Location struct { func (x *Location) Reset() { *x = Location{} - mi := &file_messages_proto_msgTypes[16] + mi := &file_messages_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1498,7 +1550,7 @@ func (x *Location) String() string { func (*Location) ProtoMessage() {} func (x *Location) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[16] + mi := &file_messages_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1511,7 +1563,7 @@ func (x *Location) ProtoReflect() protoreflect.Message { // Deprecated: Use Location.ProtoReflect.Descriptor instead. func (*Location) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{16} + return file_messages_proto_rawDescGZIP(), []int{17} } func (x *Location) GetTime() uint64 { @@ -1563,7 +1615,7 @@ type DbMessage struct { func (x *DbMessage) Reset() { *x = DbMessage{} - mi := &file_messages_proto_msgTypes[17] + mi := &file_messages_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1575,7 +1627,7 @@ func (x *DbMessage) String() string { func (*DbMessage) ProtoMessage() {} func (x *DbMessage) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[17] + mi := &file_messages_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1588,7 +1640,7 @@ func (x *DbMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use DbMessage.ProtoReflect.Descriptor instead. func (*DbMessage) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{17} + return file_messages_proto_rawDescGZIP(), []int{18} } func (x *DbMessage) GetOutbound() bool { @@ -1695,7 +1747,7 @@ type VideoData struct { func (x *VideoData) Reset() { *x = VideoData{} - mi := &file_messages_proto_msgTypes[18] + mi := &file_messages_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1707,7 +1759,7 @@ func (x *VideoData) String() string { func (*VideoData) ProtoMessage() {} func (x *VideoData) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[18] + mi := &file_messages_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1720,7 +1772,7 @@ func (x *VideoData) ProtoReflect() protoreflect.Message { // Deprecated: Use VideoData.ProtoReflect.Descriptor instead. func (*VideoData) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{18} + return file_messages_proto_rawDescGZIP(), []int{19} } func (x *VideoData) GetUrl() string { @@ -1769,7 +1821,7 @@ type VideoCredential struct { func (x *VideoCredential) Reset() { *x = VideoCredential{} - mi := &file_messages_proto_msgTypes[19] + mi := &file_messages_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1781,7 +1833,7 @@ func (x *VideoCredential) String() string { func (*VideoCredential) ProtoMessage() {} func (x *VideoCredential) ProtoReflect() protoreflect.Message { - mi := &file_messages_proto_msgTypes[19] + mi := &file_messages_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1794,7 +1846,7 @@ func (x *VideoCredential) ProtoReflect() protoreflect.Message { // Deprecated: Use VideoCredential.ProtoReflect.Descriptor instead. func (*VideoCredential) Descriptor() ([]byte, []int) { - return file_messages_proto_rawDescGZIP(), []int{19} + return file_messages_proto_rawDescGZIP(), []int{20} } func (x *VideoCredential) GetUsername() string { @@ -1932,18 +1984,20 @@ const file_messages_proto_rawDesc = "" + "\tsignature\x18\x03 \x01(\fR\tsignature\x12)\n" + "\x10server_timestamp\x18\x04 \x03(\x03R\x0fserverTimestamp\x120\n" + "\x14server_delivery_uuid\x18\x05 \x01(\tR\x12serverDeliveryUuid\x12\x1b\n" + - "\tdr_header\x18\x06 \x01(\fR\bdrHeader\"\xd7\x02\n" + + "\tdr_header\x18\x06 \x01(\fR\bdrHeader\"\xe7\x02\n" + "\x12ConversationStatus\x12\x12\n" + - "\x04uuid\x18\x01 \x01(\tR\x04uuid\x12\x1f\n" + - "\vuuid_action\x18\x02 \x01(\x05R\n" + - "uuidAction\x12\"\n" + + "\x04uuid\x18\x01 \x01(\tR\x04uuid\x12/\n" + + "\treactions\x18\x02 \x03(\v2\x11.meowlib.ReactionR\treactions\x12\"\n" + "\rreply_to_uuid\x18\x03 \x01(\tR\vreplyToUuid\x12%\n" + "\x0elocal_sequence\x18\x04 \x01(\x04R\rlocalSequence\x12\x12\n" + "\x04sent\x18\x05 \x01(\x04R\x04sent\x12\x1a\n" + "\breceived\x18\x06 \x01(\x04R\breceived\x12\x1c\n" + "\tprocessed\x18\a \x01(\x04R\tprocessed\x12>\n" + "\x10my_next_identity\x18\b \x01(\v2\x14.meowlib.ContactCardR\x0emyNextIdentity\x123\n" + - "\x16peer_next_identity_ack\x18\t \x01(\x05R\x13peerNextIdentityAck\"K\n" + + "\x16peer_next_identity_ack\x18\t \x01(\x05R\x13peerNextIdentityAck\"I\n" + + "\bReaction\x12\x1a\n" + + "\breaction\x18\x01 \x01(\tR\breaction\x12!\n" + + "\fcontact_uuid\x18\x02 \x01(\tR\vcontactUuid\"K\n" + "\x05Group\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\x12.\n" + "\amembers\x18\x02 \x03(\v2\x14.meowlib.ContactCardR\amembers\"\x95\x04\n" + @@ -2018,7 +2072,7 @@ func file_messages_proto_rawDescGZIP() []byte { return file_messages_proto_rawDescData } -var file_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 20) +var file_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 21) var file_messages_proto_goTypes = []any{ (*PackedServerMessage)(nil), // 0: meowlib.PackedServerMessage (*Invitation)(nil), // 1: meowlib.Invitation @@ -2033,13 +2087,14 @@ var file_messages_proto_goTypes = []any{ (*ContactCard)(nil), // 10: meowlib.ContactCard (*PackedUserMessage)(nil), // 11: meowlib.PackedUserMessage (*ConversationStatus)(nil), // 12: meowlib.ConversationStatus - (*Group)(nil), // 13: meowlib.Group - (*UserMessage)(nil), // 14: meowlib.UserMessage - (*File)(nil), // 15: meowlib.File - (*Location)(nil), // 16: meowlib.Location - (*DbMessage)(nil), // 17: meowlib.DbMessage - (*VideoData)(nil), // 18: meowlib.VideoData - (*VideoCredential)(nil), // 19: meowlib.VideoCredential + (*Reaction)(nil), // 13: meowlib.Reaction + (*Group)(nil), // 14: meowlib.Group + (*UserMessage)(nil), // 15: meowlib.UserMessage + (*File)(nil), // 16: meowlib.File + (*Location)(nil), // 17: meowlib.Location + (*DbMessage)(nil), // 18: meowlib.DbMessage + (*VideoData)(nil), // 19: meowlib.VideoData + (*VideoCredential)(nil), // 20: meowlib.VideoCredential } var file_messages_proto_depIdxs = []int32{ 10, // 0: meowlib.Meet.contact_card:type_name -> meowlib.ContactCard @@ -2049,38 +2104,39 @@ var file_messages_proto_depIdxs = []int32{ 8, // 4: meowlib.ToServerMessage.matriochka_message:type_name -> meowlib.Matriochka 1, // 5: meowlib.ToServerMessage.invitation:type_name -> meowlib.Invitation 11, // 6: meowlib.ToServerMessage.device_messages:type_name -> meowlib.PackedUserMessage - 18, // 7: meowlib.ToServerMessage.video_data:type_name -> meowlib.VideoData + 19, // 7: meowlib.ToServerMessage.video_data:type_name -> meowlib.VideoData 4, // 8: meowlib.ToServerMessage.credentials:type_name -> meowlib.Credentials 11, // 9: meowlib.FromServerMessage.chat:type_name -> meowlib.PackedUserMessage 9, // 10: meowlib.FromServerMessage.known_servers:type_name -> meowlib.ServerCard 1, // 11: meowlib.FromServerMessage.invitation:type_name -> meowlib.Invitation 11, // 12: meowlib.FromServerMessage.device_messages:type_name -> meowlib.PackedUserMessage - 18, // 13: meowlib.FromServerMessage.video_data:type_name -> meowlib.VideoData + 19, // 13: meowlib.FromServerMessage.video_data:type_name -> meowlib.VideoData 10, // 14: meowlib.FromServerMessage.contact_card:type_name -> meowlib.ContactCard 7, // 15: meowlib.Matriochka.prev:type_name -> meowlib.MatriochkaServer 7, // 16: meowlib.Matriochka.next:type_name -> meowlib.MatriochkaServer 9, // 17: meowlib.ContactCard.pull_servers:type_name -> meowlib.ServerCard - 10, // 18: meowlib.ConversationStatus.my_next_identity:type_name -> meowlib.ContactCard - 10, // 19: meowlib.Group.members:type_name -> meowlib.ContactCard - 12, // 20: meowlib.UserMessage.status:type_name -> meowlib.ConversationStatus - 10, // 21: meowlib.UserMessage.contact:type_name -> meowlib.ContactCard - 9, // 22: meowlib.UserMessage.known_servers:type_name -> meowlib.ServerCard - 13, // 23: meowlib.UserMessage.group:type_name -> meowlib.Group - 15, // 24: meowlib.UserMessage.files:type_name -> meowlib.File - 16, // 25: meowlib.UserMessage.current_location:type_name -> meowlib.Location - 1, // 26: meowlib.UserMessage.invitation:type_name -> meowlib.Invitation - 18, // 27: meowlib.UserMessage.video_data:type_name -> meowlib.VideoData - 12, // 28: meowlib.DbMessage.status:type_name -> meowlib.ConversationStatus - 10, // 29: meowlib.DbMessage.contact:type_name -> meowlib.ContactCard - 13, // 30: meowlib.DbMessage.group:type_name -> meowlib.Group - 16, // 31: meowlib.DbMessage.current_location:type_name -> meowlib.Location - 1, // 32: meowlib.DbMessage.invitation:type_name -> meowlib.Invitation - 19, // 33: meowlib.VideoData.credentials:type_name -> meowlib.VideoCredential - 34, // [34:34] is the sub-list for method output_type - 34, // [34:34] is the sub-list for method input_type - 34, // [34:34] is the sub-list for extension type_name - 34, // [34:34] is the sub-list for extension extendee - 0, // [0:34] is the sub-list for field type_name + 13, // 18: meowlib.ConversationStatus.reactions:type_name -> meowlib.Reaction + 10, // 19: meowlib.ConversationStatus.my_next_identity:type_name -> meowlib.ContactCard + 10, // 20: meowlib.Group.members:type_name -> meowlib.ContactCard + 12, // 21: meowlib.UserMessage.status:type_name -> meowlib.ConversationStatus + 10, // 22: meowlib.UserMessage.contact:type_name -> meowlib.ContactCard + 9, // 23: meowlib.UserMessage.known_servers:type_name -> meowlib.ServerCard + 14, // 24: meowlib.UserMessage.group:type_name -> meowlib.Group + 16, // 25: meowlib.UserMessage.files:type_name -> meowlib.File + 17, // 26: meowlib.UserMessage.current_location:type_name -> meowlib.Location + 1, // 27: meowlib.UserMessage.invitation:type_name -> meowlib.Invitation + 19, // 28: meowlib.UserMessage.video_data:type_name -> meowlib.VideoData + 12, // 29: meowlib.DbMessage.status:type_name -> meowlib.ConversationStatus + 10, // 30: meowlib.DbMessage.contact:type_name -> meowlib.ContactCard + 14, // 31: meowlib.DbMessage.group:type_name -> meowlib.Group + 17, // 32: meowlib.DbMessage.current_location:type_name -> meowlib.Location + 1, // 33: meowlib.DbMessage.invitation:type_name -> meowlib.Invitation + 20, // 34: meowlib.VideoData.credentials:type_name -> meowlib.VideoCredential + 35, // [35:35] is the sub-list for method output_type + 35, // [35:35] is the sub-list for method input_type + 35, // [35:35] is the sub-list for extension type_name + 35, // [35:35] is the sub-list for extension extendee + 0, // [0:35] is the sub-list for field type_name } func init() { file_messages_proto_init() } @@ -2094,7 +2150,7 @@ func file_messages_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_messages_proto_rawDesc), len(file_messages_proto_rawDesc)), NumEnums: 0, - NumMessages: 20, + NumMessages: 21, NumExtensions: 0, NumServices: 0, }, diff --git a/pb/messages.proto b/pb/messages.proto index 2fa7ec9..d6ed887 100644 --- a/pb/messages.proto +++ b/pb/messages.proto @@ -153,18 +153,23 @@ message PackedUserMessage { } message ConversationStatus { - string uuid = 1; // uuid of message, or uuid of related message if uuid_action is not empty - int32 uuid_action = 2; // empty => normal message, 1: receivedack, 2: processedack, 3:reaction - string reply_to_uuid = 3; // this message replies to the specified uuid - uint64 local_sequence = 4 ; // seq number in local conversation for custom reordering - uint64 sent = 5 ; // timestamp of the message sent - uint64 received = 6; // timestamp of the message received - uint64 processed = 7; // timestamp of the message processed - ContactCard my_next_identity = 8; - int32 peer_next_identity_ack = 9; // version of the new peer accepted id + string uuid = 1; // uuid of message, or uuid of related message if uuid_action is not empty + repeated Reaction reactions = 2; // reaction to the message per peer + string reply_to_uuid = 3; // this message replies to the specified uuid + uint64 local_sequence = 4 ; // seq number in local conversation for custom reordering + uint64 sent = 5 ; // timestamp of the message sent + uint64 received = 6; // timestamp of the message received + uint64 processed = 7; // timestamp of the message processed + ContactCard my_next_identity = 8; + int32 peer_next_identity_ack = 9; // version of the new peer accepted id } +message Reaction { + string reaction = 1; + string contact_uuid = 2; +} + message Group{ string name = 1; repeated ContactCard members = 2;