diff options
Diffstat (limited to 'matrix')
-rw-r--r-- | matrix/matrix.go | 51 | ||||
-rw-r--r-- | matrix/muksevt/event.go | 4 | ||||
-rw-r--r-- | matrix/rooms/room.go | 56 | ||||
-rw-r--r-- | matrix/sync.go | 37 |
4 files changed, 81 insertions, 67 deletions
diff --git a/matrix/matrix.go b/matrix/matrix.go index dcf9214..0a4c2e0 100644 --- a/matrix/matrix.go +++ b/matrix/matrix.go @@ -20,6 +20,7 @@ import ( "bytes" "context" "crypto/tls" + "encoding/gob" "encoding/json" "fmt" "io" @@ -29,6 +30,7 @@ import ( "os" "path" "path/filepath" + "reflect" "runtime" dbg "runtime/debug" "time" @@ -293,6 +295,11 @@ var AccountDataGomuksPreferences = event.Type{ Class: event.AccountDataEventType, } +func init() { + event.TypeMap[AccountDataGomuksPreferences] = reflect.TypeOf(config.UserPreferences{}) + gob.Register(&config.UserPreferences{}) +} + // OnLogin initializes the syncer and updates the room list. func (c *Container) OnLogin() { c.ui.OnLogin() @@ -462,7 +469,7 @@ func (c *Container) HandleEdit(room *rooms.Room, editsID id.EventID, editEvent * } func (c *Container) HandleReaction(room *rooms.Room, reactsTo id.EventID, reactEvent *muksevt.Event) { - rel := reactEvent.Content.GetRelatesTo() + rel := reactEvent.Content.AsReaction().RelatesTo var origEvt *muksevt.Event err := c.history.Update(room, reactsTo, func(evt *muksevt.Event) error { if evt.Unsigned.Relations.Annotations.Map == nil { @@ -502,10 +509,11 @@ func (c *Container) HandleMessage(source EventSource, mxEvent *event.Event) { return } - if editID := mxEvent.Content.GetRelatesTo().GetReplaceID(); len(editID) > 0 { + rel := mxEvent.Content.AsMessage().GetRelatesTo() + if editID := rel.GetReplaceID(); len(editID) > 0 { c.HandleEdit(room, editID, muksevt.Wrap(mxEvent)) return - } else if reactionID := mxEvent.Content.GetRelatesTo().GetAnnotationID(); mxEvent.Type == event.EventReaction && len(reactionID) > 0 { + } else if reactionID := rel.GetAnnotationID(); mxEvent.Type == event.EventReaction && len(reactionID) > 0 { c.HandleReaction(room, reactionID, muksevt.Wrap(mxEvent)) return } @@ -549,7 +557,7 @@ func (c *Container) HandleMessage(source EventSource, mxEvent *event.Event) { c.ui.Render() } } else { - debug.Printf("Parsing event %s type %s %v from %s in %s failed (ParseEvent() returned nil).", evt.ID, evt.Type.String(), evt.Content.Raw, evt.Sender, evt.RoomID) + debug.Printf("Parsing event %s type %s %v from %s in %s failed (ParseEvent() returned nil).", evt.ID, evt.Type.Repr(), evt.Content.Raw, evt.Sender, evt.RoomID) } } @@ -574,10 +582,10 @@ func (c *Container) HandleMembership(source EventSource, evt *event.Event) { } func (c *Container) processOwnMembershipChange(evt *event.Event) { - membership := evt.Content.Membership + membership := evt.Content.AsMember().Membership prevMembership := event.MembershipLeave if evt.Unsigned.PrevContent != nil { - prevMembership = evt.Unsigned.PrevContent.Membership + prevMembership = evt.Unsigned.PrevContent.AsMember().Membership } debug.Printf("Processing own membership change: %s->%s in %s", prevMembership, membership, evt.RoomID) if membership == prevMembership { @@ -704,12 +712,13 @@ func (c *Container) HandlePushRules(_ EventSource, evt *event.Event) { // HandleTag is the event handler for the m.tag account data event. func (c *Container) HandleTag(_ EventSource, evt *event.Event) { - debug.Printf("Received tags for %s: %s -- %s", evt.RoomID, evt.Content.RoomTags, string(evt.Content.VeryRaw)) room := c.GetOrCreateRoom(evt.RoomID) - newTags := make([]rooms.RoomTag, len(evt.Content.RoomTags)) + tags := evt.Content.AsTag().Tags + + newTags := make([]rooms.RoomTag, len(tags)) index := 0 - for tag, info := range evt.Content.RoomTags { + for tag, info := range tags { order := json.Number("0.5") if len(info.Order) > 0 { order = info.Order @@ -733,7 +742,7 @@ func (c *Container) HandleTyping(_ EventSource, evt *event.Event) { if !c.config.AuthCache.InitialSyncDone { return } - c.ui.MainView().SetTyping(evt.RoomID, evt.Content.TypingUserIDs) + c.ui.MainView().SetTyping(evt.RoomID, evt.Content.AsTyping().UserIDs) } func (c *Container) MarkRead(roomID id.RoomID, eventID id.EventID) { @@ -742,9 +751,9 @@ func (c *Container) MarkRead(roomID id.RoomID, eventID id.EventID) { } func (c *Container) PrepareMarkdownMessage(roomID id.RoomID, msgtype event.MessageType, text, html string, rel *ifc.Relation) *muksevt.Event { - var content event.Content + var content event.MessageEventContent if html != "" { - content = event.Content{ + content = event.MessageEventContent{ FormattedBody: html, Format: event.FormatHTML, Body: text, @@ -777,10 +786,8 @@ func (c *Container) PrepareMarkdownMessage(roomID id.RoomID, msgtype event.Messa Type: event.EventMessage, Timestamp: time.Now().UnixNano() / 1e6, RoomID: roomID, - Content: content, - Unsigned: event.Unsigned{ - TransactionID: txnID, - }, + Content: event.Content{Parsed: &content}, + Unsigned: event.Unsigned{TransactionID: txnID}, }) localEcho.Gomuks.OutgoingState = muksevt.StateLocalEcho if rel != nil && rel.Type == event.RelReplace { @@ -797,12 +804,12 @@ func (c *Container) Redact(roomID id.RoomID, eventID id.EventID, reason string) } // SendMessage sends the given event. -func (c *Container) SendEvent(event *muksevt.Event) (id.EventID, error) { +func (c *Container) SendEvent(evt *muksevt.Event) (id.EventID, error) { defer debug.Recover() - c.client.UserTyping(event.RoomID, false, 0) + c.client.UserTyping(evt.RoomID, false, 0) c.typing = 0 - resp, err := c.client.SendMessageEvent(event.RoomID, event.Type, event.Content, mautrix.ReqSendEvent{TransactionID: event.Unsigned.TransactionID}) + resp, err := c.client.SendMessageEvent(evt.RoomID, evt.Type, &evt.Content, mautrix.ReqSendEvent{TransactionID: evt.Unsigned.TransactionID}) if err != nil { return "", err } @@ -892,6 +899,12 @@ func (c *Container) GetHistory(room *rooms.Room, limit int) ([]*muksevt.Event, e return nil, err } debug.Printf("Loaded %d events for %s from server from %s to %s", len(resp.Chunk), room.ID, resp.Start, resp.End) + for _, evt := range resp.Chunk { + err := evt.Content.ParseRaw(evt.Type) + if err != nil { + debug.Printf("Failed to unmarshal content of event %s (type %s) by %s in %s: %v\n%s", evt.ID, evt.Type.Repr(), evt.Sender, evt.RoomID, err, string(evt.Content.VeryRaw)) + } + } for _, evt := range resp.State { room.UpdateState(evt) } diff --git a/matrix/muksevt/event.go b/matrix/muksevt/event.go index 9f7a3ce..d1bca13 100644 --- a/matrix/muksevt/event.go +++ b/matrix/muksevt/event.go @@ -27,8 +27,10 @@ type Event struct { func (evt *Event) SomewhatDangerousCopy() *Event { base := *evt.Event + content := *base.Content.Parsed.(*event.MessageEventContent) + evt.Content.Parsed = &content return &Event{ - Event: &base, + Event: &base, Gomuks: evt.Gomuks, } } diff --git a/matrix/rooms/room.go b/matrix/rooms/room.go index 50ec28f..87e63f0 100644 --- a/matrix/rooms/room.go +++ b/matrix/rooms/room.go @@ -62,7 +62,7 @@ type UnreadMessage struct { } type Member struct { - event.Member + event.MemberEventContent // The user who sent the membership event Sender id.UserID `json:"-"` @@ -397,25 +397,25 @@ func (room *Room) UpdateState(evt *event.Event) { if !exists { room.state[evt.Type] = make(map[string]*event.Event) } - switch evt.Type { - case event.StateRoomName: - room.NameCache = evt.Content.Name + switch content := evt.Content.Parsed.(type) { + case *event.RoomNameEventContent: + room.NameCache = content.Name room.nameCacheSource = ExplicitRoomName - case event.StateCanonicalAlias: + case *event.CanonicalAliasEventContent: if room.nameCacheSource <= CanonicalAliasRoomName { - room.NameCache = string(evt.Content.Alias) + room.NameCache = string(content.Alias) room.nameCacheSource = CanonicalAliasRoomName } - room.CanonicalAliasCache = evt.Content.Alias - case event.StateMember: + room.CanonicalAliasCache = content.Alias + case *event.MemberEventContent: if room.nameCacheSource <= MemberRoomName { room.NameCache = "" } - room.updateMemberState(evt) - case event.StateTopic: - room.topicCache = evt.Content.Topic - case event.StateEncryption: - if evt.Content.Algorithm == "m.megolm.v1.aes-sha2" { + room.updateMemberState(id.UserID(evt.GetStateKey()), evt.Sender, content) + case *event.TopicEventContent: + room.topicCache = content.Topic + case *event.EncryptionEventContent: + if content.Algorithm == "m.megolm.v1.aes-sha2" { room.Encrypted = true } } @@ -427,14 +427,13 @@ func (room *Room) UpdateState(evt *event.Event) { room.state[evt.Type][*evt.StateKey] = evt } -func (room *Room) updateMemberState(event *event.Event) { - userID := id.UserID(event.GetStateKey()) +func (room *Room) updateMemberState(userID, sender id.UserID, content *event.MemberEventContent) { if userID == room.SessionUserID { - debug.Print("Updating session user state:", string(event.Content.VeryRaw)) - room.SessionMember = room.eventToMember(userID, event.Sender, &event.Content) + debug.Print("Updating session user state:", content) + room.SessionMember = room.eventToMember(userID, sender, content) } if room.memberCache != nil { - member := room.eventToMember(userID, event.Sender, &event.Content) + member := room.eventToMember(userID, sender, content) if member.Membership.IsInviteOrJoin() { existingMember, ok := room.memberCache[userID] if ok { @@ -477,7 +476,7 @@ func (room *Room) GetTopic() string { if len(room.topicCache) == 0 { topicEvt := room.GetStateEvent(event.StateTopic, "") if topicEvt != nil { - room.topicCache = topicEvt.Content.Topic + room.topicCache = topicEvt.Content.AsTopic().Topic } } return room.topicCache @@ -487,7 +486,7 @@ func (room *Room) GetCanonicalAlias() id.RoomAlias { if len(room.CanonicalAliasCache) == 0 { canonicalAliasEvt := room.GetStateEvent(event.StateCanonicalAlias, "") if canonicalAliasEvt != nil { - room.CanonicalAliasCache = canonicalAliasEvt.Content.Alias + room.CanonicalAliasCache = canonicalAliasEvt.Content.AsCanonicalAlias().Alias } else { room.CanonicalAliasCache = "-" } @@ -502,7 +501,7 @@ func (room *Room) GetCanonicalAlias() id.RoomAlias { func (room *Room) updateNameFromNameEvent() { nameEvt := room.GetStateEvent(event.StateRoomName, "") if nameEvt != nil { - room.NameCache = nameEvt.Content.Name + room.NameCache = nameEvt.Content.AsRoomName().Name } } @@ -566,7 +565,10 @@ func (room *Room) IsReplaced() bool { evt := room.GetStateEvent(event.StateTombstone, "") var replacement id.RoomID if evt != nil { - replacement = evt.Content.ReplacementRoom + content, ok := evt.Content.Parsed.(*event.TombstoneEventContent) + if ok { + replacement = content.ReplacementRoom + } } room.replacedCache = evt != nil room.replacedByCache = &replacement @@ -581,15 +583,13 @@ func (room *Room) ReplacedBy() id.RoomID { return *room.replacedByCache } -func (room *Room) eventToMember(userID, sender id.UserID, content *event.Content) *Member { - member := content.Member - member.Membership = content.Membership +func (room *Room) eventToMember(userID, sender id.UserID, member *event.MemberEventContent) *Member { if len(member.Displayname) == 0 { member.Displayname = string(userID) } return &Member{ - Member: member, - Sender: sender, + MemberEventContent: *member, + Sender: sender, } } @@ -617,7 +617,7 @@ func (room *Room) createMemberCache() map[id.UserID]*Member { if memberEvents != nil { for userIDStr, evt := range memberEvents { userID := id.UserID(userIDStr) - member := room.eventToMember(userID, evt.Sender, &evt.Content) + member := room.eventToMember(userID, evt.Sender, evt.Content.AsMember()) if member.Membership.IsInviteOrJoin() { cache[userID] = member room.updateNthMemberCache(userID, member) diff --git a/matrix/sync.go b/matrix/sync.go index 53c1798..cd6334f 100644 --- a/matrix/sync.go +++ b/matrix/sync.go @@ -19,7 +19,6 @@ package matrix import ( - "encoding/json" "fmt" "time" @@ -154,38 +153,40 @@ func (s *GomuksSyncer) ProcessResponse(res *mautrix.RespSync, since string) (err return } -func (s *GomuksSyncer) processSyncEvents(room *rooms.Room, events []json.RawMessage, source EventSource) { +func (s *GomuksSyncer) processSyncEvents(room *rooms.Room, events []*event.Event, source EventSource) { for _, evt := range events { s.processSyncEvent(room, evt, source) } } -func (s *GomuksSyncer) processSyncEvent(room *rooms.Room, eventJSON json.RawMessage, source EventSource) { - evt := &event.Event{} - err := json.Unmarshal(eventJSON, evt) - if err != nil { - debug.Print("Failed to unmarshal event: %v\n%s", err, string(eventJSON)) - return +func (s *GomuksSyncer) processSyncEvent(room *rooms.Room, evt *event.Event, source EventSource) { + if room != nil { + evt.RoomID = room.ID } // Ensure the type class is correct. It's safe to mutate since it's not a pointer. // Listeners are keyed by type structs, which means only the correct class will pass. switch { case evt.StateKey != nil: evt.Type.Class = event.StateEventType - case source == EventSourcePresence, source & EventSourceEphemeral != 0: + case source == EventSourcePresence, source&EventSourceEphemeral != 0: evt.Type.Class = event.EphemeralEventType - case source & EventSourceAccountData != 0: + case source&EventSourceAccountData != 0: evt.Type.Class = event.AccountDataEventType case source == EventSourceToDevice: evt.Type.Class = event.ToDeviceEventType default: evt.Type.Class = event.MessageEventType } - if room != nil { - evt.RoomID = room.ID - if evt.Type.IsState() { - room.UpdateState(evt) - } + + err := evt.Content.ParseRaw(evt.Type) + if err != nil { + debug.Printf("Failed to unmarshal content of event %s (type %s) by %s in %s: %v\n%s", evt.ID, evt.Type.Repr(), evt.Sender, evt.RoomID, err, string(evt.Content.VeryRaw)) + // TODO might be good to let these pass to allow handling invalid events too + return + } + + if room != nil && evt.Type.IsState() { + room.UpdateState(evt) } s.notifyListeners(source, evt) } @@ -217,8 +218,8 @@ func (s *GomuksSyncer) OnFailedSync(res *mautrix.RespSync, err error) (time.Dura } // GetFilterJSON returns a filter with a timeline limit of 50. -func (s *GomuksSyncer) GetFilterJSON(_ id.UserID) json.RawMessage { - filter := &mautrix.Filter{ +func (s *GomuksSyncer) GetFilterJSON(_ id.UserID) *mautrix.Filter { + return &mautrix.Filter{ Room: mautrix.RoomFilter{ IncludeLeave: false, State: mautrix.FilterPart{ @@ -264,6 +265,4 @@ func (s *GomuksSyncer) GetFilterJSON(_ id.UserID) json.RawMessage { NotTypes: []event.Type{event.NewEventType("*")}, }, } - rawFilter, _ := json.Marshal(&filter) - return rawFilter } |