tempestas

A REST API for processing sensor.community data
git clone https://git.bracken.jp/tempestas.git
Log | Files | Refs | README | LICENSE

commit 9771ddbe35f4e955a46f102d80ab70743b875b4a
parent f15c48a2e40cc62921919f9d60b4e412840de4bb
Author: Chris Bracken <chris@bracken.jp>
Date:   Thu, 11 Nov 2021 14:19:16 -0800

Extract HTTP server to its own package

This extracts out the HTTP API into its own package. This also moves the
database state into the HttpServer object, eliminating the use of a
global variable to hold this.

Diffstat:
Ahttp/http.go | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mmain.go | 46+++-------------------------------------------
2 files changed, 60 insertions(+), 43 deletions(-)

diff --git a/http/http.go b/http/http.go @@ -0,0 +1,57 @@ +package http + +import ( + "encoding/json" + "fmt" + "net/http" + "time" + + "git.bracken.jp/tempestas/airrohr" + "git.bracken.jp/tempestas/storage" + "goji.io" + "goji.io/pat" +) + +type HttpServer struct { + ds *storage.DataStore +} + +func CreateServer(ds *storage.DataStore) *HttpServer { + s := new(HttpServer) + s.ds = ds + return s +} + +func (s HttpServer) ListenAndServe(addr string) error { + mux := goji.NewMux() + mux.HandleFunc(pat.Post("/sensor/airrohr/"), s.PostAirrohr) + return http.ListenAndServe(addr, mux) +} + +func (s HttpServer) PostAirrohr(w http.ResponseWriter, r *http.Request) { + contentType := r.Header.Get("Content-Type") + if contentType != "application/json" { + errorResponse(w, "Content-Type must be application/json", http.StatusUnsupportedMediaType) + return + } + var report airrohr.Report + err := airrohr.Parse(r.Body, &report) + if err != nil { + fmt.Println("Error: unknown JSON format from sensor: " + err.Error()) + errorResponse(w, "Bad Request. "+err.Error(), http.StatusBadRequest) + return + } + t := time.Now().UTC() + fmt.Println(t.String() + " Report received from sensor " + report.SensorId) + s.ds.StoreReport(&report, t) + errorResponse(w, "Success", http.StatusOK) +} + +func errorResponse(w http.ResponseWriter, message string, httpStatusCode int) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(httpStatusCode) + resp := make(map[string]string) + resp["message"] = message + jsonResp, _ := json.Marshal(resp) + w.Write(jsonResp) +} diff --git a/main.go b/main.go @@ -1,54 +1,15 @@ package main import ( - "encoding/json" "fmt" - "io" "log" - "net/http" "os" - "time" - "git.bracken.jp/tempestas/airrohr" + "git.bracken.jp/tempestas/http" "git.bracken.jp/tempestas/storage" _ "github.com/lib/pq" - "goji.io" - "goji.io/pat" ) -var ( - ds *storage.DataStore -) - -func PostAirrohr(w http.ResponseWriter, r *http.Request) { - contentType := r.Header.Get("Content-Type") - if contentType != "application/json" { - errorResponse(w, "Content-Type must be application/json", http.StatusUnsupportedMediaType) - return - } - var report airrohr.Report - err := airrohr.Parse(r.Body, &report) - if err != nil { - s, err := io.ReadAll(r.Body) - fmt.Println("Error: unknown JSON format from sensor: " + err.Error() + ". Message: " + string(s)) - errorResponse(w, "Bad Request. "+err.Error(), http.StatusBadRequest) - return - } - t := time.Now().UTC() - fmt.Println(t.String() + " Report received from sensor " + report.SensorId) - ds.StoreReport(&report, t) - errorResponse(w, "Success", http.StatusOK) -} - -func errorResponse(w http.ResponseWriter, message string, httpStatusCode int) { - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(httpStatusCode) - resp := make(map[string]string) - resp["message"] = message - jsonResp, _ := json.Marshal(resp) - w.Write(jsonResp) -} - func main() { fmt.Println("Initializing database") dbname := os.Getenv("TEMPESTAS_DB") @@ -58,7 +19,6 @@ func main() { defer ds.Close() fmt.Println("Waiting for requests") - mux := goji.NewMux() - mux.HandleFunc(pat.Post("/sensor/airrohr/"), PostAirrohr) - log.Fatal(http.ListenAndServe(":8080", mux)) + s := http.CreateServer(ds) + log.Fatal(s.ListenAndServe(":8080")) }