From 2ea80dac6f823e49f93cab6d3a7b0f0b7b12d741 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sat, 28 Dec 2024 18:58:49 +0200 Subject: [PATCH] web/statestore: allow sync event fields to be null --- pkg/hicli/init.go | 26 ++++++-------------------- pkg/hicli/paginate.go | 15 ++------------- pkg/hicli/syncwrap.go | 1 - web/src/api/statestore/main.ts | 14 +++++++------- web/src/api/statestore/room.ts | 12 ++++++------ web/src/api/types/hievents.ts | 22 ++++++++++++---------- web/src/api/types/hitypes.ts | 12 ++++++++++++ 7 files changed, 45 insertions(+), 57 deletions(-) diff --git a/pkg/hicli/init.go b/pkg/hicli/init.go index a50023d..3c2b40f 100644 --- a/pkg/hicli/init.go +++ b/pkg/hicli/init.go @@ -14,12 +14,9 @@ import ( func (h *HiClient) getInitialSyncRoom(ctx context.Context, room *database.Room) *SyncRoom { syncRoom := &SyncRoom{ - Meta: room, - Events: make([]*database.Event, 0, 2), - Timeline: make([]database.TimelineRowTuple, 0), - State: map[event.Type]map[string]database.EventRowID{}, - Notifications: make([]SyncNotification, 0), - Receipts: make(map[id.EventID][]*database.Receipt), + Meta: room, + Events: make([]*database.Event, 0, 2), + State: map[event.Type]map[string]database.EventRowID{}, } ad, err := h.DB.AccountData.GetAllRoom(ctx, h.Account.UserID, room.ID) if err != nil { @@ -27,7 +24,6 @@ func (h *HiClient) getInitialSyncRoom(ctx context.Context, room *database.Room) if ctx.Err() != nil { return nil } - syncRoom.AccountData = make(map[event.Type]*database.AccountData) } else { syncRoom.AccountData = make(map[event.Type]*database.AccountData, len(ad)) for _, data := range ad { @@ -79,9 +75,7 @@ func (h *HiClient) GetInitialSync(ctx context.Context, batchSize int) iter.Seq[* return } payload := SyncComplete{ - Rooms: make(map[id.RoomID]*SyncRoom, len(rooms)-1), - LeftRooms: make([]id.RoomID, 0), - AccountData: make(map[event.Type]*database.AccountData), + Rooms: make(map[id.RoomID]*SyncRoom, len(rooms)), } if i == 0 { payload.InvitedRooms, err = h.DB.InvitedRoom.GetAll(ctx) @@ -91,6 +85,7 @@ func (h *HiClient) GetInitialSync(ctx context.Context, batchSize int) iter.Seq[* } return } + // TODO include space rooms in first batch too? payload.SpaceEdges, err = h.DB.SpaceEdge.GetAll(ctx, "") if err != nil { if ctx.Err() == nil { @@ -100,12 +95,6 @@ func (h *HiClient) GetInitialSync(ctx context.Context, batchSize int) iter.Seq[* } payload.ClearState = true } - if payload.InvitedRooms == nil { - payload.InvitedRooms = make([]*database.InvitedRoom, 0) - } - if payload.SpaceEdges == nil { - payload.SpaceEdges = make(map[id.RoomID][]*database.SpaceEdge) - } for _, room := range rooms { if room.SortingTimestamp == rooms[len(rooms)-1].SortingTimestamp { break @@ -127,10 +116,7 @@ func (h *HiClient) GetInitialSync(ctx context.Context, batchSize int) iter.Seq[* return } payload := SyncComplete{ - Rooms: make(map[id.RoomID]*SyncRoom), - InvitedRooms: make([]*database.InvitedRoom, 0), - LeftRooms: make([]id.RoomID, 0), - AccountData: make(map[event.Type]*database.AccountData, len(ad)), + AccountData: make(map[event.Type]*database.AccountData, len(ad)), } for _, data := range ad { payload.AccountData[event.Type{Type: data.Type, Class: event.AccountDataEventType}] = data diff --git a/pkg/hicli/paginate.go b/pkg/hicli/paginate.go index 542ff5b..f41ceee 100644 --- a/pkg/hicli/paginate.go +++ b/pkg/hicli/paginate.go @@ -147,6 +147,7 @@ func (h *HiClient) processGetRoomState(ctx context.Context, roomID id.RoomID, fe return fmt.Errorf("failed to save current state entries: %w", err) } roomChanged := updatedRoom.CheckChangesAndCopyInto(room) + // TODO dispatch space edge changes if something changed? (fairly unlikely though) err = sdc.Apply(ctx, room, h.DB.SpaceEdge) if err != nil { return err @@ -160,21 +161,9 @@ func (h *HiClient) processGetRoomState(ctx context.Context, roomID id.RoomID, fe h.EventHandler(&SyncComplete{ Rooms: map[id.RoomID]*SyncRoom{ roomID: { - Meta: room, - Timeline: make([]database.TimelineRowTuple, 0), - State: make(map[event.Type]map[string]database.EventRowID), - AccountData: make(map[event.Type]*database.AccountData), - Events: make([]*database.Event, 0), - Reset: false, - Notifications: make([]SyncNotification, 0), - Receipts: make(map[id.EventID][]*database.Receipt), + Meta: room, }, }, - InvitedRooms: make([]*database.InvitedRoom, 0), - AccountData: make(map[event.Type]*database.AccountData), - LeftRooms: make([]id.RoomID, 0), - // TODO dispatch space edge changes if something changed? (fairly unlikely though) - SpaceEdges: make(map[id.RoomID][]*database.SpaceEdge), }) } } diff --git a/pkg/hicli/syncwrap.go b/pkg/hicli/syncwrap.go index 5b34f9b..8492da2 100644 --- a/pkg/hicli/syncwrap.go +++ b/pkg/hicli/syncwrap.go @@ -38,7 +38,6 @@ func (h *hiSyncer) ProcessResponse(ctx context.Context, resp *mautrix.RespSync, Rooms: make(map[id.RoomID]*SyncRoom, len(resp.Rooms.Join)), InvitedRooms: make([]*database.InvitedRoom, 0, len(resp.Rooms.Invite)), LeftRooms: make([]id.RoomID, 0, len(resp.Rooms.Leave)), - SpaceEdges: make(map[id.RoomID][]*database.SpaceEdge), }}) err := c.preProcessSyncResponse(ctx, resp, since) if err != nil { diff --git a/web/src/api/statestore/main.ts b/web/src/api/statestore/main.ts index f4332f8..1bfde16 100644 --- a/web/src/api/statestore/main.ts +++ b/web/src/api/statestore/main.ts @@ -122,7 +122,7 @@ export class StateStore { entry.meta.unread_highlights !== oldEntry.meta.current.unread_highlights || entry.meta.marked_unread !== oldEntry.meta.current.marked_unread || entry.meta.preview_event_rowid !== oldEntry.meta.current.preview_event_rowid || - entry.events.findIndex(evt => evt.rowid === entry.meta.preview_event_rowid) !== -1 + (entry.events ?? []).findIndex(evt => evt.rowid === entry.meta.preview_event_rowid) !== -1 } #makeRoomListEntry(entry: SyncRoom, room?: RoomStateStore): RoomListEntry | null { @@ -165,7 +165,7 @@ export class StateStore { } const resyncRoomList = this.roomList.current.length === 0 const changedRoomListEntries = new Map() - for (const data of sync.invited_rooms) { + for (const data of sync.invited_rooms ?? []) { const room = new InvitedRoomStore(data, this) this.inviteRooms.set(room.room_id, room) if (!resyncRoomList) { @@ -176,7 +176,7 @@ export class StateStore { } } const hasInvites = this.inviteRooms.size > 0 - for (const [roomID, data] of Object.entries(sync.rooms)) { + for (const [roomID, data] of Object.entries(sync.rooms ?? {})) { let isNewRoom = false let room = this.rooms.get(roomID) if (!room) { @@ -203,7 +203,7 @@ export class StateStore { } } - if (window.Notification?.permission === "granted" && !focused.current) { + if (window.Notification?.permission === "granted" && !focused.current && data.notifications) { for (const notification of data.notifications) { this.showNotification(room, notification.event_rowid, notification.sound) } @@ -212,7 +212,7 @@ export class StateStore { this.switchRoom?.(roomID) } } - for (const ad of Object.values(sync.account_data)) { + for (const ad of Object.values(sync.account_data ?? {})) { if (ad.type === "io.element.recent_emoji") { this.#frequentlyUsedEmoji = null } else if (ad.type === "fi.mau.gomuks.preferences") { @@ -222,7 +222,7 @@ export class StateStore { this.accountData.set(ad.type, ad.content) this.accountDataSubs.notify(ad.type) } - for (const roomID of sync.left_rooms) { + for (const roomID of sync.left_rooms ?? []) { if (this.activeRoomID === roomID) { this.switchRoom?.(null) } @@ -233,7 +233,7 @@ export class StateStore { let updatedRoomList: RoomListEntry[] | undefined if (resyncRoomList) { updatedRoomList = this.inviteRooms.values().toArray() - updatedRoomList = updatedRoomList.concat(Object.values(sync.rooms) + updatedRoomList = updatedRoomList.concat(Object.values(sync.rooms ?? {}) .map(entry => this.#makeRoomListEntry(entry)) .filter(entry => entry !== null)) updatedRoomList.sort((r1, r2) => r1.sorting_timestamp - r2.sorting_timestamp) diff --git a/web/src/api/statestore/room.ts b/web/src/api/statestore/room.ts index 20b4ae3..7419a55 100644 --- a/web/src/api/statestore/room.ts +++ b/web/src/api/statestore/room.ts @@ -390,7 +390,7 @@ export class RoomStateStore { } else { this.meta.emit(sync.meta) } - for (const ad of Object.values(sync.account_data)) { + for (const ad of Object.values(sync.account_data ?? {})) { if (ad.type === "fi.mau.gomuks.preferences") { this.serverPreferenceCache = ad.content this.preferenceSub.notify() @@ -398,10 +398,10 @@ export class RoomStateStore { this.accountData.set(ad.type, ad.content) this.accountDataSubs.notify(ad.type) } - for (const evt of sync.events) { + for (const evt of sync.events ?? []) { this.applyEvent(evt) } - for (const [evtType, changedEvts] of Object.entries(sync.state)) { + for (const [evtType, changedEvts] of Object.entries(sync.state ?? {})) { let stateMap = this.state.get(evtType) if (!stateMap) { stateMap = new Map() @@ -414,9 +414,9 @@ export class RoomStateStore { this.stateSubs.notify(evtType) } if (sync.reset) { - this.timeline = sync.timeline + this.timeline = sync.timeline ?? [] this.pendingEvents.splice(0, this.pendingEvents.length) - } else { + } else if (sync.timeline) { this.timeline.push(...sync.timeline) } if (sync.meta.unread_notifications === 0 && sync.meta.unread_highlights === 0) { @@ -426,7 +426,7 @@ export class RoomStateStore { this.openNotifications.clear() } this.notifyTimelineSubscribers() - for (const [evtID, receipts] of Object.entries(sync.receipts)) { + for (const [evtID, receipts] of Object.entries(sync.receipts ?? {})) { this.applyReceipts(receipts, evtID, false) } } diff --git a/web/src/api/types/hievents.ts b/web/src/api/types/hievents.ts index f05296e..f7d85d3 100644 --- a/web/src/api/types/hievents.ts +++ b/web/src/api/types/hievents.ts @@ -19,6 +19,7 @@ import { DBReceipt, DBRoom, DBRoomAccountData, + DBSpaceEdge, EventRowID, RawDBEvent, TimelineRowTuple, @@ -71,13 +72,13 @@ export interface ImageAuthTokenEvent extends BaseRPCCommand { export interface SyncRoom { meta: DBRoom - timeline: TimelineRowTuple[] - events: RawDBEvent[] - state: Record> + timeline: TimelineRowTuple[] | null + events: RawDBEvent[] | null + state: Record> | null reset: boolean - notifications: SyncNotification[] - account_data: Record - receipts: Record + notifications: SyncNotification[] | null + account_data: Record | null + receipts: Record | null } export interface SyncNotification { @@ -86,10 +87,11 @@ export interface SyncNotification { } export interface SyncCompleteData { - rooms: Record - invited_rooms: DBInvitedRoom[] - left_rooms: RoomID[] - account_data: Record + rooms: Record | null + invited_rooms: DBInvitedRoom[] | null + left_rooms: RoomID[] | null + account_data: Record | null + space_edges: Record[]> | null since?: string clear_state?: boolean } diff --git a/web/src/api/types/hitypes.ts b/web/src/api/types/hitypes.ts index 7796e82..a859a47 100644 --- a/web/src/api/types/hitypes.ts +++ b/web/src/api/types/hitypes.ts @@ -71,6 +71,18 @@ export interface DBRoom { prev_batch: string } +export interface DBSpaceEdge { + space_id: RoomID + child_id: RoomID + + child_event_rowid?: EventRowID + order?: string + suggested?: true + + parent_event_rowid?: EventRowID + canonical?: true +} + //eslint-disable-next-line @typescript-eslint/no-explicit-any export type UnknownEventContent = Record