Rewrite Strix from scratch as single binary
Complete architecture rewrite following go2rtc patterns: - pkg/ for pure logic (camdb, tester, probe, generate) - internal/ for application glue with Init() modules - Single HTTP server on :4567 with all endpoints - zerolog with password masking and memory ring buffer - Environment-based config only (no YAML files) API endpoints: /api/search, /api/streams, /api/test, /api/probe, /api/generate, /api/health, /api/log Dependencies: go2rtc v1.9.14, go-sqlite3, miekg/dns, zerolog
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
package search
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/eduard256/strix/internal/api"
|
||||
"github.com/eduard256/strix/internal/app"
|
||||
"github.com/eduard256/strix/pkg/camdb"
|
||||
"github.com/rs/zerolog"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
var log zerolog.Logger
|
||||
var db *sql.DB
|
||||
|
||||
func Init() {
|
||||
log = app.GetLogger("search")
|
||||
|
||||
var err error
|
||||
db, err = sql.Open("sqlite3", app.DB+"?mode=ro")
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("[search] db open")
|
||||
}
|
||||
|
||||
// verify DB is readable
|
||||
var count int
|
||||
if err = db.QueryRow("SELECT COUNT(*) FROM brands").Scan(&count); err != nil {
|
||||
log.Fatal().Err(err).Msg("[search] db verify")
|
||||
}
|
||||
log.Info().Int("brands", count).Msg("[search] loaded")
|
||||
|
||||
api.HandleFunc("api/search", apiSearch)
|
||||
api.HandleFunc("api/streams", apiStreams)
|
||||
}
|
||||
|
||||
func apiSearch(w http.ResponseWriter, r *http.Request) {
|
||||
q := strings.TrimSpace(r.URL.Query().Get("q"))
|
||||
|
||||
var results []camdb.Result
|
||||
var err error
|
||||
|
||||
if q == "" {
|
||||
results, err = camdb.SearchAll(db)
|
||||
} else {
|
||||
results, err = camdb.SearchQuery(db, q)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
api.Error(w, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
api.ResponseJSON(w, map[string]any{"results": results})
|
||||
}
|
||||
|
||||
func apiStreams(w http.ResponseWriter, r *http.Request) {
|
||||
q := r.URL.Query()
|
||||
|
||||
ids := q.Get("ids")
|
||||
if ids == "" {
|
||||
http.Error(w, "ids required", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
ip := q.Get("ip")
|
||||
if ip == "" {
|
||||
http.Error(w, "ip required", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
channel, _ := strconv.Atoi(q.Get("channel"))
|
||||
|
||||
var portFilter map[int]bool
|
||||
if ps := q.Get("ports"); ps != "" {
|
||||
portFilter = map[int]bool{}
|
||||
for _, p := range strings.Split(ps, ",") {
|
||||
if v, err := strconv.Atoi(strings.TrimSpace(p)); err == nil {
|
||||
portFilter[v] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
streams, err := camdb.BuildStreams(db, &camdb.StreamParams{
|
||||
IDs: ids,
|
||||
IP: ip,
|
||||
User: q.Get("user"),
|
||||
Pass: q.Get("pass"),
|
||||
Channel: channel,
|
||||
Ports: portFilter,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
status := http.StatusInternalServerError
|
||||
if strings.Contains(err.Error(), "not found") {
|
||||
status = http.StatusNotFound
|
||||
} else if strings.Contains(err.Error(), "invalid") || strings.Contains(err.Error(), "unknown") {
|
||||
status = http.StatusBadRequest
|
||||
}
|
||||
http.Error(w, err.Error(), status)
|
||||
return
|
||||
}
|
||||
|
||||
api.ResponseJSON(w, map[string]any{"streams": streams})
|
||||
}
|
||||
Reference in New Issue
Block a user