summaryrefslogtreecommitdiffstats
path: root/vendor/maunium.net/go/mautrix/event/content.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/maunium.net/go/mautrix/event/content.go')
-rw-r--r--vendor/maunium.net/go/mautrix/event/content.go506
1 files changed, 506 insertions, 0 deletions
diff --git a/vendor/maunium.net/go/mautrix/event/content.go b/vendor/maunium.net/go/mautrix/event/content.go
new file mode 100644
index 00000000..5624fd59
--- /dev/null
+++ b/vendor/maunium.net/go/mautrix/event/content.go
@@ -0,0 +1,506 @@
+// Copyright (c) 2021 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
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+package event
+
+import (
+ "encoding/gob"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "reflect"
+)
+
+// TypeMap is a mapping from event type to the content struct type.
+// This is used by Content.ParseRaw() for creating the correct type of struct.
+var TypeMap = map[Type]reflect.Type{
+ StateMember: reflect.TypeOf(MemberEventContent{}),
+ StatePowerLevels: reflect.TypeOf(PowerLevelsEventContent{}),
+ StateCanonicalAlias: reflect.TypeOf(CanonicalAliasEventContent{}),
+ StateRoomName: reflect.TypeOf(RoomNameEventContent{}),
+ StateRoomAvatar: reflect.TypeOf(RoomAvatarEventContent{}),
+ StateServerACL: reflect.TypeOf(ServerACLEventContent{}),
+ StateTopic: reflect.TypeOf(TopicEventContent{}),
+ StateTombstone: reflect.TypeOf(TombstoneEventContent{}),
+ StateCreate: reflect.TypeOf(CreateEventContent{}),
+ StateJoinRules: reflect.TypeOf(JoinRulesEventContent{}),
+ StateHistoryVisibility: reflect.TypeOf(HistoryVisibilityEventContent{}),
+ StateGuestAccess: reflect.TypeOf(GuestAccessEventContent{}),
+ StatePinnedEvents: reflect.TypeOf(PinnedEventsEventContent{}),
+ StatePolicyRoom: reflect.TypeOf(ModPolicyContent{}),
+ StatePolicyServer: reflect.TypeOf(ModPolicyContent{}),
+ StatePolicyUser: reflect.TypeOf(ModPolicyContent{}),
+ StateEncryption: reflect.TypeOf(EncryptionEventContent{}),
+ StateBridge: reflect.TypeOf(BridgeEventContent{}),
+ StateHalfShotBridge: reflect.TypeOf(BridgeEventContent{}),
+ StateSpaceParent: reflect.TypeOf(SpaceParentEventContent{}),
+ StateSpaceChild: reflect.TypeOf(SpaceChildEventContent{}),
+ StateInsertionMarker: reflect.TypeOf(InsertionMarkerContent{}),
+
+ EventMessage: reflect.TypeOf(MessageEventContent{}),
+ EventSticker: reflect.TypeOf(MessageEventContent{}),
+ EventEncrypted: reflect.TypeOf(EncryptedEventContent{}),
+ EventRedaction: reflect.TypeOf(RedactionEventContent{}),
+ EventReaction: reflect.TypeOf(ReactionEventContent{}),
+
+ BeeperMessageStatus: reflect.TypeOf(BeeperMessageStatusEventContent{}),
+
+ AccountDataRoomTags: reflect.TypeOf(TagEventContent{}),
+ AccountDataDirectChats: reflect.TypeOf(DirectChatsEventContent{}),
+ AccountDataFullyRead: reflect.TypeOf(FullyReadEventContent{}),
+ AccountDataIgnoredUserList: reflect.TypeOf(IgnoredUserListEventContent{}),
+
+ EphemeralEventTyping: reflect.TypeOf(TypingEventContent{}),
+ EphemeralEventReceipt: reflect.TypeOf(ReceiptEventContent{}),
+ EphemeralEventPresence: reflect.TypeOf(PresenceEventContent{}),
+
+ InRoomVerificationStart: reflect.TypeOf(VerificationStartEventContent{}),
+ InRoomVerificationReady: reflect.TypeOf(VerificationReadyEventContent{}),
+ InRoomVerificationAccept: reflect.TypeOf(VerificationAcceptEventContent{}),
+ InRoomVerificationKey: reflect.TypeOf(VerificationKeyEventContent{}),
+ InRoomVerificationMAC: reflect.TypeOf(VerificationMacEventContent{}),
+ InRoomVerificationCancel: reflect.TypeOf(VerificationCancelEventContent{}),
+
+ ToDeviceRoomKey: reflect.TypeOf(RoomKeyEventContent{}),
+ ToDeviceForwardedRoomKey: reflect.TypeOf(ForwardedRoomKeyEventContent{}),
+ ToDeviceRoomKeyRequest: reflect.TypeOf(RoomKeyRequestEventContent{}),
+ ToDeviceEncrypted: reflect.TypeOf(EncryptedEventContent{}),
+ ToDeviceRoomKeyWithheld: reflect.TypeOf(RoomKeyWithheldEventContent{}),
+ ToDeviceDummy: reflect.TypeOf(DummyEventContent{}),
+
+ ToDeviceVerificationStart: reflect.TypeOf(VerificationStartEventContent{}),
+ ToDeviceVerificationAccept: reflect.TypeOf(VerificationAcceptEventContent{}),
+ ToDeviceVerificationKey: reflect.TypeOf(VerificationKeyEventContent{}),
+ ToDeviceVerificationMAC: reflect.TypeOf(VerificationMacEventContent{}),
+ ToDeviceVerificationCancel: reflect.TypeOf(VerificationCancelEventContent{}),
+ ToDeviceVerificationRequest: reflect.TypeOf(VerificationRequestEventContent{}),
+
+ ToDeviceOrgMatrixRoomKeyWithheld: reflect.TypeOf(RoomKeyWithheldEventContent{}),
+
+ CallInvite: reflect.TypeOf(CallInviteEventContent{}),
+ CallCandidates: reflect.TypeOf(CallCandidatesEventContent{}),
+ CallAnswer: reflect.TypeOf(CallAnswerEventContent{}),
+ CallReject: reflect.TypeOf(CallRejectEventContent{}),
+ CallSelectAnswer: reflect.TypeOf(CallSelectAnswerEventContent{}),
+ CallNegotiate: reflect.TypeOf(CallNegotiateEventContent{}),
+ CallHangup: reflect.TypeOf(CallHangupEventContent{}),
+}
+
+// Content stores the content of a Matrix event.
+//
+// By default, the raw JSON bytes are stored in VeryRaw and parsed into a map[string]interface{} in the Raw field.
+// Additionally, you can call ParseRaw with the correct event type to parse the (VeryRaw) content into a nicer struct,
+// which you can then access from Parsed or via the helper functions.
+//
+// When being marshaled into JSON, the data in Parsed will be marshaled first and then recursively merged
+// with the data in Raw. Values in Raw are preferred, but nested objects will be recursed into before merging,
+// rather than overriding the whole object with the one in Raw).
+// If one of them is nil, the only the other is used. If both (Parsed and Raw) are nil, VeryRaw is used instead.
+type Content struct {
+ VeryRaw json.RawMessage
+ Raw map[string]interface{}
+ Parsed interface{}
+}
+
+type Relatable interface {
+ GetRelatesTo() *RelatesTo
+ OptionalGetRelatesTo() *RelatesTo
+ SetRelatesTo(rel *RelatesTo)
+}
+
+func (content *Content) UnmarshalJSON(data []byte) error {
+ content.VeryRaw = data
+ err := json.Unmarshal(data, &content.Raw)
+ return err
+}
+
+func (content *Content) MarshalJSON() ([]byte, error) {
+ if content.Raw == nil {
+ if content.Parsed == nil {
+ if content.VeryRaw == nil {
+ return []byte("{}"), nil
+ }
+ return content.VeryRaw, nil
+ }
+ return json.Marshal(content.Parsed)
+ } else if content.Parsed != nil {
+ // TODO this whole thing is incredibly hacky
+ // It needs to produce JSON, where:
+ // * content.Parsed is applied after content.Raw
+ // * MarshalJSON() is respected inside content.Parsed
+ // * Custom field inside nested objects of content.Raw are preserved,
+ // even if content.Parsed contains the higher-level objects.
+ // * content.Raw is not modified
+
+ unparsed, err := json.Marshal(content.Parsed)
+ if err != nil {
+ return nil, err
+ }
+
+ var rawParsed map[string]interface{}
+ err = json.Unmarshal(unparsed, &rawParsed)
+ if err != nil {
+ return nil, err
+ }
+
+ output := make(map[string]interface{})
+ for key, value := range content.Raw {
+ output[key] = value
+ }
+
+ mergeMaps(output, rawParsed)
+ return json.Marshal(output)
+ }
+ return json.Marshal(content.Raw)
+}
+
+// Deprecated: use errors.Is directly
+func IsUnsupportedContentType(err error) bool {
+ return errors.Is(err, ErrUnsupportedContentType)
+}
+
+var ErrContentAlreadyParsed = errors.New("content is already parsed")
+var ErrUnsupportedContentType = errors.New("unsupported event type")
+
+func (content *Content) ParseRaw(evtType Type) error {
+ if content.Parsed != nil {
+ return ErrContentAlreadyParsed
+ }
+ structType, ok := TypeMap[evtType]
+ if !ok {
+ return fmt.Errorf("%w %s", ErrUnsupportedContentType, evtType.Repr())
+ }
+ content.Parsed = reflect.New(structType).Interface()
+ return json.Unmarshal(content.VeryRaw, &content.Parsed)
+}
+
+func mergeMaps(into, from map[string]interface{}) {
+ for key, newValue := range from {
+ existingValue, ok := into[key]
+ if !ok {
+ into[key] = newValue
+ continue
+ }
+ existingValueMap, okEx := existingValue.(map[string]interface{})
+ newValueMap, okNew := newValue.(map[string]interface{})
+ if okEx && okNew {
+ mergeMaps(existingValueMap, newValueMap)
+ } else {
+ into[key] = newValue
+ }
+ }
+}
+
+func init() {
+ gob.Register(&MemberEventContent{})
+ gob.Register(&PowerLevelsEventContent{})
+ gob.Register(&CanonicalAliasEventContent{})
+ gob.Register(&EncryptionEventContent{})
+ gob.Register(&BridgeEventContent{})
+ gob.Register(&SpaceChildEventContent{})
+ gob.Register(&SpaceParentEventContent{})
+ gob.Register(&RoomNameEventContent{})
+ gob.Register(&RoomAvatarEventContent{})
+ gob.Register(&TopicEventContent{})
+ gob.Register(&TombstoneEventContent{})
+ gob.Register(&CreateEventContent{})
+ gob.Register(&JoinRulesEventContent{})
+ gob.Register(&HistoryVisibilityEventContent{})
+ gob.Register(&GuestAccessEventContent{})
+ gob.Register(&PinnedEventsEventContent{})
+ gob.Register(&MessageEventContent{})
+ gob.Register(&MessageEventContent{})
+ gob.Register(&EncryptedEventContent{})
+ gob.Register(&RedactionEventContent{})
+ gob.Register(&ReactionEventContent{})
+ gob.Register(&TagEventContent{})
+ gob.Register(&DirectChatsEventContent{})
+ gob.Register(&FullyReadEventContent{})
+ gob.Register(&IgnoredUserListEventContent{})
+ gob.Register(&TypingEventContent{})
+ gob.Register(&ReceiptEventContent{})
+ gob.Register(&PresenceEventContent{})
+ gob.Register(&RoomKeyEventContent{})
+ gob.Register(&ForwardedRoomKeyEventContent{})
+ gob.Register(&RoomKeyRequestEventContent{})
+ gob.Register(&RoomKeyWithheldEventContent{})
+}
+
+// Helper cast functions below
+
+func (content *Content) AsMember() *MemberEventContent {
+ casted, ok := content.Parsed.(*MemberEventContent)
+ if !ok {
+ return &MemberEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsPowerLevels() *PowerLevelsEventContent {
+ casted, ok := content.Parsed.(*PowerLevelsEventContent)
+ if !ok {
+ return &PowerLevelsEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsCanonicalAlias() *CanonicalAliasEventContent {
+ casted, ok := content.Parsed.(*CanonicalAliasEventContent)
+ if !ok {
+ return &CanonicalAliasEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsRoomName() *RoomNameEventContent {
+ casted, ok := content.Parsed.(*RoomNameEventContent)
+ if !ok {
+ return &RoomNameEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsRoomAvatar() *RoomAvatarEventContent {
+ casted, ok := content.Parsed.(*RoomAvatarEventContent)
+ if !ok {
+ return &RoomAvatarEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsTopic() *TopicEventContent {
+ casted, ok := content.Parsed.(*TopicEventContent)
+ if !ok {
+ return &TopicEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsTombstone() *TombstoneEventContent {
+ casted, ok := content.Parsed.(*TombstoneEventContent)
+ if !ok {
+ return &TombstoneEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsCreate() *CreateEventContent {
+ casted, ok := content.Parsed.(*CreateEventContent)
+ if !ok {
+ return &CreateEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsJoinRules() *JoinRulesEventContent {
+ casted, ok := content.Parsed.(*JoinRulesEventContent)
+ if !ok {
+ return &JoinRulesEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsHistoryVisibility() *HistoryVisibilityEventContent {
+ casted, ok := content.Parsed.(*HistoryVisibilityEventContent)
+ if !ok {
+ return &HistoryVisibilityEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsGuestAccess() *GuestAccessEventContent {
+ casted, ok := content.Parsed.(*GuestAccessEventContent)
+ if !ok {
+ return &GuestAccessEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsPinnedEvents() *PinnedEventsEventContent {
+ casted, ok := content.Parsed.(*PinnedEventsEventContent)
+ if !ok {
+ return &PinnedEventsEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsEncryption() *EncryptionEventContent {
+ casted, ok := content.Parsed.(*EncryptionEventContent)
+ if !ok {
+ return &EncryptionEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsBridge() *BridgeEventContent {
+ casted, ok := content.Parsed.(*BridgeEventContent)
+ if !ok {
+ return &BridgeEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsSpaceChild() *SpaceChildEventContent {
+ casted, ok := content.Parsed.(*SpaceChildEventContent)
+ if !ok {
+ return &SpaceChildEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsSpaceParent() *SpaceParentEventContent {
+ casted, ok := content.Parsed.(*SpaceParentEventContent)
+ if !ok {
+ return &SpaceParentEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsMessage() *MessageEventContent {
+ casted, ok := content.Parsed.(*MessageEventContent)
+ if !ok {
+ return &MessageEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsEncrypted() *EncryptedEventContent {
+ casted, ok := content.Parsed.(*EncryptedEventContent)
+ if !ok {
+ return &EncryptedEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsRedaction() *RedactionEventContent {
+ casted, ok := content.Parsed.(*RedactionEventContent)
+ if !ok {
+ return &RedactionEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsReaction() *ReactionEventContent {
+ casted, ok := content.Parsed.(*ReactionEventContent)
+ if !ok {
+ return &ReactionEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsTag() *TagEventContent {
+ casted, ok := content.Parsed.(*TagEventContent)
+ if !ok {
+ return &TagEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsDirectChats() *DirectChatsEventContent {
+ casted, ok := content.Parsed.(*DirectChatsEventContent)
+ if !ok {
+ return &DirectChatsEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsFullyRead() *FullyReadEventContent {
+ casted, ok := content.Parsed.(*FullyReadEventContent)
+ if !ok {
+ return &FullyReadEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsIgnoredUserList() *IgnoredUserListEventContent {
+ casted, ok := content.Parsed.(*IgnoredUserListEventContent)
+ if !ok {
+ return &IgnoredUserListEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsTyping() *TypingEventContent {
+ casted, ok := content.Parsed.(*TypingEventContent)
+ if !ok {
+ return &TypingEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsReceipt() *ReceiptEventContent {
+ casted, ok := content.Parsed.(*ReceiptEventContent)
+ if !ok {
+ return &ReceiptEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsPresence() *PresenceEventContent {
+ casted, ok := content.Parsed.(*PresenceEventContent)
+ if !ok {
+ return &PresenceEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsRoomKey() *RoomKeyEventContent {
+ casted, ok := content.Parsed.(*RoomKeyEventContent)
+ if !ok {
+ return &RoomKeyEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsForwardedRoomKey() *ForwardedRoomKeyEventContent {
+ casted, ok := content.Parsed.(*ForwardedRoomKeyEventContent)
+ if !ok {
+ return &ForwardedRoomKeyEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsRoomKeyRequest() *RoomKeyRequestEventContent {
+ casted, ok := content.Parsed.(*RoomKeyRequestEventContent)
+ if !ok {
+ return &RoomKeyRequestEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsRoomKeyWithheld() *RoomKeyWithheldEventContent {
+ casted, ok := content.Parsed.(*RoomKeyWithheldEventContent)
+ if !ok {
+ return &RoomKeyWithheldEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsCallInvite() *CallInviteEventContent {
+ casted, ok := content.Parsed.(*CallInviteEventContent)
+ if !ok {
+ return &CallInviteEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsCallCandidates() *CallCandidatesEventContent {
+ casted, ok := content.Parsed.(*CallCandidatesEventContent)
+ if !ok {
+ return &CallCandidatesEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsCallAnswer() *CallAnswerEventContent {
+ casted, ok := content.Parsed.(*CallAnswerEventContent)
+ if !ok {
+ return &CallAnswerEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsCallReject() *CallRejectEventContent {
+ casted, ok := content.Parsed.(*CallRejectEventContent)
+ if !ok {
+ return &CallRejectEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsCallSelectAnswer() *CallSelectAnswerEventContent {
+ casted, ok := content.Parsed.(*CallSelectAnswerEventContent)
+ if !ok {
+ return &CallSelectAnswerEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsCallNegotiate() *CallNegotiateEventContent {
+ casted, ok := content.Parsed.(*CallNegotiateEventContent)
+ if !ok {
+ return &CallNegotiateEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsCallHangup() *CallHangupEventContent {
+ casted, ok := content.Parsed.(*CallHangupEventContent)
+ if !ok {
+ return &CallHangupEventContent{}
+ }
+ return casted
+}
+func (content *Content) AsModPolicy() *ModPolicyContent {
+ casted, ok := content.Parsed.(*ModPolicyContent)
+ if !ok {
+ return &ModPolicyContent{}
+ }
+ return casted
+}