Initial commit.
This commit is contained in:
commit
63539b5bc1
9 changed files with 401 additions and 0 deletions
121
cmd/smartswitch-server/main.go
Normal file
121
cmd/smartswitch-server/main.go
Normal file
|
@ -0,0 +1,121 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
type webhook struct {
|
||||
Name string
|
||||
Path string
|
||||
SecretKey string `yaml:"secret_key"`
|
||||
NumSwitches int `yaml:"num_switches"`
|
||||
MomentarySwitches []int `yaml:"momentary_switches"`
|
||||
SwitchStates []int `json:switch_states`
|
||||
}
|
||||
|
||||
func debug(msg string, args ...interface{}) {
|
||||
if viper.GetBool("Debug") {
|
||||
log.Printf(msg, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func initWebhooks(filename string) {
|
||||
bytes, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
log.Panicf("Couldn't read config file: %s", err)
|
||||
}
|
||||
|
||||
var hooks []webhook
|
||||
|
||||
err = yaml.Unmarshal(bytes, &hooks)
|
||||
if err != nil {
|
||||
log.Panicf("Couldn't parse webhook file: %v", err)
|
||||
}
|
||||
|
||||
debug("Webhook definitions:")
|
||||
debug("%v", hooks)
|
||||
|
||||
for _, v := range hooks {
|
||||
v.SwitchStates = make([]int, v.NumSwitches)
|
||||
http.HandleFunc("/"+v.Path, makeWebhookHandler(v))
|
||||
}
|
||||
}
|
||||
|
||||
func runServer() {
|
||||
http.ListenAndServe(":"+viper.GetString("ListenPort"), nil)
|
||||
}
|
||||
|
||||
func makeWebhookHandler(hook webhook) func(http.ResponseWriter, *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// authentication check
|
||||
keys, ok := r.URL.Query()["key"]
|
||||
if !ok || len(keys) == 0 {
|
||||
log.Printf("No key found for webhook: %s", hook.Name)
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
providedKey := keys[0]
|
||||
|
||||
if providedKey == "" || providedKey != hook.SecretKey {
|
||||
log.Printf("Failed to authenticate request for webhook: %s", hook.Name)
|
||||
debug("Got key '%s', expected key '%s'", providedKey, hook.SecretKey)
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// now actually handle the request
|
||||
if r.Method == "GET" {
|
||||
webhookRead(hook, w, r)
|
||||
|
||||
} else if r.Method == "POST" {
|
||||
webhookWrite(hook, w, r)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func webhookRead(hook webhook, w http.ResponseWriter, r *http.Request) {
|
||||
err := json.NewEncoder(w).Encode(hook.SwitchStates)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Failed to send response: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// momentary switches have been read, so make sure they're 0
|
||||
// next time
|
||||
for _, i := range hook.MomentarySwitches {
|
||||
hook.SwitchStates[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
func webhookWrite(hook webhook, w http.ResponseWriter, r *http.Request) {
|
||||
err := json.NewDecoder(r.Body).Decode(&hook.SwitchStates)
|
||||
if err != nil {
|
||||
log.Printf("Failed to parse json for '%s': %v", hook.Name, err)
|
||||
http.Error(w, "Failed to parse json", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
// read environment config
|
||||
viper.BindEnv("Debug", "DEBUG")
|
||||
viper.BindEnv("WebhookFile", "WEBHOOK_CONFIG_FILE")
|
||||
viper.BindEnv("ListenPort", "PORT")
|
||||
|
||||
viper.SetDefault("ListenPort", "7200")
|
||||
viper.SetDefault("WebhookFile", "./webhooks.yaml")
|
||||
viper.SetDefault("Debug", false)
|
||||
|
||||
// read webhook config
|
||||
initWebhooks(viper.GetString("WebhookFile"))
|
||||
|
||||
// serve app
|
||||
runServer()
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue