116 lines
3.1 KiB
Go
116 lines
3.1 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"io/fs"
|
|
"log"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
|
|
"energy-frontend/internal/config"
|
|
)
|
|
|
|
func NewRouter(cfg config.Config, frontendFS fs.FS) http.Handler {
|
|
pool, err := pgxpool.New(context.Background(), cfg.DB.DSN)
|
|
if err != nil {
|
|
log.Fatalf("db pool: %v", err)
|
|
}
|
|
|
|
mux := http.NewServeMux()
|
|
auth := newAuthHandler(cfg.Auth)
|
|
|
|
mux.HandleFunc("POST /api/login", auth.loginHandler)
|
|
mux.HandleFunc("POST /api/logout", auth.logoutHandler)
|
|
|
|
protected := http.NewServeMux()
|
|
protected.HandleFunc("GET /api/auth/check", auth.checkHandler)
|
|
protected.HandleFunc("GET /api/bars", func(w http.ResponseWriter, r *http.Request) {
|
|
period := r.URL.Query().Get("period")
|
|
if period == "" {
|
|
period = "day"
|
|
}
|
|
count, err := strconv.Atoi(r.URL.Query().Get("count"))
|
|
if err != nil || count <= 0 {
|
|
count = periodDefaults[period]
|
|
}
|
|
bars, err := getBars(r.Context(), pool, period, count)
|
|
if err != nil {
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, map[string]interface{}{"bars": bars})
|
|
})
|
|
protected.HandleFunc("GET /api/power", func(w http.ResponseWriter, r *http.Request) {
|
|
tr := r.URL.Query().Get("range")
|
|
if tr == "" {
|
|
tr = "24h"
|
|
}
|
|
pts, err := getPower(r.Context(), pool, tr)
|
|
if err != nil {
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, map[string]interface{}{"points": pts})
|
|
})
|
|
protected.HandleFunc("GET /api/battery", func(w http.ResponseWriter, r *http.Request) {
|
|
tr := r.URL.Query().Get("range")
|
|
if tr == "" {
|
|
tr = "24h"
|
|
}
|
|
pts, err := getBattery(r.Context(), pool, tr)
|
|
if err != nil {
|
|
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, map[string]interface{}{"points": pts})
|
|
})
|
|
|
|
mux.Handle("/api/", auth.middleware(protected))
|
|
|
|
if frontendFS != nil {
|
|
mux.Handle("/", spaHandler(frontendFS))
|
|
}
|
|
|
|
return corsMiddleware(mux)
|
|
}
|
|
|
|
func spaHandler(frontendFS fs.FS) http.Handler {
|
|
fileServer := http.FileServer(http.FS(frontendFS))
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
path := strings.TrimPrefix(r.URL.Path, "/")
|
|
if path == "" {
|
|
path = "index.html"
|
|
}
|
|
if _, err := fs.Stat(frontendFS, path); err == nil {
|
|
fileServer.ServeHTTP(w, r)
|
|
return
|
|
}
|
|
r.URL.Path = "/"
|
|
fileServer.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
|
|
func corsMiddleware(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Access-Control-Allow-Origin", r.Header.Get("Origin"))
|
|
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
|
|
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
|
|
w.Header().Set("Access-Control-Allow-Credentials", "true")
|
|
if r.Method == "OPTIONS" {
|
|
w.WriteHeader(http.StatusOK)
|
|
return
|
|
}
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
|
|
func writeJSON(w http.ResponseWriter, status int, v interface{}) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(status)
|
|
json.NewEncoder(w).Encode(v)
|
|
}
|