diff --git a/bridgev2/errors.go b/bridgev2/errors.go index 514dc238..63433e71 100644 --- a/bridgev2/errors.go +++ b/bridgev2/errors.go @@ -75,6 +75,7 @@ var ( ErrMediaConvertFailed error = WrapErrorInStatus(errors.New("failed to convert media")).WithMessage("failed to convert media").WithIsCertain(true).WithSendNotice(true) ErrMembershipNotSupported error = WrapErrorInStatus(errors.New("this bridge does not support changing group membership")).WithIsCertain(true).WithErrorAsMessage().WithSendNotice(false).WithErrorReason(event.MessageStatusUnsupported) ErrDeleteChatNotSupported error = WrapErrorInStatus(errors.New("this bridge does not support deleting chats")).WithIsCertain(true).WithErrorAsMessage().WithSendNotice(false).WithErrorReason(event.MessageStatusUnsupported) + ErrActionResponseNotSupported error = WrapErrorInStatus(errors.New("this bridge does not support action responses")).WithIsCertain(true).WithErrorAsMessage().WithSendNotice(false).WithErrorReason(event.MessageStatusUnsupported) ErrPowerLevelsNotSupported error = WrapErrorInStatus(errors.New("this bridge does not support changing group power levels")).WithIsCertain(true).WithErrorAsMessage().WithSendNotice(false).WithErrorReason(event.MessageStatusUnsupported) ErrRemoteEchoTimeout = WrapErrorInStatus(errors.New("remote echo timed out")).WithIsCertain(false).WithSendNotice(true).WithErrorReason(event.MessageStatusTooOld) ErrRemoteAckTimeout = WrapErrorInStatus(errors.New("remote ack timed out")).WithIsCertain(false).WithSendNotice(true).WithErrorReason(event.MessageStatusTooOld) diff --git a/bridgev2/matrix/connector.go b/bridgev2/matrix/connector.go index f6a41e9b..80dad7cc 100644 --- a/bridgev2/matrix/connector.go +++ b/bridgev2/matrix/connector.go @@ -155,6 +155,7 @@ func (br *Connector) Init(bridge *bridgev2.Bridge) { br.EventProcessor.On(event.StateBeeperDisappearingTimer, br.handleRoomEvent) br.EventProcessor.On(event.BeeperDeleteChat, br.handleRoomEvent) br.EventProcessor.On(event.BeeperAcceptMessageRequest, br.handleRoomEvent) + br.EventProcessor.On(event.BeeperActionResponse, br.handleRoomEvent) br.EventProcessor.On(event.EphemeralEventReceipt, br.handleEphemeralEvent) br.EventProcessor.On(event.EphemeralEventTyping, br.handleEphemeralEvent) br.EventProcessor.On(event.EphemeralEventAIStream, br.handleEphemeralEvent) diff --git a/bridgev2/matrix/matrix.go b/bridgev2/matrix/matrix.go index fed85da6..804e2527 100644 --- a/bridgev2/matrix/matrix.go +++ b/bridgev2/matrix/matrix.go @@ -68,6 +68,10 @@ func (br *Connector) handleEphemeralEvent(ctx context.Context, evt *event.Event) case event.EphemeralEventTyping: typingContent := evt.Content.AsTyping() typingContent.UserIDs = slices.DeleteFunc(typingContent.UserIDs, br.shouldIgnoreEventFromUser) + case event.EphemeralEventAIStream: + if br.shouldIgnoreEvent(evt) { + return + } } br.Bridge.QueueMatrixEvent(ctx, evt) } diff --git a/bridgev2/matrixinterface.go b/bridgev2/matrixinterface.go index cef8c048..b4b64e1e 100644 --- a/bridgev2/matrixinterface.go +++ b/bridgev2/matrixinterface.go @@ -218,7 +218,6 @@ type MarkAsDMMatrixAPI interface { MarkAsDM(ctx context.Context, roomID id.RoomID, otherUser id.UserID) error } -// EphemeralSendingMatrixAPI extends MatrixAPI with ephemeral event delivery. type EphemeralSendingMatrixAPI interface { MatrixAPI SendEphemeralEvent(ctx context.Context, roomID id.RoomID, eventType event.Type, content *event.Content, txnID string) (*mautrix.RespSendEvent, error) diff --git a/bridgev2/networkinterface.go b/bridgev2/networkinterface.go index 1ba7a443..cac28019 100644 --- a/bridgev2/networkinterface.go +++ b/bridgev2/networkinterface.go @@ -657,10 +657,8 @@ type TypingHandlingNetworkAPI interface { HandleMatrixTyping(ctx context.Context, msg *MatrixTyping) error } -// EphemeralHandlingNetworkAPI is an optional interface that network connectors can implement to handle ephemeral events. type EphemeralHandlingNetworkAPI interface { NetworkAPI - // HandleMatrixEphemeral is called when a custom ephemeral event is sent in a portal room. HandleMatrixEphemeral(ctx context.Context, msg *MatrixEphemeralEvent) error } diff --git a/bridgev2/portal.go b/bridgev2/portal.go index 61d9ed25..ada28549 100644 --- a/bridgev2/portal.go +++ b/bridgev2/portal.go @@ -954,7 +954,7 @@ func (portal *Portal) handleMatrixEphemeral(ctx context.Context, sender *User, e login, _, err := portal.FindPreferredLogin(ctx, sender, true) if err != nil { log.Err(err).Msg("Failed to get user login to handle ephemeral event") - return EventHandlingResultFailed + return EventHandlingResultFailed.WithMSSError(err) } var origSender *OrigSender if login == nil { @@ -982,9 +982,9 @@ func (portal *Portal) handleMatrixEphemeral(ctx context.Context, sender *User, e }) if err != nil { log.Err(err).Msg("Failed to bridge Matrix ephemeral event") - return EventHandlingResultFailed + return EventHandlingResultFailed.WithMSSError(err) } - return EventHandlingResultSuccess + return EventHandlingResultSuccess.WithMSS() } func (portal *Portal) sendTypings(ctx context.Context, userIDs []id.UserID, typing bool) { @@ -1878,7 +1878,7 @@ func (portal *Portal) handleMatrixActionResponse( } api, ok := sender.Client.(ActionResponseHandlingNetworkAPI) if !ok { - return EventHandlingResultIgnored + return EventHandlingResultIgnored.WithMSSError(ErrActionResponseNotSupported) } err := api.HandleMatrixActionResponse(ctx, &MatrixActionResponse{ Event: evt, diff --git a/client_ephemeral_test.go b/client_ephemeral_test.go index a9ef530a..89be27a0 100644 --- a/client_ephemeral_test.go +++ b/client_ephemeral_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Tulir Asokan +// Copyright (c) 2026 Tulir Asokan // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/event/beeper.go b/event/beeper.go index adcc7b26..4401dbff 100644 --- a/event/beeper.go +++ b/event/beeper.go @@ -214,8 +214,6 @@ func (content *MessageEventContent) RemovePerMessageProfileFallback() { } } -// BeeperActionHint represents a single button in a com.beeper.action_hints content block. -// Based on MSC1485 (tulir). type BeeperActionHint struct { Body string `json:"body"` EventType string `json:"event_type,omitempty"` @@ -225,8 +223,6 @@ type BeeperActionHint struct { Img id.ContentURI `json:"img,omitempty"` } -// BeeperActionHints is a single object under "com.beeper.action_hints" containing -// both the hints array (from MSC1485) and Beeper extension fields. type BeeperActionHints struct { Hints []BeeperActionHint `json:"hints"` Exclusive bool `json:"exclusive,omitempty"` @@ -235,7 +231,6 @@ type BeeperActionHints struct { Context json.RawMessage `json:"context,omitempty"` } -// BeeperActionResponseEventContent represents the content of a com.beeper.action_response event. type BeeperActionResponseEventContent struct { RelatesTo *RelatesTo `json:"m.relates_to,omitempty"` ActionID string `json:"action_id,omitempty"` diff --git a/event/powerlevels_ephemeral_test.go b/event/powerlevels_ephemeral_test.go index 693f7d10..10d77d1d 100644 --- a/event/powerlevels_ephemeral_test.go +++ b/event/powerlevels_ephemeral_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2020 Tulir Asokan +// Copyright (c) 2026 Tulir Asokan // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this diff --git a/event/type.go b/event/type.go index 502eecf3..401d7563 100644 --- a/event/type.go +++ b/event/type.go @@ -206,7 +206,7 @@ var ( StateElementFunctionalMembers = Type{"io.element.functional_members", StateEventType} StateBeeperRoomFeatures = Type{"com.beeper.room_features", StateEventType} StateBeeperDisappearingTimer = Type{"com.beeper.disappearing_timer", StateEventType} - StateMSC4391BotCommand = Type{"org.matrix.msc4391.command_description", StateEventType} + StateMSC4391BotCommand = Type{"org.matrix.msc4391.command_description", StateEventType} ) // Message events