wip: work on http api

This commit is contained in:
saji 2024-02-24 16:48:19 -06:00
parent b5f5289b45
commit 34fca3d564
2 changed files with 101 additions and 43 deletions

81
http.go
View file

@ -31,13 +31,6 @@ func TelemRouter(log *slog.Logger, broker *Broker, db *db.TelemDb) http.Handler
r.Use(middleware.Logger) // TODO: integrate with slog instead of go default logger. r.Use(middleware.Logger) // TODO: integrate with slog instead of go default logger.
r.Use(middleware.Recoverer) r.Use(middleware.Recoverer)
r.Get("/schema", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
// return the spicy json response.
w.WriteHeader(http.StatusOK)
w.Write([]byte(skylab.SkylabDefinitions))
})
// heartbeat request. // heartbeat request.
r.Get("/ping", func(w http.ResponseWriter, r *http.Request) { r.Get("/ping", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("pong")) w.Write([]byte("pong"))
@ -84,39 +77,7 @@ func apiV1(broker *Broker, db *db.TelemDb) chi.Router {
}) })
// this is to get a single field // this is to get a single field
r.Get("/{name:[a-z_]+}/{field:[a-z_]+}", func(w http.ResponseWriter, r *http.Request) { r.Get("/{name:[a-z_]+}/{field:[a-z_]+}")
var err error
// we need a start and end time. If none is provided,
// we use unix epoch as start, and now + 1 day as end.
start := time.Unix(0, 0)
startString := r.URL.Query().Get("start")
if startString != "" {
start, err = time.Parse(time.RFC3339, startString)
if err != nil {
}
}
end := time.Now().Add(1 * time.Hour)
endParam := r.URL.Query().Get("start")
if endParam != "" {
end, err = time.Parse(time.RFC3339, endParam)
if err != nil {
}
}
name := chi.URLParam(r, "name")
field := chi.URLParam(r, "field")
// TODO: add limit/pagination ?
res, err := db.GetValues(r.Context(), name, field, start, end)
if err != nil {
// 500 server error:
fmt.Print(err)
}
b, err := json.Marshal(res)
w.Write(b)
})
}) })
@ -190,6 +151,46 @@ func apiV1PacketSubscribe(broker *Broker, db *db.TelemDb) http.HandlerFunc {
} }
} }
// apiV1GetValues is a function that creates a handler for
// getting the specific value from a packet.
// this is useful for OpenMCT or other viewer APIs
func apiV1GetValues(db *db.TelemDb) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var err error
// we need a start and end time. If none is provided,
// we use unix epoch as start, and now + 1 day as end.
start := time.Unix(0, 0)
startString := r.URL.Query().Get("start")
if startString != "" {
start, err = time.Parse(time.RFC3339, startString)
if err != nil {
}
}
end := time.Now().Add(1 * time.Hour)
endParam := r.URL.Query().Get("start")
if endParam != "" {
end, err = time.Parse(time.RFC3339, endParam)
if err != nil {
}
}
name := chi.URLParam(r, "name")
field := chi.URLParam(r, "field")
// TODO: add limit and pagination
res, err := db.GetValues(r.Context(), name, field, start, end)
if err != nil {
// 500 server error:
fmt.Print(err)
}
b, err := json.Marshal(res)
w.Write(b)
}
}
// TODO: rename. record is not a clear name. Runs? drives? segments? // TODO: rename. record is not a clear name. Runs? drives? segments?
func apiV1GetRecords(db *db.TelemDb) http.HandlerFunc { func apiV1GetRecords(db *db.TelemDb) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {

View file

@ -3,9 +3,66 @@ package db
import ( import (
"context" "context"
"fmt" "fmt"
"strings"
"time" "time"
) )
// Modifier augments SQL strings.
type Modifier interface {
ModifyStatement(string) string
}
type LimitOffsetModifier struct {
Limit int
Offset int
}
// BusEventFilter is a filter for bus events.
type BusEventFilter struct {
Names []string
TimerangeStart time.Time
TimerangeEnd time.Time
}
func (bef *BusEventFilter) String() string {
var sb []string = make([]string, 0, 2)
if len(bef.Names) > 0 {
names := strings.Join(bef.Names, ",")
sb = append(sb, fmt.Sprintf("name IN (%s)", names))
}
if !bef.TimerangeStart.IsZero() && !bef.TimerangeEnd.IsZero() {
sb = append(sb, fmt.Sprintf(""))
}
return ""
}
type BusEventElement interface {
Element() string
}
type NormalExtract struct {
Key string
}
type JSONExtract struct {
Key string
}
type BusEventQuery struct {
Elements []BusEventElement
Filter BusEventFilter
Limits LimitOffsetModifier
}
func (beq *BusEventQuery) String() string {
// select
return ""
}
// now we can optionally add a limit.
// Datum is a single measurement - it is more granular than a packet. // Datum is a single measurement - it is more granular than a packet.
// the classic example is bms_measurement.current // the classic example is bms_measurement.current
type Datum struct { type Datum struct {
@ -23,10 +80,10 @@ func (tdb *TelemDb) GetValues(ctx context.Context, packetName, field string, sta
SqlFrag := ` SqlFrag := `
SELECT SELECT
ts as timestamp, ts as timestamp,
json_extract(data, '$.current') as val json_extract(data, '$.' || ?) as val
FROM bus_events WHERE name IS 'bms_measurement' FROM bus_events WHERE name IS ?
` `
rows, err := tdb.db.QueryxContext(ctx, SqlFrag) rows, err := tdb.db.QueryxContext(ctx, SqlFrag, field, packetName)
if err != nil { if err != nil {
return nil, err return nil, err
} }