174 lines
4.3 KiB
Go
174 lines
4.3 KiB
Go
package frigate
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/eduard256/strix/internal/api"
|
|
"github.com/eduard256/strix/internal/app"
|
|
"github.com/rs/zerolog"
|
|
)
|
|
|
|
var log zerolog.Logger
|
|
var frigateURL string
|
|
|
|
func Init() {
|
|
log = app.GetLogger("frigate")
|
|
|
|
frigateURL = detectFrigateURL()
|
|
|
|
log.Info().Str("url", frigateURL).Msg("[frigate] target")
|
|
|
|
api.HandleFunc("api/frigate/check", apiCheck)
|
|
}
|
|
|
|
func apiCheck(w http.ResponseWriter, r *http.Request) {
|
|
client := &http.Client{Timeout: 3 * time.Second}
|
|
|
|
result := map[string]any{
|
|
"url": frigateURL,
|
|
"detection": "unknown",
|
|
"ha_addons": nil,
|
|
"frigate_slug": "",
|
|
}
|
|
|
|
// show how URL was detected
|
|
if env := os.Getenv("STRIX_FRIGATE_URL"); env != "" {
|
|
result["detection"] = "env"
|
|
} else if os.Getenv("SUPERVISOR_TOKEN") != "" {
|
|
result["detection"] = "supervisor"
|
|
result["supervisor_token_len"] = len(os.Getenv("SUPERVISOR_TOKEN"))
|
|
// show what addons we found
|
|
addons, frigateSlug := listHAAddons()
|
|
result["ha_addons"] = addons
|
|
result["frigate_slug"] = frigateSlug
|
|
} else {
|
|
result["detection"] = "fallback_localhost"
|
|
}
|
|
|
|
resp, err := client.Get(frigateURL + "/api/config")
|
|
if err != nil {
|
|
result["connected"] = false
|
|
result["error"] = err.Error()
|
|
api.ResponseJSON(w, result)
|
|
return
|
|
}
|
|
resp.Body.Close()
|
|
|
|
result["connected"] = true
|
|
result["status_code"] = resp.StatusCode
|
|
result["message"] = fmt.Sprintf("Frigate API responded with %d", resp.StatusCode)
|
|
api.ResponseJSON(w, result)
|
|
}
|
|
|
|
// detectFrigateURL determines Frigate URL in priority order:
|
|
// 1. STRIX_FRIGATE_URL env var
|
|
// 2. HA Supervisor API autodiscovery
|
|
// 3. fallback to localhost:5000
|
|
func detectFrigateURL() string {
|
|
// 1. explicit env
|
|
if url := os.Getenv("STRIX_FRIGATE_URL"); url != "" {
|
|
log.Info().Str("url", url).Msg("[frigate] using STRIX_FRIGATE_URL")
|
|
return url
|
|
}
|
|
|
|
// 2. HA Supervisor autodiscovery
|
|
if token := os.Getenv("SUPERVISOR_TOKEN"); token != "" {
|
|
log.Info().Msg("[frigate] SUPERVISOR_TOKEN found, trying autodiscovery")
|
|
|
|
slug := findFrigateAddon(token)
|
|
if slug != "" {
|
|
// HA addon hostname format: slug with _ replaced by - and prefixed
|
|
url := fmt.Sprintf("http://%s:5000", slug)
|
|
log.Info().Str("slug", slug).Str("url", url).Msg("[frigate] found via Supervisor")
|
|
return url
|
|
}
|
|
|
|
log.Warn().Msg("[frigate] Supervisor available but Frigate addon not found")
|
|
}
|
|
|
|
// 3. fallback
|
|
return "http://localhost:5000"
|
|
}
|
|
|
|
// findFrigateAddon queries HA Supervisor API for installed addons and finds Frigate
|
|
func findFrigateAddon(token string) string {
|
|
client := &http.Client{Timeout: 3 * time.Second}
|
|
|
|
req, err := http.NewRequest("GET", "http://supervisor/addons", nil)
|
|
if err != nil {
|
|
log.Debug().Err(err).Msg("[frigate] supervisor request failed")
|
|
return ""
|
|
}
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
log.Debug().Err(err).Msg("[frigate] supervisor API unreachable")
|
|
return ""
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
var body struct {
|
|
Data struct {
|
|
Addons []struct {
|
|
Slug string `json:"slug"`
|
|
Name string `json:"name"`
|
|
State string `json:"state"`
|
|
URL string `json:"url"`
|
|
Hostname string `json:"hostname"`
|
|
} `json:"addons"`
|
|
} `json:"data"`
|
|
}
|
|
|
|
if err = json.NewDecoder(resp.Body).Decode(&body); err != nil {
|
|
log.Debug().Err(err).Msg("[frigate] supervisor response parse failed")
|
|
return ""
|
|
}
|
|
|
|
for _, addon := range body.Data.Addons {
|
|
// match by slug or name containing "frigate"
|
|
if addon.Slug == "ccab4aaf_frigate" || addon.Slug == "frigate" {
|
|
if addon.Hostname != "" {
|
|
return addon.Hostname
|
|
}
|
|
return addon.Slug
|
|
}
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
// listHAAddons returns raw response from Supervisor API for debug
|
|
func listHAAddons() (any, string) {
|
|
token := os.Getenv("SUPERVISOR_TOKEN")
|
|
if token == "" {
|
|
return nil, ""
|
|
}
|
|
|
|
client := &http.Client{Timeout: 3 * time.Second}
|
|
|
|
req, err := http.NewRequest("GET", "http://supervisor/addons", nil)
|
|
if err != nil {
|
|
return map[string]string{"error": err.Error()}, ""
|
|
}
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
return map[string]string{"error": err.Error()}, ""
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
var raw any
|
|
json.NewDecoder(resp.Body).Decode(&raw)
|
|
|
|
return map[string]any{
|
|
"status_code": resp.StatusCode,
|
|
"body": raw,
|
|
}, ""
|
|
}
|