diff --git a/README.md b/README.md index 4cace42..dd1839a 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ `spaceapid` serves a [SpaceAPI](https://spaceapi.io)-compatible JSON on port 8080: ```shell -$ curl http://localhost:8080 | jq +$ curl http://[::1]:8080 | jq { "api_compatibility": [ "14" @@ -28,50 +28,38 @@ The config consists of three parts: See [Running](#Running) for details. +## Updating values + +The state of the boolean `state->open` property can be modified via `/state/open`: + +```shell +curl -X PUT -u user:password -d true http://[::1]:8080/state/open +``` + +The same is true for the endpoints for sensors configured under `"dynamic"`. +Currently only the sensors with the `value/unit/location/name/description` schema are implemented. +At the time of writing this includes `temperature`, `barometer`, `humidity`, `beverage_supply`, `power_consumption`, +and `account_balance`. +Out-of-spec sensors may also be used as long as they share the same schema. + +```shell +curl -X PUT -u user:password -d 23.42 http://[::1]:8080/sensors/{temperature,humidity,...}[/location[/name]] +``` + +As can be seen in the example, the http urls are generated from sensor type and optionally `location` and `name`. +Depending on sensor type `location` might be required for your sensors, see the schema for details. + ## Building See the `go.mod` file for minimum required Go version. There are currently no dependencies apart from the Go standard library. -``` shell -go build -ldflags '-X main.version=v420.69-rc23' . -``` - ## Running Set the environment variable to a comma-separated list of config files or pass the `-c` flag. ```shell -env SPACEAPID_CONFIG_PATH=config-template.json go run . +env CONFIG_PATH=config-template.json go run . # OR go run . -c config-credentials.json,config-dynamic.json,config-response.json ``` - -## Updating values - -The state of the boolean `state->open` and `state->message` property can be modified via `/state/{open,message}`: - -```shell -curl -X PUT -u user:password -d true http://localhost:8080/state/open -curl -X PUT -u user:password -d "Nur mit Passierschein A38 :3" http://localhost:8080/state/message -``` - -As `state->message` is optional, its value can be deleted by using the `PUT` method with an empty payload, or by using `DELETE`: - -```shell -curl -X PUT -u user:password -d "" http://localhost:8080/state/message -# OR -curl -X DELETE -u user:password http://localhost:8080/state/message -``` - -The same updating procedure applies for the endpoints for sensors configured under `"dynamic"`. -Currently only the sensors with the `value/unit/location/name/description` schema are implemented. -At the time of writing this includes `temperature`, `barometer`, `humidity`, `beverage_supply`, `power_consumption`, and `account_balance`. -Out-of-spec sensors may be used as well, as long as they share the same schema. - -```shell -curl -X PUT -u user:password -d 23.42 http://localhost:8080/sensors/{temperature,humidity,...}[/location[/name]] -``` - -As can be seen in the example, the http urls are generated from sensor type and optionally `location` and `name`. -Depending on sensor type, `location` might be required for your sensors, see the schema for details. diff --git a/config/config.go b/config/config.go index 444fd45..2190837 100644 --- a/config/config.go +++ b/config/config.go @@ -14,7 +14,7 @@ import ( ) const ( - envConfigPath = "SPACEAPID_CONFIG_PATH" + envConfigPath = "CONFIG_PATH" ) type pathsT []string @@ -59,7 +59,7 @@ func getConfigPaths() (paths pathsT) { // If paths is still empty we are missing something if len(paths) == 0 { - log.Fatalln("Error: Neither env: ", envConfigPath, "nor cli flag was specified, unable to start without config.") + log.Fatalln("Neither the env variable nor cli flag was specified, we are missing a config file.") } return } @@ -91,7 +91,7 @@ func ParseConfiguration() (conf SpaceapidConfig) { log.Fatalln("Provided file doesn't specify compatibility with API version 14") } - // Initialize fields for environment sensors + // Initialise fields for environment sensors conf.Response.Sensors = make(map[string][]types.EnvironmentSensor) for key, sensorConfigs := range conf.Dynamic.Sensors { conf.Response.Sensors[key] = make([]types.EnvironmentSensor, len(sensorConfigs)) diff --git a/go.mod b/go.mod index 506613d..e3d228e 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ module git.hamburg.ccc.de/ccchh/spaceapid -go 1.22 +go 1.21 diff --git a/handlers/state.go b/handlers/state.go index d1ab9d9..f965db4 100644 --- a/handlers/state.go +++ b/handlers/state.go @@ -34,37 +34,3 @@ func StateOpen( resp.LastChange = time.Now().Unix() } } - -func StateMessagePUT( - authDB config.HTTPBACredentials, validCredentials []config.HTTPBACredentialID, - resp *types.SpaceState, -) func(http.ResponseWriter, *http.Request) { - return func(w http.ResponseWriter, r *http.Request) { - body, err := updateEndpointValidator(authDB, validCredentials, w, r) - if err != nil { - log.Println(err) - return - } - - // Set SpaceAPI response values - resp.Message = string(body) - resp.LastChange = time.Now().Unix() - } -} - -func StateMessageDELETE( - authDB config.HTTPBACredentials, validCredentials []config.HTTPBACredentialID, - resp *types.SpaceState, -) func(http.ResponseWriter, *http.Request) { - return func(w http.ResponseWriter, r *http.Request) { - _, err := updateEndpointValidator(authDB, validCredentials, w, r) - if err != nil { - log.Println(err) - return - } - - // Set SpaceAPI response values - resp.Message = "" - resp.LastChange = time.Now().Unix() - } -} diff --git a/handlers/util.go b/handlers/util.go index 27c2d9f..890d983 100644 --- a/handlers/util.go +++ b/handlers/util.go @@ -10,7 +10,8 @@ import ( "git.hamburg.ccc.de/ccchh/spaceapid/util" ) -// updateEndpointValidator checks BasicAuth credentials and then returns the request body +// updateEndpointValidator checks BasicAuth credentials, +// checks for correct HTTP method and then returns the request body func updateEndpointValidator( authDB config.HTTPBACredentials, validCredentials []config.HTTPBACredentialID, w http.ResponseWriter, r *http.Request, @@ -23,6 +24,13 @@ func updateEndpointValidator( return []byte{}, errors.New(fmt.Sprintf("Unauthorized request from %s Username: %s Password: %s", r.RemoteAddr, username, password)) } + // Check if PUT method + if r.Method != http.MethodPut { + w.Header().Set("Allow", http.MethodPut) + http.Error(w, "", http.StatusMethodNotAllowed) + return []byte{}, errors.New(fmt.Sprintf("Wrong Method: %s from %s at %s", r.Method, r.RemoteAddr, r.RequestURI)) + } + // Read request body body, err := io.ReadAll(r.Body) if err != nil { diff --git a/main.go b/main.go index 35b564d..8e4b013 100644 --- a/main.go +++ b/main.go @@ -50,29 +50,21 @@ func main() { os.Exit(0) }(&conf.Response) - // Root handler - http.HandleFunc("GET /{$}", + // Register HTTP handlers + http.HandleFunc("/", handlers.Root(&conf.Response), ) - // state->open - http.HandleFunc("PUT /state/open", + http.HandleFunc("/state/open", handlers.StateOpen(conf.Credentials, conf.Dynamic.State.Open.AllowedCredentials, &conf.Response.State), ) - // state->message - http.HandleFunc("PUT /state/message", - handlers.StateMessagePUT(conf.Credentials, conf.Dynamic.State.Open.AllowedCredentials, &conf.Response.State), - ) - http.HandleFunc("DELETE /state/message", - handlers.StateMessageDELETE(conf.Credentials, conf.Dynamic.State.Open.AllowedCredentials, &conf.Response.State), - ) - // Register handlers for environmental sensors + // Register handlers for Environmental Sensors for sensorType, envSensorConfigs := range conf.Dynamic.Sensors { for i, envSensorConfig := range envSensorConfigs { - urlPattern := "PUT " + util.GetSensorURLPath( + urlPath := util.GetSensorURLPath( sensorType, envSensorConfig.SensorData.Location, envSensorConfig.SensorData.Name, ) http.HandleFunc( - urlPattern, + urlPath, handlers.EnvironmentSensor( conf.Credentials, envSensorConfig.AllowedCredentials, &conf.Response.Sensors[sensorType][i], ), diff --git a/persistence/persistentState.go b/persistence/persistentState.go index 74fbdb2..01e1912 100644 --- a/persistence/persistentState.go +++ b/persistence/persistentState.go @@ -89,10 +89,9 @@ func SaveCurrentState(response types.SpaceAPIResponseV14) { // Create persistent state persistentStateV14 := types.PersistentStateV14{ State: struct { - Open bool `json:"open"` - LastChange int64 `json:"lastchange"` - Message string `json:"message,omitempty"` - }{Open: response.State.Open, LastChange: response.State.LastChange, Message: response.State.Message}, + Open bool `json:"open"` + LastChange int64 `json:"lastchange"` + }{Open: response.State.Open, LastChange: response.State.LastChange}, } // Save sensor state persistentStateV14.Sensors = make(map[string][]types.PersistentEnvironmentSensor) diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..5db72dd --- /dev/null +++ b/renovate.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:recommended" + ] +} diff --git a/types/v14.go b/types/v14.go index 3763fe4..2492639 100644 --- a/types/v14.go +++ b/types/v14.go @@ -38,9 +38,8 @@ type SpaceAPIResponseV14 struct { } type SpaceState struct { - Open bool `json:"open"` - LastChange int64 `json:"lastchange"` - Message string `json:"message,omitempty"` + Open bool `json:"open"` + LastChange int64 `json:"lastchange"` } type EnvironmentSensor struct { @@ -54,9 +53,8 @@ type EnvironmentSensor struct { type PersistentStateV14 struct { State struct { - Open bool `json:"open"` - LastChange int64 `json:"lastchange"` - Message string `json:"message,omitempty"` + Open bool `json:"open"` + LastChange int64 `json:"lastchange"` } `json:"state"` Sensors map[string][]PersistentEnvironmentSensor `json:"sensors,omitempty"` }