package api import ( "context" "database/sql" "encoding/json" "fmt" "net/http" "time" "git.joco.dk/sng/fermentord/internal/controllers" "git.joco.dk/sng/fermentord/internal/dal" "github.com/getsentry/sentry-go" "github.com/rs/zerolog/log" ) type API struct { db *dal.DAL config *controllers.ControllerConfig configChangeCallback func() } func NewAPI(db *dal.DAL) *API { return &API{ db: db, } } func (a *API) HealthCheck(w http.ResponseWriter, r *http.Request) { defer sentry.Recover() ctxb := context.Background() ctx, cancel := context.WithTimeout(ctxb, 5*time.Second) defer cancel() err := a.db.InReadOnlyTransaction(ctx, func(tx *sql.Tx) error { _, err := tx.Query("SELECT version()") return err }) if err != nil { http.Error(w, "Unhealthy", http.StatusServiceUnavailable) return } w.Write([]byte("Healthy")) } func (a *API) GetConfig(w http.ResponseWriter, r *http.Request) { defer sentry.Recover() resp, err := json.MarshalIndent(a.config, "", " ") if err != nil { log.Panic().Err(err).Msg("Error marshalling configuration.") } w.Write(resp) } func (a *API) GetTemperatures(w http.ResponseWriter, r *http.Request) { defer sentry.Recover() ctxb := context.Background() keys, ok := r.URL.Query()["since"] if !ok || len(keys[0]) < 1 { http.Error(w, "Missing since parameter.", http.StatusBadRequest) return } since, err := time.Parse(time.RFC3339, keys[0]) if err != nil { http.Error(w, "Invalid format of since parameter. Expected RFC3339 formatted string.", http.StatusBadRequest) return } ctx, cancel := context.WithTimeout(ctxb, 30*time.Second) defer cancel() var data []byte err = a.db.InReadOnlyTransaction(ctx, func(tx *sql.Tx) error { readings, err := dal.LoadTemperatureReadingsSince(ctx, tx, since) if err != nil { return err } data, err = json.MarshalIndent(readings, "", " ") if err != nil { return err } return nil }) if err != nil { log.Panic().Err(err).Msg("Failed to load temperature readings from DB.") } fmt.Fprintf(w, string(data)) } func (a *API) GetStateChanges(w http.ResponseWriter, r *http.Request) { defer sentry.Recover() ctxb := context.Background() keys, ok := r.URL.Query()["since"] if !ok || len(keys[0]) < 1 { http.Error(w, "Missing since parameter.", http.StatusBadRequest) return } since, err := time.Parse(time.RFC3339, keys[0]) if err != nil { http.Error(w, "Invalid format of since parameter. Expected RFC3339 formatted string.", http.StatusBadRequest) return } ctx, cancel := context.WithTimeout(ctxb, 30*time.Second) defer cancel() var data []byte err = a.db.InReadOnlyTransaction(ctx, func(tx *sql.Tx) error { readings, err := dal.LoadChamberStateChangesSince(ctx, tx, since) if err != nil { return err } data, err = json.MarshalIndent(readings, "", " ") if err != nil { return err } return nil }) if err != nil { log.Panic().Err(err).Msg("Failed to serialize temperature readings to JSON.") } fmt.Fprintf(w, string(data)) }