package main import ( "fmt" "net/http" "github.com/mattermost/mattermost-server/plugin" "github.com/pkg/errors" "sync" "reflect" "github.com/google/go-cmp/cmp" "os" "github.com/fatih/structs" ) type Config struct { NumDoors uint8 `json:",string"` WatchPath string } func (c *Config) configMap() map[string]interface{} { var configMap map[string]interface{} = structs.Map(c) for k, v := range(configMap) { configMap[k] = fmt.Sprintf("%v", v) } return configMap } type HelloWorldPlugin struct { plugin.MattermostPlugin config *Config configLock sync.RWMutex configChanged chan struct{} doors map[uint8]bool configUpdates int } func (p *HelloWorldPlugin) initDoors() { p.doors = make(map[uint8]bool) for i := uint8(0); i < p.config.NumDoors; i++ { p.doors[i] = false } } func (p *HelloWorldPlugin) init() *HelloWorldPlugin { p.config = &Config{NumDoors: 1, WatchPath: "./"} p.configChanged = make(chan struct{}) p.initDoors() return p; } func (p *HelloWorldPlugin) ServeHTTP(c *plugin.Context, w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "Hello, world!") } func (p *HelloWorldPlugin) confChangedEvent() { select { case p.configChanged <- struct{}{}: default: } } func (p *HelloWorldPlugin) persistGoodConfig() { var configMap map[string]interface{} = structs.Map(p.config) for k, v := range(configMap) { configMap[k] = fmt.Sprintf("%v", v) } p.API.SavePluginConfig(configMap) } func (p *HelloWorldPlugin) OnConfigurationChange() error { var newConfig *Config = new(Config); if err := p.API.LoadPluginConfiguration(newConfig); err != nil { defer p.persistGoodConfig() return errors.Wrap(err, "failed to load configuration") } if newConfig == p.config || reflect.ValueOf(*newConfig).NumField() == 0 || cmp.Equal(*newConfig, *p.config) { defer p.persistGoodConfig() p.API.LogInfo("Passed same config, or empty?") return nil; } if _, err := os.Stat(newConfig.WatchPath); err != nil { defer p.persistGoodConfig() return errors.Wrap(err, "Invalid watch path") } p.configLock.Lock() defer p.confChangedEvent() defer p.configLock.Unlock() p.config = newConfig p.configUpdates++ p.initDoors() p.API.LogInfo(fmt.Sprintf("Config: %d %s", p.config.NumDoors, p.config.WatchPath)) return nil } func watchLoop(p *HelloWorldPlugin) { for { p.configLock.Lock() p.configLock.Unlock() select { case <- p.configChanged: p.API.LogInfo(fmt.Sprintf("CONFIG CHANGED, RESTARTING %d", p.configUpdates)) } } } func (p *HelloWorldPlugin) OnActivate() error { go watchLoop(p) return nil } // This example demonstrates a plugin that handles HTTP requests which respond by greeting the // world. func main() { plugin.ClientMain((&HelloWorldPlugin{}).init()) }