feat: restore XMPP bridge to use direct client connection instead of bridge user
Some checks are pending
ci / plugin-ci (push) Waiting to run

- Replace bridgeUser with bridgeClient (*xmppClient.Client) in XMPP bridge
- Update createXMPPClient to return XMPP client with TLS configuration
- Migrate connection, disconnection, and room operations to use bridgeClient
- Update Ping() and RoomExists() methods to use client methods directly
- Maintain bridge-agnostic user management system for additional users
- Fix formatting and import organization across bridge components

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Felipe M 2025-08-04 18:04:10 +02:00
parent db8037ffbf
commit 65038fb7a2
No known key found for this signature in database
GPG key ID: 52E5D65FCF99808A
6 changed files with 101 additions and 87 deletions

View file

@ -2,6 +2,7 @@ package xmpp
import ( import (
"context" "context"
"crypto/tls"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
@ -11,9 +12,9 @@ import (
"github.com/mattermost/mattermost-plugin-bridge-xmpp/server/bridge" "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/bridge"
"github.com/mattermost/mattermost-plugin-bridge-xmpp/server/config" "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/config"
"github.com/mattermost/mattermost-plugin-bridge-xmpp/server/logger" "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/logger"
"github.com/mattermost/mattermost-plugin-bridge-xmpp/server/model"
pluginModel "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/model" pluginModel "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/model"
"github.com/mattermost/mattermost-plugin-bridge-xmpp/server/store/kvstore" "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/store/kvstore"
xmppClient "github.com/mattermost/mattermost-plugin-bridge-xmpp/server/xmpp"
"github.com/mattermost/mattermost/server/public/plugin" "github.com/mattermost/mattermost/server/public/plugin"
) )
@ -22,7 +23,7 @@ type xmppBridge struct {
logger logger.Logger logger logger.Logger
api plugin.API api plugin.API
kvstore kvstore.KVStore kvstore kvstore.KVStore
bridgeUser model.BridgeUser // Handles the bridge user and main bridge XMPP connection bridgeClient *xmppClient.Client // Main bridge XMPP client connection
userManager pluginModel.BridgeUserManager userManager pluginModel.BridgeUserManager
// Connection management // Connection management
@ -55,15 +56,28 @@ func NewBridge(log logger.Logger, api plugin.API, kvstore kvstore.KVStore, cfg *
// Initialize XMPP client with configuration // Initialize XMPP client with configuration
if cfg.EnableSync && cfg.XMPPServerURL != "" && cfg.XMPPUsername != "" && cfg.XMPPPassword != "" { if cfg.EnableSync && cfg.XMPPServerURL != "" && cfg.XMPPUsername != "" && cfg.XMPPPassword != "" {
b.bridgeUser = b.createXMPPClient(cfg) b.bridgeClient = b.createXMPPClient(cfg)
} }
return b return b
} }
// createXMPPClient creates an XMPP client with the given configuration // createXMPPClient creates an XMPP client with the given configuration
func (b *xmppBridge) createXMPPClient(cfg *config.Configuration) model.BridgeUser { func (b *xmppBridge) createXMPPClient(cfg *config.Configuration) *xmppClient.Client {
return NewXMPPUser("_bridge_", "Bridge User", cfg.XMPPUsername, cfg, b.logger) // Create TLS config based on certificate verification setting
tlsConfig := &tls.Config{
InsecureSkipVerify: cfg.XMPPInsecureSkipVerify,
}
return xmppClient.NewClientWithTLS(
cfg.XMPPServerURL,
cfg.XMPPUsername,
cfg.XMPPPassword,
cfg.GetXMPPResource(),
"", // remoteID not needed for bridge client
tlsConfig,
b.logger,
)
} }
// UpdateConfiguration updates the bridge configuration // UpdateConfiguration updates the bridge configuration
@ -86,9 +100,9 @@ func (b *xmppBridge) UpdateConfiguration(newConfig any) error {
return fmt.Errorf("XMPP server URL, username, and password are required when sync is enabled") return fmt.Errorf("XMPP server URL, username, and password are required when sync is enabled")
} }
b.bridgeUser = b.createXMPPClient(cfg) b.bridgeClient = b.createXMPPClient(cfg)
} else { } else {
b.bridgeUser = nil b.bridgeClient = nil
} }
// Check if we need to restart the bridge due to configuration changes // Check if we need to restart the bridge due to configuration changes
@ -164,8 +178,8 @@ func (b *xmppBridge) Stop() error {
b.cancel() b.cancel()
} }
if b.bridgeUser != nil { if b.bridgeClient != nil {
if err := b.bridgeUser.Disconnect(); err != nil { if err := b.bridgeClient.Disconnect(); err != nil {
b.logger.LogWarn("Error disconnecting from XMPP server", "error", err) b.logger.LogWarn("Error disconnecting from XMPP server", "error", err)
} }
} }
@ -177,13 +191,13 @@ func (b *xmppBridge) Stop() error {
// connectToXMPP establishes connection to the XMPP server // connectToXMPP establishes connection to the XMPP server
func (b *xmppBridge) connectToXMPP() error { func (b *xmppBridge) connectToXMPP() error {
if b.bridgeUser == nil { if b.bridgeClient == nil {
return fmt.Errorf("XMPP client is not initialized") return fmt.Errorf("XMPP client is not initialized")
} }
b.logger.LogDebug("Connecting to XMPP server") b.logger.LogDebug("Connecting to XMPP server")
err := b.bridgeUser.Connect() err := b.bridgeClient.Connect()
if err != nil { if err != nil {
b.connected.Store(false) b.connected.Store(false)
return fmt.Errorf("failed to connect to XMPP server: %w", err) return fmt.Errorf("failed to connect to XMPP server: %w", err)
@ -193,11 +207,11 @@ func (b *xmppBridge) connectToXMPP() error {
b.logger.LogInfo("Successfully connected to XMPP server") b.logger.LogInfo("Successfully connected to XMPP server")
// Set online presence after successful connection // Set online presence after successful connection
if err := b.bridgeUser.SetState(pluginModel.UserStateOnline); err != nil { if err := b.bridgeClient.SetOnlinePresence(); err != nil {
b.logger.LogWarn("Failed to set online presence", "error", err) b.logger.LogWarn("Failed to set online presence", "error", err)
// Don't fail the connection for presence issues // Don't fail the connection for presence issues
} else { } else {
b.logger.LogDebug("Set bridge user online presence") b.logger.LogDebug("Set bridge client online presence")
} }
return nil return nil
@ -236,7 +250,7 @@ func (b *xmppBridge) joinXMPPRoom(channelID, roomJID string) error {
return fmt.Errorf("not connected to XMPP server") return fmt.Errorf("not connected to XMPP server")
} }
err := b.bridgeUser.JoinChannel(roomJID) err := b.bridgeClient.JoinRoom(roomJID)
if err != nil { if err != nil {
return fmt.Errorf("failed to join XMPP room: %w", err) return fmt.Errorf("failed to join XMPP room: %w", err)
} }
@ -319,8 +333,8 @@ func (b *xmppBridge) handleReconnection() {
b.logger.LogInfo("Attempting to reconnect to XMPP server") b.logger.LogInfo("Attempting to reconnect to XMPP server")
b.connected.Store(false) b.connected.Store(false)
if b.bridgeUser != nil { if b.bridgeClient != nil {
_ = b.bridgeUser.Disconnect() _ = b.bridgeClient.Disconnect()
} }
// Retry connection with exponential backoff // Retry connection with exponential backoff
@ -363,14 +377,14 @@ func (b *xmppBridge) Ping() error {
return fmt.Errorf("XMPP bridge is not connected") return fmt.Errorf("XMPP bridge is not connected")
} }
if b.bridgeUser == nil { if b.bridgeClient == nil {
return fmt.Errorf("XMPP client not initialized") return fmt.Errorf("XMPP client not initialized")
} }
b.logger.LogDebug("Testing XMPP bridge connectivity with ping") b.logger.LogDebug("Testing XMPP bridge connectivity with ping")
// Use the XMPP user's ping method // Use the XMPP client's ping method
if err := b.bridgeUser.Ping(); err != nil { if err := b.bridgeClient.Ping(); err != nil {
b.logger.LogWarn("XMPP bridge ping failed", "error", err) b.logger.LogWarn("XMPP bridge ping failed", "error", err)
return fmt.Errorf("XMPP bridge ping failed: %w", err) return fmt.Errorf("XMPP bridge ping failed: %w", err)
} }
@ -397,7 +411,7 @@ func (b *xmppBridge) CreateChannelMapping(channelID, roomJID string) error {
// Join the room if connected // Join the room if connected
if b.connected.Load() { if b.connected.Load() {
if err := b.bridgeUser.JoinChannel(roomJID); err != nil { if err := b.bridgeClient.JoinRoom(roomJID); err != nil {
b.logger.LogWarn("Failed to join newly mapped room", "channel_id", channelID, "room_jid", roomJID, "error", err) b.logger.LogWarn("Failed to join newly mapped room", "channel_id", channelID, "room_jid", roomJID, "error", err)
} }
} }
@ -463,8 +477,8 @@ func (b *xmppBridge) DeleteChannelMapping(channelID string) error {
b.mappingsMu.Unlock() b.mappingsMu.Unlock()
// Leave the room if connected // Leave the room if connected
if b.connected.Load() && b.bridgeUser != nil { if b.connected.Load() && b.bridgeClient != nil {
if err := b.bridgeUser.LeaveChannel(roomJID); err != nil { if err := b.bridgeClient.LeaveRoom(roomJID); err != nil {
b.logger.LogWarn("Failed to leave unmapped room", "channel_id", channelID, "room_jid", roomJID, "error", err) b.logger.LogWarn("Failed to leave unmapped room", "channel_id", channelID, "room_jid", roomJID, "error", err)
// Don't fail the entire operation if leaving the room fails // Don't fail the entire operation if leaving the room fails
} else { } else {
@ -482,14 +496,14 @@ func (b *xmppBridge) RoomExists(roomID string) (bool, error) {
return false, fmt.Errorf("not connected to XMPP server") return false, fmt.Errorf("not connected to XMPP server")
} }
if b.bridgeUser == nil { if b.bridgeClient == nil {
return false, fmt.Errorf("XMPP client not initialized") return false, fmt.Errorf("XMPP client not initialized")
} }
b.logger.LogDebug("Checking if XMPP room exists", "room_jid", roomID) b.logger.LogDebug("Checking if XMPP room exists", "room_jid", roomID)
// Use the XMPP user to check room existence // Use the XMPP client to check room existence
exists, err := b.bridgeUser.CheckChannelExists(roomID) exists, err := b.bridgeClient.CheckRoomExists(roomID)
if err != nil { if err != nil {
b.logger.LogError("Failed to check room existence", "room_jid", roomID, "error", err) b.logger.LogError("Failed to check room existence", "room_jid", roomID, "error", err)
return false, fmt.Errorf("failed to check room existence: %w", err) return false, fmt.Errorf("failed to check room existence: %w", err)