This commit implements a complete multi-user bridge management system that allows bridges to control multiple users with async goroutine management and convenience methods for channel operations. Key features: - Bridge-agnostic BridgeUser interface with validation, identity, state management, channel operations, connection lifecycle, and goroutine lifecycle methods - BridgeUserManager interface for user lifecycle management with bridge type identification - XMPPUser implementation for XMPP bridge with XMPP client integration, connection monitoring, and room operations - MattermostUser implementation for Mattermost bridge with API integration and channel management - Updated Bridge interface to include GetUserManager() method - Base UserManager implementation with generic user management logic - Added Ping() and CheckChannelExists() methods to BridgeUser interface for health checking and room validation - Updated bridge manager naming from Manager to BridgeManager for clarity The system enables bridges to manage multiple users (like "Mattermost Bridge" user in XMPP) with proper state management, connection monitoring, and channel operations abstracted across different bridge protocols. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
188 lines
5 KiB
Go
188 lines
5 KiB
Go
package bridge
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sync"
|
|
|
|
"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/model"
|
|
)
|
|
|
|
// Manager implements the BridgeUserManager interface with bridge-agnostic logic
|
|
type UserManager struct {
|
|
bridgeType string
|
|
logger logger.Logger
|
|
users map[string]model.BridgeUser
|
|
mu sync.RWMutex
|
|
ctx context.Context
|
|
cancel context.CancelFunc
|
|
}
|
|
|
|
// NewUserManager creates a new user manager for a specific bridge type
|
|
func NewUserManager(bridgeType string, logger logger.Logger) model.BridgeUserManager {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
return &UserManager{
|
|
bridgeType: bridgeType,
|
|
logger: logger,
|
|
users: make(map[string]model.BridgeUser),
|
|
ctx: ctx,
|
|
cancel: cancel,
|
|
}
|
|
}
|
|
|
|
// CreateUser adds a user to the bridge system
|
|
func (m *UserManager) CreateUser(user model.BridgeUser) error {
|
|
// Validate the user first
|
|
if err := user.Validate(); err != nil {
|
|
return fmt.Errorf("invalid user: %w", err)
|
|
}
|
|
|
|
userID := user.GetID()
|
|
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
|
|
// Check if user already exists
|
|
if _, exists := m.users[userID]; exists {
|
|
return fmt.Errorf("user %s already exists", userID)
|
|
}
|
|
|
|
m.logger.LogDebug("Adding bridge user", "bridge_type", m.bridgeType, "user_id", userID, "display_name", user.GetDisplayName())
|
|
|
|
// Store the user
|
|
m.users[userID] = user
|
|
|
|
m.logger.LogInfo("Bridge user added successfully", "bridge_type", m.bridgeType, "user_id", userID)
|
|
return nil
|
|
}
|
|
|
|
// GetUser retrieves a user by ID
|
|
func (m *UserManager) GetUser(userID string) (model.BridgeUser, error) {
|
|
m.mu.RLock()
|
|
defer m.mu.RUnlock()
|
|
|
|
user, exists := m.users[userID]
|
|
if !exists {
|
|
return nil, fmt.Errorf("user %s not found", userID)
|
|
}
|
|
|
|
return user, nil
|
|
}
|
|
|
|
// DeleteUser removes a user from the bridge system
|
|
func (m *UserManager) DeleteUser(userID string) error {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
|
|
user, exists := m.users[userID]
|
|
if !exists {
|
|
return fmt.Errorf("user %s not found", userID)
|
|
}
|
|
|
|
m.logger.LogDebug("Deleting bridge user", "bridge_type", m.bridgeType, "user_id", userID)
|
|
|
|
// Stop the user first
|
|
if err := user.Stop(); err != nil {
|
|
m.logger.LogWarn("Error stopping user during deletion", "bridge_type", m.bridgeType, "user_id", userID, "error", err)
|
|
}
|
|
|
|
// Disconnect if still connected
|
|
if user.IsConnected() {
|
|
if err := user.Disconnect(); err != nil {
|
|
m.logger.LogWarn("Error disconnecting user during deletion", "bridge_type", m.bridgeType, "user_id", userID, "error", err)
|
|
}
|
|
}
|
|
|
|
// Remove from map
|
|
delete(m.users, userID)
|
|
|
|
m.logger.LogInfo("Bridge user deleted successfully", "bridge_type", m.bridgeType, "user_id", userID)
|
|
return nil
|
|
}
|
|
|
|
// ListUsers returns a list of all users
|
|
func (m *UserManager) ListUsers() []model.BridgeUser {
|
|
m.mu.RLock()
|
|
defer m.mu.RUnlock()
|
|
|
|
users := make([]model.BridgeUser, 0, len(m.users))
|
|
for _, user := range m.users {
|
|
users = append(users, user)
|
|
}
|
|
|
|
return users
|
|
}
|
|
|
|
// HasUser checks if a user exists
|
|
func (m *UserManager) HasUser(userID string) bool {
|
|
m.mu.RLock()
|
|
defer m.mu.RUnlock()
|
|
|
|
_, exists := m.users[userID]
|
|
return exists
|
|
}
|
|
|
|
// Start initializes the user manager
|
|
func (m *UserManager) Start(ctx context.Context) error {
|
|
m.logger.LogDebug("Starting user manager", "bridge_type", m.bridgeType)
|
|
|
|
// Update context
|
|
m.ctx = ctx
|
|
|
|
// Start all existing users
|
|
m.mu.RLock()
|
|
defer m.mu.RUnlock()
|
|
|
|
for userID, user := range m.users {
|
|
if err := user.Start(ctx); err != nil {
|
|
m.logger.LogWarn("Failed to start user during manager startup", "bridge_type", m.bridgeType, "user_id", userID, "error", err)
|
|
// Continue starting other users even if one fails
|
|
}
|
|
}
|
|
|
|
m.logger.LogInfo("User manager started", "bridge_type", m.bridgeType, "user_count", len(m.users))
|
|
return nil
|
|
}
|
|
|
|
// Stop shuts down the user manager
|
|
func (m *UserManager) Stop() error {
|
|
m.logger.LogDebug("Stopping user manager", "bridge_type", m.bridgeType)
|
|
|
|
if m.cancel != nil {
|
|
m.cancel()
|
|
}
|
|
|
|
// Stop all users
|
|
m.mu.RLock()
|
|
users := make([]model.BridgeUser, 0, len(m.users))
|
|
for _, user := range m.users {
|
|
users = append(users, user)
|
|
}
|
|
m.mu.RUnlock()
|
|
|
|
for _, user := range users {
|
|
if err := user.Stop(); err != nil {
|
|
m.logger.LogWarn("Error stopping user during manager shutdown", "bridge_type", m.bridgeType, "user_id", user.GetID(), "error", err)
|
|
}
|
|
}
|
|
|
|
m.logger.LogInfo("User manager stopped", "bridge_type", m.bridgeType)
|
|
return nil
|
|
}
|
|
|
|
// UpdateConfiguration updates configuration for all users
|
|
func (m *UserManager) UpdateConfiguration(cfg *config.Configuration) error {
|
|
m.logger.LogDebug("Updating configuration for user manager", "bridge_type", m.bridgeType)
|
|
|
|
// For now, we don't propagate config changes to individual users
|
|
// This can be extended later if needed
|
|
m.logger.LogInfo("User manager configuration updated", "bridge_type", m.bridgeType)
|
|
return nil
|
|
}
|
|
|
|
// GetBridgeType returns the bridge type this manager handles
|
|
func (m *UserManager) GetBridgeType() string {
|
|
return m.bridgeType
|
|
}
|