Compare commits

..

1 commit

Author SHA1 Message Date
7a8b904852 --wip-- [skip ci] 2026-07-21 21:32:49 +02:00
9 changed files with 22 additions and 62 deletions

View file

@ -1,9 +0,0 @@
root = true
[*]
trim_trailing_whitespace = true
insert_final_newline = true
[*.json]
indent_style = tab
tab_width = 4

View file

@ -6,8 +6,7 @@
$ curl http://localhost:8080 | jq
{
"api_compatibility": [
"14",
"15"
"14"
],
"space": "CCCHH",
...
@ -16,16 +15,16 @@ $ curl http://localhost:8080 | jq
## Configuring
`spaceapid` has to be configured via one or multiple json files.
spaceapid has to be configured via one or multiple json files.
A sample configuration is provided as [config-template.json](./config-template.json).
The config consists of three parts:
- `"credentials"`
- List of Username/Password credentials for HTTP BasicAuth
- `"dynamic"`
- The dynamic parts of the message
- `"static"`
- The static (pre-filled) parts of the message
- The configuration for the dynamic parts of the message
- `"response"`
- The static (pre-filled) parts of the response
See [Running](#Running) for details.

View file

@ -66,7 +66,7 @@
}
}
},
"static": {
"response": {
"api_compatibility": [
"14",
"15"

View file

@ -69,7 +69,7 @@ func ParseConfiguration() (conf SpaceapidConfig) {
log.Println("Parsing configuration files")
paths := getConfigPaths()
log.Println("Config files:", paths)
log.Println(paths)
for _, path := range paths {
// Read file
file, err := os.ReadFile(path)
@ -86,9 +86,9 @@ func ParseConfiguration() (conf SpaceapidConfig) {
}
}
// Sanity check: Config should declare compatibility with current SpaceAPI message version
if !slices.Contains(conf.Response.APICompatibility, types.CurrentMessageVersion) {
log.Fatalln("Provided config doesn't specify compatibility with current API version", types.CurrentMessageVersion)
// Check if compatible with v14
if !slices.Contains(conf.Response.APICompatibility, "14") {
log.Fatalln("Provided file doesn't specify compatibility with API version 14")
}
// Initialize fields for environment sensors

View file

@ -34,5 +34,5 @@ type SpaceapidConfig struct {
// The dynamic part of the spaceapi JSON
Dynamic DynamicStateConfig `json:"dynamic"`
// The static part of the spaceapi JSON
Response types.SpaceAPIResponse `json:"static"`
Response types.SpaceAPIResponse `json:"response"`
}

View file

@ -11,7 +11,7 @@ import (
"git.hamburg.ccc.de/ccchh/spaceapid/types"
)
func EnvironmentSensorPUT(
func EnvironmentSensor(
authDB config.HTTPBACredentials, validCredentials []config.HTTPBACredentialID,
resp *types.EnvironmentSensor,
) func(http.ResponseWriter, *http.Request) {
@ -35,20 +35,3 @@ func EnvironmentSensorPUT(
resp.LastChange = time.Now().Unix()
}
}
func EnvironmentSensorDELETE(
authDB config.HTTPBACredentials, validCredentials []config.HTTPBACredentialID,
resp *types.EnvironmentSensor,
) 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.Value = 0
resp.LastChange = time.Now().Unix()
}
}

View file

@ -1,6 +1,7 @@
package handlers
import (
"errors"
"fmt"
"io"
"net/http"
@ -19,14 +20,14 @@ func updateEndpointValidator(
if !ok || !util.CheckCredentials(authDB, validCredentials, username, password) {
w.Header().Set("WWW-Authenticate", "Basic realm=\"spaceapid\"")
http.Error(w, "", http.StatusUnauthorized)
return []byte{}, fmt.Errorf("Unauthorized request from %s Username: %s Password: %s", r.RemoteAddr, username, password)
return []byte{}, errors.New(fmt.Sprintf("Unauthorized request from %s Username: %s Password: %s", r.RemoteAddr, username, password))
}
// Read request body
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "", http.StatusInternalServerError)
return []byte{}, fmt.Errorf("Failed to read request body from %s with error: %s", r.RemoteAddr, err)
return []byte{}, errors.New(fmt.Sprintf("Failed to read request body from %s with error: %s", r.RemoteAddr, err))
}
return body, nil

15
main.go
View file

@ -25,9 +25,6 @@ func init() {
}
func main() {
if version == "" {
version = "unknown"
}
log.Println("SpaceAPId version", version)
flag.Parse()
@ -71,18 +68,12 @@ func main() {
// Register handlers for environmental sensors
for sensorType, envSensorConfigs := range conf.Dynamic.Sensors {
for i, envSensorConfig := range envSensorConfigs {
urlPattern := util.GetSensorURLPath(
urlPattern := "PUT " + util.GetSensorURLPath(
sensorType, envSensorConfig.SensorData.Location, envSensorConfig.SensorData.Name,
)
http.HandleFunc(
"PUT "+urlPattern,
handlers.EnvironmentSensorPUT(
conf.Credentials, envSensorConfig.AllowedCredentials, &conf.Response.Sensors[sensorType][i],
),
)
http.HandleFunc(
"DELETE "+urlPattern,
handlers.EnvironmentSensorDELETE(
urlPattern,
handlers.EnvironmentSensor(
conf.Credentials, envSensorConfig.AllowedCredentials, &conf.Response.Sensors[sensorType][i],
),
)

View file

@ -1,10 +1,5 @@
package types
const CurrentMessageVersion = "15"
// SpaceAPIResponse represents the contents of the SpaceAPI message
//
// Currently implemented version: 15
type SpaceAPIResponse struct {
APICompatibility []string `json:"api_compatibility"` // REQUIRED
Space string `json:"space"` // REQUIRED
@ -125,10 +120,10 @@ type SpaceAPIState struct {
} `json:"icon,omitzero"`
}
func (s *SpaceAPIState) FromPersistentSpaceState(ps PersistentSpaceState) {
s.Open = ps.State.Open
s.LastChange = ps.State.LastChange
s.Message = ps.State.Message
func (s *SpaceAPIState) FromPersistentSpaceState(state PersistentSpaceState) {
s.Open = state.State.Open
s.LastChange = state.State.LastChange
s.Message = state.State.Message
}
type SpaceAPIEvents struct {