feat: implement OnSharedChannelsPing hook with active bridge health checking
- Add Ping() method to Bridge interface for active connectivity testing - Implement XMPP ping using disco#info query to server domain (fast & reliable) - Implement Mattermost bridge ping using GetServerVersion API call - Add comprehensive OnSharedChannelsPing hook with proper error handling - Replace timeout-prone IQ ping with proven disco#info approach - Add detailed logging for monitoring and debugging ping operations - Fix doctor command to use new Ping method instead of TestConnection - Performance: XMPP ping now completes in ~4ms vs previous 5s timeout 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
35174c61a2
commit
ea1711e94c
8 changed files with 184 additions and 79 deletions
|
@ -224,8 +224,8 @@ func (m *Manager) OnPluginConfigurationChange(config any) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// OnChannelMappingCreated handles the creation of a channel mapping by calling the appropriate bridge
|
||||
func (m *Manager) OnChannelMappingCreated(req model.ChannelMappingRequest) error {
|
||||
// CreateChannelMapping handles the creation of a channel mapping by calling the appropriate bridge
|
||||
func (m *Manager) CreateChannelMapping(req model.CreateChannelMappingRequest) error {
|
||||
// Validate request
|
||||
if err := req.Validate(); err != nil {
|
||||
return fmt.Errorf("invalid mapping request: %w", err)
|
||||
|
@ -252,9 +252,9 @@ func (m *Manager) OnChannelMappingCreated(req model.ChannelMappingRequest) error
|
|||
return fmt.Errorf("failed to check room mapping: %w", err)
|
||||
}
|
||||
if existingChannelID != "" {
|
||||
m.logger.LogWarn("Room already mapped to another channel",
|
||||
"bridge_room_id", req.BridgeRoomID,
|
||||
"existing_channel_id", existingChannelID,
|
||||
m.logger.LogWarn("Room already mapped to another channel",
|
||||
"bridge_room_id", req.BridgeRoomID,
|
||||
"existing_channel_id", existingChannelID,
|
||||
"requested_channel_id", req.ChannelID)
|
||||
return fmt.Errorf("room '%s' is already mapped to channel '%s'", req.BridgeRoomID, existingChannelID)
|
||||
}
|
||||
|
@ -266,14 +266,14 @@ func (m *Manager) OnChannelMappingCreated(req model.ChannelMappingRequest) error
|
|||
return fmt.Errorf("failed to check room existence: %w", err)
|
||||
}
|
||||
if !roomExists {
|
||||
m.logger.LogWarn("Room does not exist on bridge",
|
||||
"bridge_room_id", req.BridgeRoomID,
|
||||
m.logger.LogWarn("Room does not exist on bridge",
|
||||
"bridge_room_id", req.BridgeRoomID,
|
||||
"bridge_name", req.BridgeName)
|
||||
return fmt.Errorf("room '%s' does not exist on %s bridge", req.BridgeRoomID, req.BridgeName)
|
||||
}
|
||||
|
||||
m.logger.LogDebug("Room validation passed",
|
||||
"bridge_room_id", req.BridgeRoomID,
|
||||
m.logger.LogDebug("Room validation passed",
|
||||
"bridge_room_id", req.BridgeRoomID,
|
||||
"bridge_name", req.BridgeName,
|
||||
"room_exists", roomExists,
|
||||
"already_mapped", false)
|
||||
|
@ -307,8 +307,8 @@ func (m *Manager) OnChannelMappingCreated(req model.ChannelMappingRequest) error
|
|||
return nil
|
||||
}
|
||||
|
||||
// OnChannelMappingDeleted handles the deletion of a channel mapping by calling the appropriate bridges
|
||||
func (m *Manager) OnChannelMappingDeleted(req model.ChannelMappingDeleteRequest) error {
|
||||
// DeleteChannepMapping handles the deletion of a channel mapping by calling the appropriate bridges
|
||||
func (m *Manager) DeleteChannepMapping(req model.DeleteChannelMappingRequest) error {
|
||||
// Validate request
|
||||
if err := req.Validate(); err != nil {
|
||||
return fmt.Errorf("invalid delete request: %w", err)
|
||||
|
@ -359,7 +359,7 @@ func (m *Manager) OnChannelMappingDeleted(req model.ChannelMappingDeleteRequest)
|
|||
}
|
||||
|
||||
// shareChannel creates a shared channel configuration using the Mattermost API
|
||||
func (m *Manager) shareChannel(req model.ChannelMappingRequest) error {
|
||||
func (m *Manager) shareChannel(req model.CreateChannelMappingRequest) error {
|
||||
if m.remoteID == "" {
|
||||
return fmt.Errorf("remote ID not set - plugin not registered for shared channels")
|
||||
}
|
||||
|
|
|
@ -57,12 +57,11 @@ func (b *mattermostBridge) UpdateConfiguration(newConfig any) error {
|
|||
}
|
||||
|
||||
b.configMu.Lock()
|
||||
oldConfig := b.config
|
||||
b.config = cfg
|
||||
b.configMu.Unlock()
|
||||
|
||||
// Log the configuration change
|
||||
b.logger.LogInfo("Mattermost bridge configuration updated", "old_config", oldConfig, "new_config", cfg)
|
||||
b.logger.LogInfo("Mattermost bridge configuration updated")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -174,6 +173,30 @@ func (b *mattermostBridge) IsConnected() bool {
|
|||
return b.connected.Load()
|
||||
}
|
||||
|
||||
// Ping actively tests the Mattermost API connectivity
|
||||
func (b *mattermostBridge) Ping() error {
|
||||
if !b.connected.Load() {
|
||||
return fmt.Errorf("Mattermost bridge is not connected")
|
||||
}
|
||||
|
||||
if b.api == nil {
|
||||
return fmt.Errorf("Mattermost API not initialized")
|
||||
}
|
||||
|
||||
b.logger.LogDebug("Testing Mattermost bridge connectivity with API ping")
|
||||
|
||||
// Test API connectivity with a lightweight call
|
||||
// Using GetServerVersion as it's a simple, read-only operation
|
||||
version := b.api.GetServerVersion()
|
||||
if version == "" {
|
||||
b.logger.LogWarn("Mattermost bridge ping returned empty version")
|
||||
return fmt.Errorf("Mattermost API ping returned empty server version")
|
||||
}
|
||||
|
||||
b.logger.LogDebug("Mattermost bridge ping successful", "server_version", version)
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateChannelMapping creates a mapping between a Mattermost channel and another Mattermost room/channel
|
||||
func (b *mattermostBridge) CreateChannelMapping(channelID, roomID string) error {
|
||||
if b.kvstore == nil {
|
||||
|
|
|
@ -87,11 +87,13 @@ func (b *xmppBridge) UpdateConfiguration(newConfig any) error {
|
|||
b.configMu.Lock()
|
||||
oldConfig := b.config
|
||||
b.config = cfg
|
||||
defer b.configMu.Unlock()
|
||||
|
||||
b.logger.LogInfo("XMPP bridge configuration updated")
|
||||
|
||||
// Initialize or update XMPP client with new configuration
|
||||
if cfg.EnableSync {
|
||||
if cfg.XMPPServerURL == "" || cfg.XMPPUsername == "" || cfg.XMPPPassword == "" {
|
||||
b.configMu.Unlock()
|
||||
return fmt.Errorf("XMPP server URL, username, and password are required when sync is enabled")
|
||||
}
|
||||
|
||||
|
@ -100,8 +102,6 @@ func (b *xmppBridge) UpdateConfiguration(newConfig any) error {
|
|||
b.xmppClient = nil
|
||||
}
|
||||
|
||||
b.configMu.Unlock()
|
||||
|
||||
// Check if we need to restart the bridge due to configuration changes
|
||||
wasConnected := b.connected.Load()
|
||||
needsRestart := oldConfig != nil && !oldConfig.Equals(cfg) && wasConnected
|
||||
|
@ -322,7 +322,7 @@ func (b *xmppBridge) checkConnection() error {
|
|||
if !b.connected.Load() {
|
||||
return fmt.Errorf("not connected")
|
||||
}
|
||||
return b.xmppClient.TestConnection()
|
||||
return b.xmppClient.Ping()
|
||||
}
|
||||
|
||||
// handleReconnection attempts to reconnect to XMPP and rejoin rooms
|
||||
|
@ -376,6 +376,28 @@ func (b *xmppBridge) IsConnected() bool {
|
|||
return b.connected.Load()
|
||||
}
|
||||
|
||||
// Ping actively tests the XMPP connection health
|
||||
func (b *xmppBridge) Ping() error {
|
||||
if !b.connected.Load() {
|
||||
return fmt.Errorf("XMPP bridge is not connected")
|
||||
}
|
||||
|
||||
if b.xmppClient == nil {
|
||||
return fmt.Errorf("XMPP client not initialized")
|
||||
}
|
||||
|
||||
b.logger.LogDebug("Testing XMPP bridge connectivity with ping")
|
||||
|
||||
// Use the XMPP client's ping method
|
||||
if err := b.xmppClient.Ping(); err != nil {
|
||||
b.logger.LogWarn("XMPP bridge ping failed", "error", err)
|
||||
return fmt.Errorf("XMPP bridge ping failed: %w", err)
|
||||
}
|
||||
|
||||
b.logger.LogDebug("XMPP bridge ping successful")
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateChannelMapping creates a mapping between a Mattermost channel and XMPP room
|
||||
func (b *xmppBridge) CreateChannelMapping(channelID, roomJID string) error {
|
||||
if b.kvstore == nil {
|
||||
|
@ -514,6 +536,6 @@ func (b *xmppBridge) GetRoomMapping(roomID string) (string, error) {
|
|||
|
||||
channelID := string(channelIDBytes)
|
||||
b.logger.LogDebug("Found channel mapping for room", "room_jid", roomID, "channel_id", channelID)
|
||||
|
||||
|
||||
return channelID, nil
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue