diff --git a/mattermost/server/bathroom-linux-amd64 b/mattermost/server/bathroom-linux-amd64 index 5daaba3..7a38eb5 100755 --- a/mattermost/server/bathroom-linux-amd64 +++ b/mattermost/server/bathroom-linux-amd64 Binary files differ diff --git a/mattermost/server/bathroom-linux-amd64 b/mattermost/server/bathroom-linux-amd64 index 5daaba3..7a38eb5 100755 --- a/mattermost/server/bathroom-linux-amd64 +++ b/mattermost/server/bathroom-linux-amd64 Binary files differ diff --git a/mattermost/server/bathroom.go b/mattermost/server/bathroom.go index 642a2e1..550a50a 100644 --- a/mattermost/server/bathroom.go +++ b/mattermost/server/bathroom.go @@ -7,22 +7,46 @@ "github.com/pkg/errors" "sync" "reflect" + "github.com/google/go-cmp/cmp" + "os" + "github.com/fatih/structs" ) type Config struct { - NumDoors uint8 + 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) Init() *HelloWorldPlugin { +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; } @@ -31,19 +55,51 @@ fmt.Fprint(w, "Hello, world!") } -func (p *HelloWorldPlugin) OnConfigurationChange() error { - p.configLock.Lock() - defer p.configLock.Unlock() +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 { - // p.config = newConfig + 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 @@ -52,23 +108,22 @@ func watchLoop(p *HelloWorldPlugin) { for { p.configLock.Lock() - var restart chan struct{} = p.configChanged p.configLock.Unlock() select { - case <- restart: - p.API.LogInfo("CONFIG CHANGED, RESTARTING") + case <- p.configChanged: + p.API.LogInfo(fmt.Sprintf("CONFIG CHANGED, RESTARTING %d", p.configUpdates)) } } } func (p *HelloWorldPlugin) OnActivate() error { - //go watchLoop(p) + 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()) + plugin.ClientMain((&HelloWorldPlugin{}).init()) } diff --git a/mattermost/server/bathroom-linux-amd64 b/mattermost/server/bathroom-linux-amd64 index 5daaba3..7a38eb5 100755 --- a/mattermost/server/bathroom-linux-amd64 +++ b/mattermost/server/bathroom-linux-amd64 Binary files differ diff --git a/mattermost/server/bathroom.go b/mattermost/server/bathroom.go index 642a2e1..550a50a 100644 --- a/mattermost/server/bathroom.go +++ b/mattermost/server/bathroom.go @@ -7,22 +7,46 @@ "github.com/pkg/errors" "sync" "reflect" + "github.com/google/go-cmp/cmp" + "os" + "github.com/fatih/structs" ) type Config struct { - NumDoors uint8 + 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) Init() *HelloWorldPlugin { +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; } @@ -31,19 +55,51 @@ fmt.Fprint(w, "Hello, world!") } -func (p *HelloWorldPlugin) OnConfigurationChange() error { - p.configLock.Lock() - defer p.configLock.Unlock() +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 { - // p.config = newConfig + 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 @@ -52,23 +108,22 @@ func watchLoop(p *HelloWorldPlugin) { for { p.configLock.Lock() - var restart chan struct{} = p.configChanged p.configLock.Unlock() select { - case <- restart: - p.API.LogInfo("CONFIG CHANGED, RESTARTING") + case <- p.configChanged: + p.API.LogInfo(fmt.Sprintf("CONFIG CHANGED, RESTARTING %d", p.configUpdates)) } } } func (p *HelloWorldPlugin) OnActivate() error { - //go watchLoop(p) + 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()) + plugin.ClientMain((&HelloWorldPlugin{}).init()) } diff --git a/mattermost/server/bathroom.tar.gz b/mattermost/server/bathroom.tar.gz index 4a75780..0c9a41c 100644 --- a/mattermost/server/bathroom.tar.gz +++ b/mattermost/server/bathroom.tar.gz Binary files differ diff --git a/mattermost/server/bathroom-linux-amd64 b/mattermost/server/bathroom-linux-amd64 index 5daaba3..7a38eb5 100755 --- a/mattermost/server/bathroom-linux-amd64 +++ b/mattermost/server/bathroom-linux-amd64 Binary files differ diff --git a/mattermost/server/bathroom.go b/mattermost/server/bathroom.go index 642a2e1..550a50a 100644 --- a/mattermost/server/bathroom.go +++ b/mattermost/server/bathroom.go @@ -7,22 +7,46 @@ "github.com/pkg/errors" "sync" "reflect" + "github.com/google/go-cmp/cmp" + "os" + "github.com/fatih/structs" ) type Config struct { - NumDoors uint8 + 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) Init() *HelloWorldPlugin { +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; } @@ -31,19 +55,51 @@ fmt.Fprint(w, "Hello, world!") } -func (p *HelloWorldPlugin) OnConfigurationChange() error { - p.configLock.Lock() - defer p.configLock.Unlock() +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 { - // p.config = newConfig + 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 @@ -52,23 +108,22 @@ func watchLoop(p *HelloWorldPlugin) { for { p.configLock.Lock() - var restart chan struct{} = p.configChanged p.configLock.Unlock() select { - case <- restart: - p.API.LogInfo("CONFIG CHANGED, RESTARTING") + case <- p.configChanged: + p.API.LogInfo(fmt.Sprintf("CONFIG CHANGED, RESTARTING %d", p.configUpdates)) } } } func (p *HelloWorldPlugin) OnActivate() error { - //go watchLoop(p) + 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()) + plugin.ClientMain((&HelloWorldPlugin{}).init()) } diff --git a/mattermost/server/bathroom.tar.gz b/mattermost/server/bathroom.tar.gz index 4a75780..0c9a41c 100644 --- a/mattermost/server/bathroom.tar.gz +++ b/mattermost/server/bathroom.tar.gz Binary files differ diff --git a/mattermost/server/plugin.json b/mattermost/server/plugin.json index a02176d..51d6b8b 100644 --- a/mattermost/server/plugin.json +++ b/mattermost/server/plugin.json @@ -5,11 +5,9 @@ "executable": "bathroom-linux-amd64" }, "settings_schema": { - "header":"Header", - "footer":"Footer", "settings": [ - {"key":"NumDoors", "display_name":"Number of Door Sensors", "type":"string", "default":"1"}, - {"key":"WatchPath", "display_name":"Folder path to watch for sensor changes", "type":"string", "default":"./"} + {"key":"NumDoors", "display_name":"Number of Door Sensors", "type":"text", "default":"1", "help_text":"How many Pis"}, + {"key":"WatchPath", "display_name":"Pi status folder", "type":"text", "default":"./", "help_text":"Path to watch for doorX files updated from PHP"} ] } } diff --git a/mattermost/server/bathroom-linux-amd64 b/mattermost/server/bathroom-linux-amd64 index 5daaba3..7a38eb5 100755 --- a/mattermost/server/bathroom-linux-amd64 +++ b/mattermost/server/bathroom-linux-amd64 Binary files differ diff --git a/mattermost/server/bathroom.go b/mattermost/server/bathroom.go index 642a2e1..550a50a 100644 --- a/mattermost/server/bathroom.go +++ b/mattermost/server/bathroom.go @@ -7,22 +7,46 @@ "github.com/pkg/errors" "sync" "reflect" + "github.com/google/go-cmp/cmp" + "os" + "github.com/fatih/structs" ) type Config struct { - NumDoors uint8 + 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) Init() *HelloWorldPlugin { +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; } @@ -31,19 +55,51 @@ fmt.Fprint(w, "Hello, world!") } -func (p *HelloWorldPlugin) OnConfigurationChange() error { - p.configLock.Lock() - defer p.configLock.Unlock() +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 { - // p.config = newConfig + 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 @@ -52,23 +108,22 @@ func watchLoop(p *HelloWorldPlugin) { for { p.configLock.Lock() - var restart chan struct{} = p.configChanged p.configLock.Unlock() select { - case <- restart: - p.API.LogInfo("CONFIG CHANGED, RESTARTING") + case <- p.configChanged: + p.API.LogInfo(fmt.Sprintf("CONFIG CHANGED, RESTARTING %d", p.configUpdates)) } } } func (p *HelloWorldPlugin) OnActivate() error { - //go watchLoop(p) + 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()) + plugin.ClientMain((&HelloWorldPlugin{}).init()) } diff --git a/mattermost/server/bathroom.tar.gz b/mattermost/server/bathroom.tar.gz index 4a75780..0c9a41c 100644 --- a/mattermost/server/bathroom.tar.gz +++ b/mattermost/server/bathroom.tar.gz Binary files differ diff --git a/mattermost/server/plugin.json b/mattermost/server/plugin.json index a02176d..51d6b8b 100644 --- a/mattermost/server/plugin.json +++ b/mattermost/server/plugin.json @@ -5,11 +5,9 @@ "executable": "bathroom-linux-amd64" }, "settings_schema": { - "header":"Header", - "footer":"Footer", "settings": [ - {"key":"NumDoors", "display_name":"Number of Door Sensors", "type":"string", "default":"1"}, - {"key":"WatchPath", "display_name":"Folder path to watch for sensor changes", "type":"string", "default":"./"} + {"key":"NumDoors", "display_name":"Number of Door Sensors", "type":"text", "default":"1", "help_text":"How many Pis"}, + {"key":"WatchPath", "display_name":"Pi status folder", "type":"text", "default":"./", "help_text":"Path to watch for doorX files updated from PHP"} ] } } diff --git a/mattermost/server/setup.sh b/mattermost/server/setup.sh index f2aa708..8543827 100755 --- a/mattermost/server/setup.sh +++ b/mattermost/server/setup.sh @@ -4,3 +4,5 @@ go get -u golang.org/x/sys/... go get -u github.com/fsnotify/fsnotify go get -u github.com/pkg/errors +go get -u github.com/google/go-cmp/cmp +go get -u github.com/fatih/structs