commit 3f892c246b1f5257a2d9829c9ffa99f4d997e96c
parent c3e836b084fe6e56f6a3ca3f2355e7e21dc36b1d
Author: Chris Bracken <chris@bracken.jp>
Date:   Thu, 11 Nov 2021 09:57:52 -0800
Extract data storage logic to storage package
Extracts all code related to data storage into a new storage package.
This allows us to swap out the data storage layer in tests or have
different storage providers; e.g. postgres, sqlite, flat file.
Diffstat:
2 files changed, 54 insertions(+), 31 deletions(-)
diff --git a/main.go b/main.go
@@ -1,7 +1,6 @@
 package main
 
 import (
-	"database/sql"
 	"encoding/json"
 	"fmt"
 	"io"
@@ -11,40 +10,16 @@ import (
 	"time"
 
 	"git.bracken.jp/tempestas/airrohr"
+	"git.bracken.jp/tempestas/storage"
 	_ "github.com/lib/pq"
 	"goji.io"
 	"goji.io/pat"
 )
 
-const (
-	INSERT_REPORT = "INSERT INTO " +
-		"sensor_data(sensor_id, sw_version, reading_time, reading_type, reading_value) " +
-		"VALUES($1, $2, $3, $4, $5)"
-)
-
 var (
-	db *sql.DB
+	ds *storage.DataStore
 )
 
-func setupDB() *sql.DB {
-	dbinfo := os.ExpandEnv("user=$TEMPESTAS_USER password=$TEMPESTAS_PASS dbname=$TEMPESTAS_DB sslmode=disable")
-	db, err := sql.Open("postgres", dbinfo)
-	if err != nil {
-		panic("Error connecting to database")
-	}
-	return db
-}
-
-func storeReport(report *airrohr.Report, t time.Time) {
-	for _, v := range report.Values {
-		_, err := db.Exec(INSERT_REPORT, report.SensorId, report.SoftwareVersion, t, v.Type, v.Value)
-		if err != nil {
-			fmt.Println("Error: failed to write sensor data")
-			fmt.Println(err)
-		}
-	}
-}
-
 func PostAirrohr(w http.ResponseWriter, r *http.Request) {
 	contentType := r.Header.Get("Content-Type")
 	if contentType != "application/json" {
@@ -61,7 +36,7 @@ func PostAirrohr(w http.ResponseWriter, r *http.Request) {
 	}
 	t := time.Now().UTC()
 	fmt.Println(t.String() + " Report received from sensor " + report.SensorId)
-	storeReport(&report, t)
+	ds.StoreReport(&report, t)
 	errorResponse(w, "Success", http.StatusOK)
 }
 
@@ -76,12 +51,14 @@ func errorResponse(w http.ResponseWriter, message string, httpStatusCode int) {
 
 func main() {
 	fmt.Println("Initializing database")
-	db = setupDB()
-	defer db.Close()
+	dbname := os.Getenv("TEMPESTAS_DB")
+	dbuser := os.Getenv("TEMPESTAS_USER")
+	dbpass := os.Getenv("TEMPESTAS_PASS")
+	ds := storage.Connect(dbname, dbuser, dbpass)
+	defer ds.Close()
 
 	fmt.Println("Waiting for requests")
 	mux := goji.NewMux()
 	mux.HandleFunc(pat.Post("/sensor/airrohr/"), PostAirrohr)
 	log.Fatal(http.ListenAndServe(":8080", mux))
-
 }
diff --git a/storage/storage.go b/storage/storage.go
@@ -0,0 +1,46 @@
+package storage
+
+import (
+	"database/sql"
+	"fmt"
+	"time"
+
+	"git.bracken.jp/tempestas/airrohr"
+)
+
+const (
+	INSERT_REPORT = "INSERT INTO " +
+		"sensor_data(sensor_id, sw_version, reading_time, reading_type, reading_value) " +
+		"VALUES($1, $2, $3, $4, $5)"
+)
+
+type DataStore struct {
+	db *sql.DB
+}
+
+func Connect(dbname string, user string, password string) *DataStore {
+	var s = new(DataStore)
+	var err error
+	dbinfo := fmt.Sprintf("user=%s password=%s dbname=%s sslmode=disable", user, password, dbname)
+	if s.db, err = sql.Open("postgres", dbinfo); err != nil {
+		panic("Error connecting to database")
+	}
+	return s
+}
+
+func (s DataStore) Close() {
+	s.db.Close()
+}
+
+func (s DataStore) StoreReport(report *airrohr.Report, t time.Time) {
+	if s.db == nil {
+		panic("Not connected to database")
+	}
+	for _, v := range report.Values {
+		_, err := s.db.Exec(INSERT_REPORT, report.SensorId, report.SoftwareVersion, t, v.Type, v.Value)
+		if err != nil {
+			fmt.Println("Error: failed to write sensor data")
+			fmt.Println(err)
+		}
+	}
+}