From 0c57f044c6199373eba82b5bc0da00c791ffab2a Mon Sep 17 00:00:00 2001 From: 0xzer <0xzer@users.noreply.github.com> Date: Sat, 10 Aug 2024 16:34:20 +0200 Subject: [PATCH] read receipts / more twitter events --- ROADMAP.md | 42 ++++++++++++------------- pkg/connector/client.go | 1 + pkg/connector/handlematrix.go | 18 +++++++++++ pkg/connector/handletwit.go | 23 +++++--------- pkg/twittermeow/data/response/events.go | 40 +++++++++++++++++++++++ pkg/twittermeow/data/types/messaging.go | 17 ++++++++++ pkg/twittermeow/event/event.go | 19 +++++++++++ 7 files changed, 123 insertions(+), 37 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 6697bb7..70068ff 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,35 +1,35 @@ # Features & roadmap * Matrix → Twitter - * [+] Message content - * [+] Text + * [] Message content + * [] Text * [ ] Formatting - * [+] Media - * [+] Images - * [+] Videos - * [+] Gifs - * [+] Message reactions + * [] Media + * [] Images + * [] Videos + * [] Gifs + * [] Message reactions * [ ] Typing notifications - * [ ] Read receipts + * [] Read receipts * Twitter → Matrix - * [+] Message content - * [+] Text + * [] Message content + * [] Text * [ ] Formatting - * [+] Media - * [+] Images - * [+] Videos - * [+] Gifs - * [+] Message reactions - * [+] Message history - * [+] When creating portal + * [] Media + * [] Images + * [] Videos + * [] Gifs + * [] Message reactions + * [] Message history + * [] When creating portal * [ ] Missed messages - * [+] Avatars + * [] Avatars * [ ] † Typing notifications * [ ] † Read receipts * Misc - * [+] Automatic portal creation - * [+] At startup - * [+] When receiving invite or message + * [] Automatic portal creation + * [] At startup + * [] When receiving invite or message * [ ] Provisioning API for logging in * [ ] Private chat creation by inviting Matrix puppet of Twitter user to new room * [ ] Option to use own Matrix account for messages sent from other Twitter clients diff --git a/pkg/connector/client.go b/pkg/connector/client.go index e713d77..9495a24 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -44,6 +44,7 @@ type TwitterClient struct { var ( _ bridgev2.NetworkAPI = (*TwitterClient)(nil) _ bridgev2.ReactionHandlingNetworkAPI = (*TwitterClient)(nil) + _ bridgev2.ReadReceiptHandlingNetworkAPI = (*TwitterClient)(nil) ) func NewTwitterClient(ctx context.Context, tc *TwitterConnector, login *bridgev2.UserLogin) (*TwitterClient, error) { diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index 0b19660..96c65b9 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -116,4 +116,22 @@ func (tc *TwitterClient) doHandleMatrixReaction(remove bool, conversationId, mes tc.client.Logger.Debug().Any("reactionResponse", reactionResponse).Any("payload", reactionPayload).Msg("Reaction response") return nil +} + +func (tc *TwitterClient) HandleMatrixReadReceipt(ctx context.Context, msg *bridgev2.MatrixReadReceipt) error { + params := &payload.MarkConversationReadQuery{ + ConversationID: string(msg.Portal.ID), + } + + if msg.ExactMessage != nil { + params.LastReadEventID = string(msg.ExactMessage.ID) + } else { + lastMessage, err := tc.userLogin.Bridge.DB.Message.GetLastPartAtOrBeforeTime(ctx, msg.Portal.PortalKey, msg.ReadUpTo) + if err != nil { + return err + } + params.LastReadEventID = string(lastMessage.ID) + } + + return tc.client.MarkConversationRead(params) } \ No newline at end of file diff --git a/pkg/connector/handletwit.go b/pkg/connector/handletwit.go index d376fc5..94efaca 100644 --- a/pkg/connector/handletwit.go +++ b/pkg/connector/handletwit.go @@ -38,22 +38,9 @@ func (tc *TwitterClient) HandleTwitterEvent(rawEvt any) { reactionRemoteEvent := tc.wrapReaction(evtData) tc.connector.br.QueueRemoteEvent(tc.userLogin, reactionRemoteEvent) case event.XEventConversationRead: - /* - eventData := &simplevent.Receipt{ - EventMeta: simplevent.EventMeta{ - Type: bridgev2.RemoteEventReadReceipt, - LogContext: func(c zerolog.Context) zerolog.Context { - return c. - Str("conversation_id", evtData.Conversation.ConversationID). - Str("last_read_event_id", evtData.LastReadEventID). - Str("read_at", evtData.ReadAt.String()) - }, - PortalKey: tc.MakePortalKey(evtData.Conversation), - }, - LastTarget: networkid.MessageID(evtData.LastReadEventID), - Targets: []networkid.MessageID{networkid.MessageID(evtData.LastReadEventID)}, - } - */ + // conversation read events are only fired by yourself?? + // if another user reads your message this is never fired + // they use user_updates and last_read_event_id to figure that out with the polling client tc.client.Logger.Info(). Str("conversation_id", evtData.Conversation.ConversationID). Str("last_read_event_id", evtData.LastReadEventID). @@ -78,6 +65,10 @@ func (tc *TwitterClient) HandleTwitterEvent(rawEvt any) { } tc.connector.br.QueueRemoteEvent(tc.userLogin, messageDeleteRemoteEvent) } + case event.XEventConversationNameUpdate: + tc.client.Logger.Info().Str("new_name", evtData.Name).Any("conversation_id", evtData.Conversation.ConversationID).Any("executor", evtData.Executor).Msg("XEventConversationNameUpdate") + case event.XEventConversationDelete: + tc.client.Logger.Info().Any("data", evtData).Msg("Deleted conversation") default: tc.client.Logger.Warn().Any("event_data", evtData).Msg("Received unhandled event case from twitter library") } diff --git a/pkg/twittermeow/data/response/events.go b/pkg/twittermeow/data/response/events.go index 6019460..9ded776 100644 --- a/pkg/twittermeow/data/response/events.go +++ b/pkg/twittermeow/data/response/events.go @@ -109,6 +109,26 @@ func (data *XInboxData) ToEventEntries() ([]interface{}, error) { AffectsSort: messageEventData.AffectsSort, Reactions: messageEventData.MessageReactions, } + case event.XConversationNameUpdate: + var convNameUpdateEventData types.ConversationNameUpdateData + err = json.Unmarshal(jsonEvData, &convNameUpdateEventData) + if err != nil { + return nil, err + } + + updatedAt, err := methods.UnixStringMilliToTime(convNameUpdateEventData.Time) + if err != nil { + return nil, err + } + + updatedEntry = event.XEventConversationNameUpdate{ + Conversation: data.GetConversationByID(convNameUpdateEventData.ConversationID), + Name: convNameUpdateEventData.ConversationName, + Executor: data.GetUserByID(convNameUpdateEventData.ByUserID), + EventID: convNameUpdateEventData.ID, + AffectsSort: convNameUpdateEventData.AffectsSort, + UpdatedAt: updatedAt, + } case event.XMessageDeleteEvent: var messageDeletedEventData types.MessageDeleted err = json.Unmarshal(jsonEvData, &messageDeletedEventData) @@ -148,6 +168,25 @@ func (data *XInboxData) ToEventEntries() ([]interface{}, error) { AffectsSort: convReadEventData.AffectsSort, LastReadEventID: convReadEventData.LastReadEventID, } + case event.XConversationDeleteEvent: + var convDeletedEventData types.ConversationDeletedData + err = json.Unmarshal(jsonEvData, &convDeletedEventData) + if err != nil { + return nil, err + } + + deletedAt, err := methods.UnixStringMilliToTime(convDeletedEventData.Time) + if err != nil { + return nil, err + } + + updatedEntry = event.XEventConversationDelete{ + ConversationID: convDeletedEventData.ConversationID, + EventID: convDeletedEventData.ID, + DeletedAt: deletedAt, + AffectsSort: convDeletedEventData.AffectsSort, + LastEventID: convDeletedEventData.LastEventID, + } case event.XConversationCreateEvent: var convCreatedEventData types.ConversationCreatedData err = json.Unmarshal(jsonEvData, &convCreatedEventData) @@ -167,6 +206,7 @@ func (data *XInboxData) ToEventEntries() ([]interface{}, error) { AffectsSort: convCreatedEventData.AffectsSort, RequestID: convCreatedEventData.RequestID, } + case event.XConversationMetadataUpdateEvent: var convMetadataUpdateEventData types.ConversationMetadataUpdate err = json.Unmarshal(jsonEvData, &convMetadataUpdateEventData) diff --git a/pkg/twittermeow/data/types/messaging.go b/pkg/twittermeow/data/types/messaging.go index a2caae1..12a625f 100644 --- a/pkg/twittermeow/data/types/messaging.go +++ b/pkg/twittermeow/data/types/messaging.go @@ -69,6 +69,23 @@ type ConversationCreatedData struct { RequestID string `json:"request_id,omitempty"` } +type ConversationDeletedData struct { + ID string `json:"id,omitempty"` + Time string `json:"time,omitempty"` + AffectsSort bool `json:"affects_sort,omitempty"` + ConversationID string `json:"conversation_id,omitempty"` + LastEventID string `json:"last_event_id,omitempty"` +} + +type ConversationNameUpdateData struct { + ID string `json:"id,omitempty"` + Time string `json:"time,omitempty"` + ConversationID string `json:"conversation_id,omitempty"` + ConversationName string `json:"conversation_name,omitempty"` + ByUserID string `json:"by_user_id,omitempty"` + AffectsSort bool `json:"affects_sort,omitempty"` +} + type ConversationType string const ( diff --git a/pkg/twittermeow/event/event.go b/pkg/twittermeow/event/event.go index e18630c..930965d 100644 --- a/pkg/twittermeow/event/event.go +++ b/pkg/twittermeow/event/event.go @@ -14,7 +14,9 @@ const ( XReactionDeletedEvent XEventType = "reaction_delete" XConversationReadEvent XEventType = "conversation_read" XConversationMetadataUpdateEvent XEventType = "conversation_metadata_update" + XConversationNameUpdate XEventType = "conversation_name_update" XConversationCreateEvent XEventType = "conversation_create" + XConversationDeleteEvent XEventType = "remove_conversation" XDisableNotificationsEvent XEventType = "disable_notifications" ) @@ -48,6 +50,14 @@ type XEventConversationCreated struct { RequestID string } +type XEventConversationDelete struct { + ConversationID string + EventID string + DeletedAt time.Time + AffectsSort bool + LastEventID string +} + type XEventConversationMetadataUpdate struct { Conversation types.Conversation EventID string @@ -55,6 +65,15 @@ type XEventConversationMetadataUpdate struct { AffectsSort bool } +type XEventConversationNameUpdate struct { + Conversation types.Conversation + EventID string + UpdatedAt time.Time + Name string + Executor types.User + AffectsSort bool +} + type XEventMessageDeleted struct { Conversation types.Conversation EventID string