Compare commits
9 commits
7a8b904852
...
fd3cae1866
| Author | SHA1 | Date | |
|---|---|---|---|
| fd3cae1866 | |||
| b5a286a237 | |||
| 34d05ffa49 | |||
| abde10bfc9 | |||
| b33c266fb5 | |||
| b54d4a39cd | |||
| 1d49948615 | |||
| e714cca477 | |||
| 74fbef4ae8 |
9 changed files with 62 additions and 22 deletions
9
.editorconfig
Normal file
9
.editorconfig
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.json]
|
||||||
|
indent_style = tab
|
||||||
|
tab_width = 4
|
||||||
11
README.md
11
README.md
|
|
@ -6,7 +6,8 @@
|
||||||
$ curl http://localhost:8080 | jq
|
$ curl http://localhost:8080 | jq
|
||||||
{
|
{
|
||||||
"api_compatibility": [
|
"api_compatibility": [
|
||||||
"14"
|
"14",
|
||||||
|
"15"
|
||||||
],
|
],
|
||||||
"space": "CCCHH",
|
"space": "CCCHH",
|
||||||
...
|
...
|
||||||
|
|
@ -15,16 +16,16 @@ $ curl http://localhost:8080 | jq
|
||||||
|
|
||||||
## Configuring
|
## 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).
|
A sample configuration is provided as [config-template.json](./config-template.json).
|
||||||
The config consists of three parts:
|
The config consists of three parts:
|
||||||
|
|
||||||
- `"credentials"`
|
- `"credentials"`
|
||||||
- List of Username/Password credentials for HTTP BasicAuth
|
- List of Username/Password credentials for HTTP BasicAuth
|
||||||
- `"dynamic"`
|
- `"dynamic"`
|
||||||
- The configuration for the dynamic parts of the message
|
- The dynamic parts of the message
|
||||||
- `"response"`
|
- `"static"`
|
||||||
- The static (pre-filled) parts of the response
|
- The static (pre-filled) parts of the message
|
||||||
|
|
||||||
See [Running](#Running) for details.
|
See [Running](#Running) for details.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"response": {
|
"static": {
|
||||||
"api_compatibility": [
|
"api_compatibility": [
|
||||||
"14",
|
"14",
|
||||||
"15"
|
"15"
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ func ParseConfiguration() (conf SpaceapidConfig) {
|
||||||
log.Println("Parsing configuration files")
|
log.Println("Parsing configuration files")
|
||||||
|
|
||||||
paths := getConfigPaths()
|
paths := getConfigPaths()
|
||||||
log.Println(paths)
|
log.Println("Config files:", paths)
|
||||||
for _, path := range paths {
|
for _, path := range paths {
|
||||||
// Read file
|
// Read file
|
||||||
file, err := os.ReadFile(path)
|
file, err := os.ReadFile(path)
|
||||||
|
|
@ -86,9 +86,9 @@ func ParseConfiguration() (conf SpaceapidConfig) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if compatible with v14
|
// Sanity check: Config should declare compatibility with current SpaceAPI message version
|
||||||
if !slices.Contains(conf.Response.APICompatibility, "14") {
|
if !slices.Contains(conf.Response.APICompatibility, types.CurrentMessageVersion) {
|
||||||
log.Fatalln("Provided file doesn't specify compatibility with API version 14")
|
log.Fatalln("Provided config doesn't specify compatibility with current API version", types.CurrentMessageVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize fields for environment sensors
|
// Initialize fields for environment sensors
|
||||||
|
|
|
||||||
|
|
@ -34,5 +34,5 @@ type SpaceapidConfig struct {
|
||||||
// The dynamic part of the spaceapi JSON
|
// The dynamic part of the spaceapi JSON
|
||||||
Dynamic DynamicStateConfig `json:"dynamic"`
|
Dynamic DynamicStateConfig `json:"dynamic"`
|
||||||
// The static part of the spaceapi JSON
|
// The static part of the spaceapi JSON
|
||||||
Response types.SpaceAPIResponse `json:"response"`
|
Response types.SpaceAPIResponse `json:"static"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import (
|
||||||
"git.hamburg.ccc.de/ccchh/spaceapid/types"
|
"git.hamburg.ccc.de/ccchh/spaceapid/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func EnvironmentSensor(
|
func EnvironmentSensorPUT(
|
||||||
authDB config.HTTPBACredentials, validCredentials []config.HTTPBACredentialID,
|
authDB config.HTTPBACredentials, validCredentials []config.HTTPBACredentialID,
|
||||||
resp *types.EnvironmentSensor,
|
resp *types.EnvironmentSensor,
|
||||||
) func(http.ResponseWriter, *http.Request) {
|
) func(http.ResponseWriter, *http.Request) {
|
||||||
|
|
@ -35,3 +35,20 @@ func EnvironmentSensor(
|
||||||
resp.LastChange = time.Now().Unix()
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
@ -20,14 +19,14 @@ func updateEndpointValidator(
|
||||||
if !ok || !util.CheckCredentials(authDB, validCredentials, username, password) {
|
if !ok || !util.CheckCredentials(authDB, validCredentials, username, password) {
|
||||||
w.Header().Set("WWW-Authenticate", "Basic realm=\"spaceapid\"")
|
w.Header().Set("WWW-Authenticate", "Basic realm=\"spaceapid\"")
|
||||||
http.Error(w, "", http.StatusUnauthorized)
|
http.Error(w, "", http.StatusUnauthorized)
|
||||||
return []byte{}, errors.New(fmt.Sprintf("Unauthorized request from %s Username: %s Password: %s", r.RemoteAddr, username, password))
|
return []byte{}, fmt.Errorf("Unauthorized request from %s Username: %s Password: %s", r.RemoteAddr, username, password)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read request body
|
// Read request body
|
||||||
body, err := io.ReadAll(r.Body)
|
body, err := io.ReadAll(r.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "", http.StatusInternalServerError)
|
http.Error(w, "", http.StatusInternalServerError)
|
||||||
return []byte{}, errors.New(fmt.Sprintf("Failed to read request body from %s with error: %s", r.RemoteAddr, err))
|
return []byte{}, fmt.Errorf("Failed to read request body from %s with error: %s", r.RemoteAddr, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return body, nil
|
return body, nil
|
||||||
|
|
|
||||||
15
main.go
15
main.go
|
|
@ -25,6 +25,9 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
if version == "" {
|
||||||
|
version = "unknown"
|
||||||
|
}
|
||||||
log.Println("SpaceAPId version", version)
|
log.Println("SpaceAPId version", version)
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
@ -68,12 +71,18 @@ func main() {
|
||||||
// Register handlers for environmental sensors
|
// Register handlers for environmental sensors
|
||||||
for sensorType, envSensorConfigs := range conf.Dynamic.Sensors {
|
for sensorType, envSensorConfigs := range conf.Dynamic.Sensors {
|
||||||
for i, envSensorConfig := range envSensorConfigs {
|
for i, envSensorConfig := range envSensorConfigs {
|
||||||
urlPattern := "PUT " + util.GetSensorURLPath(
|
urlPattern := util.GetSensorURLPath(
|
||||||
sensorType, envSensorConfig.SensorData.Location, envSensorConfig.SensorData.Name,
|
sensorType, envSensorConfig.SensorData.Location, envSensorConfig.SensorData.Name,
|
||||||
)
|
)
|
||||||
http.HandleFunc(
|
http.HandleFunc(
|
||||||
urlPattern,
|
"PUT "+urlPattern,
|
||||||
handlers.EnvironmentSensor(
|
handlers.EnvironmentSensorPUT(
|
||||||
|
conf.Credentials, envSensorConfig.AllowedCredentials, &conf.Response.Sensors[sensorType][i],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
http.HandleFunc(
|
||||||
|
"DELETE "+urlPattern,
|
||||||
|
handlers.EnvironmentSensorDELETE(
|
||||||
conf.Credentials, envSensorConfig.AllowedCredentials, &conf.Response.Sensors[sensorType][i],
|
conf.Credentials, envSensorConfig.AllowedCredentials, &conf.Response.Sensors[sensorType][i],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
13
types/v15.go
13
types/v15.go
|
|
@ -1,5 +1,10 @@
|
||||||
package types
|
package types
|
||||||
|
|
||||||
|
const CurrentMessageVersion = "15"
|
||||||
|
|
||||||
|
// SpaceAPIResponse represents the contents of the SpaceAPI message
|
||||||
|
//
|
||||||
|
// Currently implemented version: 15
|
||||||
type SpaceAPIResponse struct {
|
type SpaceAPIResponse struct {
|
||||||
APICompatibility []string `json:"api_compatibility"` // REQUIRED
|
APICompatibility []string `json:"api_compatibility"` // REQUIRED
|
||||||
Space string `json:"space"` // REQUIRED
|
Space string `json:"space"` // REQUIRED
|
||||||
|
|
@ -120,10 +125,10 @@ type SpaceAPIState struct {
|
||||||
} `json:"icon,omitzero"`
|
} `json:"icon,omitzero"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SpaceAPIState) FromPersistentSpaceState(state PersistentSpaceState) {
|
func (s *SpaceAPIState) FromPersistentSpaceState(ps PersistentSpaceState) {
|
||||||
s.Open = state.State.Open
|
s.Open = ps.State.Open
|
||||||
s.LastChange = state.State.LastChange
|
s.LastChange = ps.State.LastChange
|
||||||
s.Message = state.State.Message
|
s.Message = ps.State.Message
|
||||||
}
|
}
|
||||||
|
|
||||||
type SpaceAPIEvents struct {
|
type SpaceAPIEvents struct {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue