From 862cd8a0d74a8c38ac21bfe44788cc6671046ef0 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Thu, 29 Sep 2022 14:39:58 +0300 Subject: [PATCH] Add option to sync group members in parallel --- config/bridge.go | 1 + config/upgrade.go | 1 + example-config.yaml | 2 ++ portal.go | 38 +++++++++++++++++++++++++++++--------- 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/config/bridge.go b/config/bridge.go index 5828ee7..bb4fb86 100644 --- a/config/bridge.go +++ b/config/bridge.go @@ -94,6 +94,7 @@ type BridgeConfig struct { LoginSharedSecretMap map[string]string `yaml:"login_shared_secret_map"` PrivateChatPortalMeta bool `yaml:"private_chat_portal_meta"` + ParallelMemberSync bool `yaml:"parallel_member_sync"` BridgeNotices bool `yaml:"bridge_notices"` ResendBridgeInfo bool `yaml:"resend_bridge_info"` MuteBridging bool `yaml:"mute_bridging"` diff --git a/config/upgrade.go b/config/upgrade.go index 562c8a1..2d83b58 100644 --- a/config/upgrade.go +++ b/config/upgrade.go @@ -73,6 +73,7 @@ func DoUpgrade(helper *up.Helper) { helper.Copy(up.Map, "bridge", "login_shared_secret_map") } helper.Copy(up.Bool, "bridge", "private_chat_portal_meta") + helper.Copy(up.Bool, "bridge", "parallel_member_sync") helper.Copy(up.Bool, "bridge", "bridge_notices") helper.Copy(up.Bool, "bridge", "resend_bridge_info") helper.Copy(up.Bool, "bridge", "mute_bridging") diff --git a/example-config.yaml b/example-config.yaml index 864b8c9..1b662f6 100644 --- a/example-config.yaml +++ b/example-config.yaml @@ -232,6 +232,8 @@ bridge: example.com: foobar # Should the bridge explicitly set the avatar and room name for private chat portal rooms? private_chat_portal_meta: false + # Should group members be synced in parallel? This makes member sync faster + parallel_member_sync: false # Should Matrix m.notice-type messages be bridged? bridge_notices: true # Set this to true to tell the bridge to re-send m.bridge events to all rooms on the next run. diff --git a/portal.go b/portal.go index 787ef60..4ae4361 100644 --- a/portal.go +++ b/portal.go @@ -32,6 +32,7 @@ import ( "math" "mime" "net/http" + "runtime/debug" "strconv" "strings" "sync" @@ -898,6 +899,25 @@ func (portal *Portal) kickExtraUsers(participantMap map[types.JID]bool) { // portal.kickExtraUsers(participantMap) //} +func (portal *Portal) syncParticipant(source *User, participant types.GroupParticipant, puppet *Puppet, user *User, wg *sync.WaitGroup) { + defer func() { + wg.Done() + if err := recover(); err != nil { + portal.log.Errorfln("Syncing participant %s panicked: %v\n%s", participant.JID, err, debug.Stack()) + } + }() + puppet.SyncContact(source, true, false, "group participant") + if user != nil && user != source { + portal.ensureUserInvited(user) + } + if user == nil || !puppet.IntentFor(portal).IsCustomPuppet { + err := puppet.IntentFor(portal).EnsureJoined(portal.MXID) + if err != nil { + portal.log.Warnfln("Failed to make puppet of %s join %s: %v", participant.JID, portal.MXID, err) + } + } +} + func (portal *Portal) SyncParticipants(source *User, metadata *types.GroupInfo) { changed := false levels, err := portal.MainIntent().PowerLevels(portal.MXID) @@ -906,20 +926,18 @@ func (portal *Portal) SyncParticipants(source *User, metadata *types.GroupInfo) changed = true } changed = portal.applyPowerLevelFixes(levels) || changed + var wg sync.WaitGroup + wg.Add(len(metadata.Participants)) participantMap := make(map[types.JID]bool) for _, participant := range metadata.Participants { + portal.log.Debugfln("Syncing participant %s (admin: %t)", participant.JID, participant.IsAdmin) participantMap[participant.JID] = true puppet := portal.bridge.GetPuppetByJID(participant.JID) - puppet.SyncContact(source, true, false, "group participant") user := portal.bridge.GetUserByJID(participant.JID) - if user != nil && user != source { - portal.ensureUserInvited(user) - } - if user == nil || !puppet.IntentFor(portal).IsCustomPuppet { - err = puppet.IntentFor(portal).EnsureJoined(portal.MXID) - if err != nil { - portal.log.Warnfln("Failed to make puppet of %s join %s: %v", participant.JID, portal.MXID, err) - } + if portal.bridge.Config.Bridge.ParallelMemberSync { + go portal.syncParticipant(source, participant, puppet, user, &wg) + } else { + portal.syncParticipant(source, participant, puppet, user, &wg) } expectedLevel := 0 @@ -940,6 +958,8 @@ func (portal *Portal) SyncParticipants(source *User, metadata *types.GroupInfo) } } portal.kickExtraUsers(participantMap) + wg.Wait() + portal.log.Debugln("Participant sync completed") } func reuploadAvatar(intent *appservice.IntentAPI, url string) (id.ContentURI, error) {