feat: implement bidirectional message bridge system with XMPP-Mattermost integration

This commit implements a comprehensive bridge-agnostic message routing system that enables
real-time bidirectional message synchronization between XMPP and Mattermost platforms.

Key features:
- Bridge-agnostic message types and structures for extensibility
- Central message bus system with publisher-subscriber pattern
- Complete Bridge interface implementation for both XMPP and Mattermost
- Message aggregation from multiple sources for scalability
- Loop prevention mechanisms to avoid infinite message cycles
- Buffered channels for high-performance message processing

Architecture highlights:
- Producer-consumer pattern for message routing between bridges
- Thread-safe goroutine lifecycle management with context cancellation
- Message handlers separated into dedicated files for maintainability
- Support for future bridge implementations (Slack, Discord, etc.)
- Markdown content standardization across all bridges

Files added:
- server/model/message.go: Core bridge-agnostic message structures
- server/bridge/messagebus.go: Central message routing system
- server/bridge/mattermost/message_handler.go: Mattermost-specific message processing
- server/bridge/xmpp/message_handler.go: XMPP-specific message processing

Files modified:
- server/bridge/manager.go: Integration with message bus and routing
- server/bridge/mattermost/bridge.go: Complete Bridge interface implementation
- server/bridge/xmpp/bridge.go: Message aggregation and interface completion
- server/model/bridge.go: Extended Bridge interface for bidirectional messaging
- server/xmpp/client.go: Enhanced message listening with mellium.im/xmpp

🤖 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 21:52:28 +02:00
parent 69a67704f4
commit 7b56cb34c6
No known key found for this signature in database
GPG key ID: 52E5D65FCF99808A
9 changed files with 1119 additions and 41 deletions

View file

@ -14,6 +14,11 @@ import (
"github.com/mattermost/mattermost/server/public/plugin"
)
const (
// defaultMessageBufferSize is the buffer size for incoming message channels
defaultMessageBufferSize = 1000
)
// mattermostBridge handles syncing messages between Mattermost instances
type mattermostBridge struct {
logger logger.Logger
@ -21,6 +26,11 @@ type mattermostBridge struct {
kvstore kvstore.KVStore
userManager pluginModel.BridgeUserManager
// Message handling
messageHandler *mattermostMessageHandler
userResolver *mattermostUserResolver
incomingMessages chan *pluginModel.DirectionalMessage
// Connection management
connected atomic.Bool
ctx context.Context
@ -38,18 +48,23 @@ type mattermostBridge struct {
// NewBridge creates a new Mattermost bridge
func NewBridge(log logger.Logger, api plugin.API, kvstore kvstore.KVStore, cfg *config.Configuration) pluginModel.Bridge {
ctx, cancel := context.WithCancel(context.Background())
bridge := &mattermostBridge{
logger: log,
api: api,
kvstore: kvstore,
ctx: ctx,
cancel: cancel,
channelMappings: make(map[string]string),
config: cfg,
userManager: bridge.NewUserManager("mattermost", log),
b := &mattermostBridge{
logger: log,
api: api,
kvstore: kvstore,
ctx: ctx,
cancel: cancel,
channelMappings: make(map[string]string),
config: cfg,
userManager: bridge.NewUserManager("mattermost", log),
incomingMessages: make(chan *pluginModel.DirectionalMessage, defaultMessageBufferSize),
}
return bridge
// Initialize handlers after bridge is created
b.messageHandler = newMessageHandler(b)
b.userResolver = newUserResolver(b)
return b
}
// getConfiguration safely retrieves the current configuration
@ -343,3 +358,23 @@ func (b *mattermostBridge) GetRoomMapping(roomID string) (string, error) {
func (b *mattermostBridge) GetUserManager() pluginModel.BridgeUserManager {
return b.userManager
}
// GetMessageChannel returns the channel for incoming messages from Mattermost
func (b *mattermostBridge) GetMessageChannel() <-chan *pluginModel.DirectionalMessage {
return b.incomingMessages
}
// SendMessage sends a message to a Mattermost channel
func (b *mattermostBridge) SendMessage(msg *pluginModel.BridgeMessage) error {
return b.messageHandler.postMessageToMattermost(msg)
}
// GetMessageHandler returns the message handler for this bridge
func (b *mattermostBridge) GetMessageHandler() pluginModel.MessageHandler {
return b.messageHandler
}
// GetUserResolver returns the user resolver for this bridge
func (b *mattermostBridge) GetUserResolver() pluginModel.UserResolver {
return b.userResolver
}