From 6adf319cfb6609209d808a6215398a33d6429468 Mon Sep 17 00:00:00 2001 From: Skip R Date: Tue, 3 Feb 2026 21:31:59 -0800 Subject: [PATCH] connector: sync guild spaces via event instead of manually --- pkg/connector/client.go | 47 ++--------- .../{events.go => events_chat_resync.go} | 0 pkg/connector/events_guild_resync.go | 78 +++++++++++++++++++ 3 files changed, 85 insertions(+), 40 deletions(-) rename pkg/connector/{events.go => events_chat_resync.go} (100%) create mode 100644 pkg/connector/events_guild_resync.go diff --git a/pkg/connector/client.go b/pkg/connector/client.go index c8b6871..9ed9797 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -29,12 +29,9 @@ import ( "github.com/bwmarrin/discordgo" "github.com/rs/zerolog" "maunium.net/go/mautrix/bridgev2" - "maunium.net/go/mautrix/bridgev2/database" "maunium.net/go/mautrix/bridgev2/networkid" "maunium.net/go/mautrix/bridgev2/status" - "go.mau.fi/util/ptr" - "go.mau.fi/mautrix-discord/pkg/discordid" ) @@ -271,38 +268,12 @@ func (d *DiscordClient) makeAvatarForGuild(guild *discordgo.Guild) *bridgev2.Ava } } -func (d *DiscordClient) syncGuildSpace(ctx context.Context, guild *discordgo.Guild) error { - prt, err := d.connector.Bridge.GetPortalByKey(ctx, d.guildPortalKeyFromID(guild.ID)) - if err != nil { - return fmt.Errorf("couldn't get/create portal corresponding to guild: %w", err) - } - - selfEvtSender := d.selfEventSender() - info := &bridgev2.ChatInfo{ - Name: &guild.Name, - Topic: nil, - Members: &bridgev2.ChatMemberList{ - MemberMap: map[networkid.UserID]bridgev2.ChatMember{selfEvtSender.Sender: {EventSender: selfEvtSender}}, - - // As recommended by the spec, prohibit normal events by setting - // `events_default` to a suitably high number. - PowerLevels: &bridgev2.PowerLevelOverrides{EventsDefault: ptr.Ptr(100)}, - }, - Avatar: d.makeAvatarForGuild(guild), - Type: ptr.Ptr(database.RoomTypeSpace), - } - - if prt.MXID == "" { - err := prt.CreateMatrixRoom(ctx, d.UserLogin, info) - - if err != nil { - return fmt.Errorf("couldn't create room in order to materialize guild portal: %w", err) - } - } else { - prt.UpdateInfo(ctx, info, d.UserLogin, nil, time.Time{}) - } - - return nil +func (d *DiscordClient) syncGuildSpace(_ context.Context, guild *discordgo.Guild) { + d.connector.Bridge.QueueRemoteEvent(d.UserLogin, &DiscordGuildResync{ + Client: d, + guild: guild, + portalKey: d.guildPortalKeyFromID(guild.ID), + }) } func (d *DiscordClient) syncGuilds(ctx context.Context) { @@ -330,11 +301,7 @@ func (d *DiscordClient) bridgeGuild(ctx context.Context, guildID string) error { return errors.New("couldn't find guild in state") } - err = d.syncGuildSpace(ctx, guild) - if err != nil { - log.Err(err).Msg("Couldn't sync guild space portal") - return fmt.Errorf("couldn't sync guild space portal: %w", err) - } + d.syncGuildSpace(ctx, guild) for _, guildCh := range guild.Channels { if guildCh.Type != discordgo.ChannelTypeGuildText { diff --git a/pkg/connector/events.go b/pkg/connector/events_chat_resync.go similarity index 100% rename from pkg/connector/events.go rename to pkg/connector/events_chat_resync.go diff --git a/pkg/connector/events_guild_resync.go b/pkg/connector/events_guild_resync.go new file mode 100644 index 0000000..54a6912 --- /dev/null +++ b/pkg/connector/events_guild_resync.go @@ -0,0 +1,78 @@ +// mautrix-discord - A Matrix-Discord puppeting bridge. +// Copyright (C) 2026 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package connector + +import ( + "context" + + "github.com/bwmarrin/discordgo" + "github.com/rs/zerolog" + "go.mau.fi/util/ptr" + "maunium.net/go/mautrix/bridgev2" + "maunium.net/go/mautrix/bridgev2/database" + "maunium.net/go/mautrix/bridgev2/networkid" +) + +type DiscordGuildResync struct { + Client *DiscordClient + guild *discordgo.Guild + portalKey networkid.PortalKey +} + +var ( + _ bridgev2.RemoteChatResyncWithInfo = (*DiscordGuildResync)(nil) + _ bridgev2.RemoteEventThatMayCreatePortal = (*DiscordGuildResync)(nil) +) + +func (d *DiscordGuildResync) AddLogContext(c zerolog.Context) zerolog.Context { + return c.Str("guild_id", d.guild.ID).Str("guild_name", d.guild.Name) +} + +func (d *DiscordGuildResync) GetPortalKey() networkid.PortalKey { + return d.portalKey +} + +func (d *DiscordGuildResync) GetSender() bridgev2.EventSender { + return bridgev2.EventSender{} +} + +func (d *DiscordGuildResync) GetType() bridgev2.RemoteEventType { + return bridgev2.RemoteEventChatResync +} + +func (d *DiscordGuildResync) ShouldCreatePortal() bool { + return true +} + +func (d *DiscordGuildResync) GetChatInfo(ctx context.Context, portal *bridgev2.Portal) (*bridgev2.ChatInfo, error) { + selfEvtSender := d.Client.selfEventSender() + + return &bridgev2.ChatInfo{ + Name: &d.guild.Name, + Topic: nil, + Members: &bridgev2.ChatMemberList{ + MemberMap: map[networkid.UserID]bridgev2.ChatMember{ + selfEvtSender.Sender: {EventSender: selfEvtSender}, + }, + // As recommended by the spec, prohibit normal events by setting + // events_default to a suitably high number. + PowerLevels: &bridgev2.PowerLevelOverrides{EventsDefault: ptr.Ptr(100)}, + }, + Avatar: d.Client.makeAvatarForGuild(d.guild), + Type: ptr.Ptr(database.RoomTypeSpace), + }, nil +}