Skip to content

Commit 5846ee3

Browse files
Fizzadarclaude
andcommitted
Recover room state for portals saved without it
Shared group portals were rejected unless their saved state said private_group, so a group created through CreateGroup or a portal left behind by a failed resync stopped sync permanently. Shared portals are only ever created for groups, so return them as-is. Portals with no saved state still fail on an incremental sync, which omits the chat type. Move GetChatInfo's snapshot fallback into resolveRoomState and use it for sync updates, chat deletion and membership changes too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 18c7892 commit 5846ee3

5 files changed

Lines changed: 23 additions & 27 deletions

File tree

‎pkg/connector/chatinfo.go‎

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,12 @@ import (
99
"maunium.net/go/mautrix"
1010
"maunium.net/go/mautrix/bridgev2"
1111
"maunium.net/go/mautrix/bridgev2/networkid"
12-
"maunium.net/go/mautrix/id"
1312
)
1413

1514
// GetChatInfo uses saved native state, or fetches it when provisioning gets a
1615
// new room before the polling loop does. This read never advances the cursor.
1716
func (r *RedditClient) GetChatInfo(ctx context.Context, portal *bridgev2.Portal) (*bridgev2.ChatInfo, error) {
18-
roomID := portalIDToRoomID(portal.ID)
19-
state, key, err := r.roomState(ctx, roomID, &mautrix.SyncJoinedRoom{})
20-
if errors.Is(err, errMissingChatType) {
21-
full, fetchErr := r.fetchRoomSnapshots(ctx, []id.RoomID{roomID})
22-
if fetchErr != nil {
23-
return nil, fetchErr
24-
}
25-
joined := full.Rooms.Join[roomID]
26-
if joined == nil {
27-
joined, err = r.inviteSnapshot(full.Rooms.Invite[roomID])
28-
if err != nil {
29-
return nil, err
30-
}
31-
}
32-
state, key, err = r.roomState(ctx, roomID, joined)
33-
}
17+
state, key, err := r.resolveRoomState(ctx, portalIDToRoomID(portal.ID), &mautrix.SyncJoinedRoom{})
3418
if err != nil {
3519
return nil, err
3620
}

‎pkg/connector/chatsync.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ func (r *RedditClient) applyHiddenChatData(ctx context.Context, resp *redditchat
215215
}
216216

217217
func (r *RedditClient) handleRoomUpdate(ctx context.Context, roomID id.RoomID, joined *mautrix.SyncJoinedRoom) error {
218-
state, portalKey, err := r.roomState(ctx, roomID, joined)
218+
state, portalKey, err := r.resolveRoomState(ctx, roomID, joined)
219219
if err != nil {
220220
return err
221221
}

‎pkg/connector/membership.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ func (r *RedditClient) HandleMatrixMembership(ctx context.Context, msg *bridgev2
4141
return nil, bridgev2.ErrMembershipNotSupported
4242
}
4343
roomID := portalIDToRoomID(msg.Portal.ID)
44-
state, key, err := r.roomState(ctx, roomID, &mautrix.SyncJoinedRoom{})
44+
state, key, err := r.resolveRoomState(ctx, roomID, &mautrix.SyncJoinedRoom{})
4545
if err != nil {
4646
return nil, err
4747
}

‎pkg/connector/requests.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func (r *RedditClient) HandleMatrixDeleteChat(ctx context.Context, msg *bridgev2
5858
return errors.New("reddit chats cannot be deleted for everyone")
5959
}
6060
roomID := portalIDToRoomID(msg.Portal.ID)
61-
state, key, err := r.roomState(ctx, roomID, &mautrix.SyncJoinedRoom{})
61+
state, key, err := r.resolveRoomState(ctx, roomID, &mautrix.SyncJoinedRoom{})
6262
if err != nil {
6363
return err
6464
}

‎pkg/connector/roomstate.go‎

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -165,15 +165,27 @@ func (r *RedditClient) savedRoomPortal(ctx context.Context, roomID id.RoomID) (*
165165
return portal, err
166166
}
167167
key.Receiver = ""
168-
portal, err = r.main.Bridge.DB.Portal.GetByKey(ctx, key)
169-
if err != nil || portal == nil {
170-
return portal, err
168+
return r.main.Bridge.DB.Portal.GetByKey(ctx, key)
169+
}
170+
171+
// A portal row can exist without saved state, e.g. after a failed resync, and
172+
// incremental syncs omit the chat type. Fetch the snapshot outside roomMu.
173+
func (r *RedditClient) resolveRoomState(ctx context.Context, roomID id.RoomID, joined *mautrix.SyncJoinedRoom) (*RoomState, networkid.PortalKey, error) {
174+
state, key, err := r.roomState(ctx, roomID, joined)
175+
if !errors.Is(err, errMissingChatType) {
176+
return state, key, err
171177
}
172-
meta, ok := portal.Metadata.(*PortalMetadata)
173-
if !ok || meta == nil || meta.State == nil || meta.State.Type != "private_group" {
174-
return nil, errors.New("shared Reddit portal is not a known group")
178+
full, err := r.fetchRoomSnapshots(ctx, []id.RoomID{roomID})
179+
if err != nil {
180+
return nil, networkid.PortalKey{}, err
181+
}
182+
snapshot := full.Rooms.Join[roomID]
183+
if snapshot == nil {
184+
if snapshot, err = r.inviteSnapshot(full.Rooms.Invite[roomID]); err != nil {
185+
return nil, networkid.PortalKey{}, err
186+
}
175187
}
176-
return portal, nil
188+
return r.roomState(ctx, roomID, snapshot)
177189
}
178190

179191
func (r *RedditClient) chatInfoFromState(state *RoomState) *bridgev2.ChatInfo {

0 commit comments

Comments
 (0)