channels: give getParticipants a stable Hash when read-model versions are missing
cachedParticipants returned a participant page with Hash=0 whenever the channel_base / channel_participants rows in read_model_versions were never seeded for a channel (e.g. groups created via messages.createChat). With Hash=0 the RPC layer can never answer channels.channelParticipantsNotModified, so a client that polls the member list re-fetches it in a tight loop forever. Fall back to a deterministic content hash derived from the page itself (channel id, page key, count, and each member's id/role/status/rank) so an unchanged member list yields an identical non-zero Hash and the client converges. The read-model-backed path is unchanged. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
41f65bf0fc
commit
5f63240f2d
2 changed files with 103 additions and 5 deletions
|
|
@ -814,6 +814,51 @@ func TestGetParticipantsCacheInvalidatesAfterAdminMutation(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestGetParticipantsFallsBackToContentHashWithoutReadModelVersions(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
const ownerID int64 = 1001
|
||||
base := &countingChannelStore{ChannelStore: memory.NewChannelStore()}
|
||||
// No WithReadModelVersions: channelParticipantsHash can never build an opaque
|
||||
// version hash, so the service must derive a stable one from the page itself.
|
||||
service := NewService(base)
|
||||
created, err := service.CreateChannel(ctx, ownerID, domain.CreateChannelRequest{
|
||||
Title: "Fallback Hash",
|
||||
Megagroup: true,
|
||||
MemberUserIDs: []int64{1002},
|
||||
Date: 1700004105,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("CreateChannel: %v", err)
|
||||
}
|
||||
filter := domain.ChannelParticipantsFilter{Kind: domain.ChannelParticipantsRecent}
|
||||
|
||||
first, err := service.GetParticipants(ctx, ownerID, created.Channel.ID, filter, 0, 20)
|
||||
if err != nil {
|
||||
t.Fatalf("first participants: %v", err)
|
||||
}
|
||||
if first.Hash == 0 {
|
||||
t.Fatalf("first participants hash = 0, want stable non-zero fallback")
|
||||
}
|
||||
second, err := service.GetParticipants(ctx, ownerID, created.Channel.ID, filter, 0, 20)
|
||||
if err != nil {
|
||||
t.Fatalf("second participants: %v", err)
|
||||
}
|
||||
if second.Hash != first.Hash {
|
||||
t.Fatalf("second hash = %d, want stable %d", second.Hash, first.Hash)
|
||||
}
|
||||
|
||||
if _, err := service.InviteToChannel(ctx, ownerID, created.Channel.ID, []int64{1003}, 1700004106); err != nil {
|
||||
t.Fatalf("InviteToChannel: %v", err)
|
||||
}
|
||||
third, err := service.GetParticipants(ctx, ownerID, created.Channel.ID, filter, 0, 20)
|
||||
if err != nil {
|
||||
t.Fatalf("third participants: %v", err)
|
||||
}
|
||||
if third.Hash == first.Hash {
|
||||
t.Fatalf("third hash = %d, want changed after a new member joined", third.Hash)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFullMegagroupAdminGrantFillsManageRanks(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
service := NewService(memory.NewChannelStore())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue