provisioning: improve compat with beeper desktop

This commit is contained in:
Skip R
2026-02-05 22:17:48 -08:00
parent 4f420c4662
commit a7ae544999

View File

@@ -20,6 +20,7 @@ import (
"context"
"errors"
"net/http"
"strings"
"github.com/bwmarrin/discordgo"
"github.com/rs/zerolog"
@@ -81,16 +82,17 @@ func (d *DiscordConnector) setUpProvisioningAPIs() error {
type guildEntry struct {
ID string `json:"id"`
Name string `json:"name"`
// TODO v1 uses `id.ContentURI` whereas we stuff the discord cdn url here
AvatarURL string `json:"avatar_url"`
// v1-compatible fields:
// new in v2:
Bridged bool `json:"bridged"`
Available bool `json:"available"`
// legacy fields from v1:
MXID string `json:"mxid"`
AutoBridge bool `json:"auto_bridge_channels"`
BridgingMode string `json:"bridging_mode"`
Available bool `json:"available"`
}
type respGuildsList struct {
Guilds []guildEntry `json:"guilds"`
@@ -120,6 +122,8 @@ func (p *ProvisioningAPI) guildsList(w http.ResponseWriter, r *http.Request, log
ctx := r.Context()
p.log.Info().Str("login_id", discordid.ParseUserLoginID(login.ID)).Msg("guilds list requested via provisioning api")
bridgedGuildIDs := client.bridgedGuildIDs()
var resp respGuildsList
resp.Guilds = []guildEntry{}
for _, guild := range client.Session.State.Guilds {
@@ -131,27 +135,62 @@ func (p *ProvisioningAPI) guildsList(w http.ResponseWriter, r *http.Request, log
Msg("Failed to get guild portal for provisioning list")
}
_, beingBridged := bridgedGuildIDs[guild.ID]
mxid := ""
if portal != nil {
if portal != nil && portal.MXID != "" {
mxid = portal.MXID.String()
} else if beingBridged {
// Beeper Desktop expects the space to exist by the time it receives
// our HTTP response. If it doesn't, then the space won't appear
// until the app is reloaded, and the toggle in the user interface
// won't respond to the user's click.
//
// Pre-bridgev2, we synchronously bridged guilds. However, this
// might take a while for guilds with many channels.
//
// To solve this, generate a deterministic room ID to use as the
// MXID so that it recognizes the guild as bridged, even if the
// portals haven't been created just yet. This lets us
// asynchronously bridge guilds while keeping the UI responsive.
mxid = p.connector.Bridge.Matrix.GenerateDeterministicRoomID(portalKey).String()
}
resp.Guilds = append(resp.Guilds, guildEntry{
ID: guild.ID,
// For now, have the ID exactly correspond to the portal ID. This
// practically means that the ID will begin with an asterisk (the
// guild portal ID sigil).
//
// Otherwise, Beeper Desktop will show a duplicate space for every
// guild, as it recognizes the guild returned from this HTTP
// endpoint and the actual space itself as separate "entities".
// (Despite this, they point to identical rooms.)
ID: string(discordid.MakeGuildPortalID(guild.ID)),
Name: guild.Name,
AvatarURL: discordgo.EndpointGuildIcon(guild.ID, guild.Icon),
MXID: mxid,
BridgingMode: "everything",
Bridged: beingBridged,
Available: !guild.Unavailable,
// v1 (legacy) backwards compat:
MXID: mxid,
AutoBridge: beingBridged,
BridgingMode: "everything",
})
}
exhttp.WriteJSONResponse(w, 200, resp)
}
// normalizeGuildID removes the guild portal sigil from a guild ID if it's
// there.
//
// This helps facilitate code that would like to accept portal keys
// corresponding to guilds as well as plain Discord guild IDs.
func normalizeGuildID(guildID string) string {
return strings.TrimPrefix(guildID, discordid.GuildPortalKeySigil)
}
func (p *ProvisioningAPI) bridgeGuild(w http.ResponseWriter, r *http.Request, login *bridgev2.UserLogin, client *DiscordClient) {
guildID := r.PathValue("guildID")
guildID := normalizeGuildID(r.PathValue("guildID"))
if guildID == "" {
mautrix.MInvalidParam.WithMessage("no guild id").Write(w)
return
@@ -192,7 +231,7 @@ func (p *ProvisioningAPI) bridgeGuild(w http.ResponseWriter, r *http.Request, lo
}
func (p *ProvisioningAPI) unbridgeGuild(w http.ResponseWriter, r *http.Request, login *bridgev2.UserLogin, client *DiscordClient) {
guildID := r.PathValue("guildID")
guildID := normalizeGuildID(r.PathValue("guildID"))
if guildID == "" {
mautrix.MInvalidParam.WithMessage("no guild id").Write(w)
return