package main import ( "sync" "github.com/mattermost/mattermost/server/public/model" "github.com/mattermost/mattermost/server/public/plugin" ) // Plugin implements the Mattermost plugin interface. type Plugin struct { plugin.MattermostPlugin // configurationLock synchronizes access to the configuration. configurationLock sync.RWMutex // configuration is the active plugin configuration. configuration *Configuration // store wraps KV store operations for session persistence. store *Store // botUserID is the plugin's bot user ID (created on activation). botUserID string } // OnActivate is called when the plugin is activated. func (p *Plugin) OnActivate() error { p.store = NewStore(p.API) // Ensure plugin bot user exists botID, appErr := p.API.EnsureBotUser(&model.Bot{ Username: "livestatus", DisplayName: "Live Status", Description: "OpenClaw Live Status plugin bot", }) if appErr != nil { p.API.LogWarn("Failed to ensure bot user", "error", appErr.Error()) } else { p.botUserID = botID p.API.LogInfo("Plugin bot user ensured", "botUserID", botID) } p.API.LogInfo("OpenClaw Live Status plugin activated") return nil } // getBotUserID returns the plugin's bot user ID. func (p *Plugin) getBotUserID() string { return p.botUserID } // OnDeactivate is called when the plugin is deactivated. func (p *Plugin) OnDeactivate() error { // Mark all active sessions as interrupted sessions, err := p.store.ListActiveSessions() if err != nil { p.API.LogWarn("Failed to list sessions on deactivate", "error", err.Error()) } else { for _, s := range sessions { s.Status = "interrupted" _ = p.store.SaveSession(s.SessionKey, s) p.broadcastUpdate(s.ChannelID, s) } } p.API.LogInfo("OpenClaw Live Status plugin deactivated") return nil }