diff --git a/cmd/api/api.go b/cmd/api/api.go index 61f2d688..d6b4adde 100644 --- a/cmd/api/api.go +++ b/cmd/api/api.go @@ -54,28 +54,31 @@ func Init() { log.Info().Str("addr", cfg.Mod.Listen).Msg("[api] listen") - s := http.Server{} - s.Handler = http.DefaultServeMux // 4th + Handler = http.DefaultServeMux // 4th if cfg.Mod.Origin == "*" { - s.Handler = middlewareCORS(s.Handler) // 3rd + Handler = middlewareCORS(Handler) // 3rd } if cfg.Mod.Username != "" { - s.Handler = middlewareAuth(cfg.Mod.Username, cfg.Mod.Password, s.Handler) // 2nd + Handler = middlewareAuth(cfg.Mod.Username, cfg.Mod.Password, Handler) // 2nd } if log.Trace().Enabled() { - s.Handler = middlewareLog(s.Handler) // 1st + Handler = middlewareLog(Handler) // 1st } go func() { + s := http.Server{} + s.Handler = Handler if err = s.Serve(listener); err != nil { log.Fatal().Err(err).Msg("[api] serve") } }() } +var Handler http.Handler + // HandleFunc handle pattern with relative path: // - "api/streams" => "{basepath}/api/streams" // - "/streams" => "/streams" diff --git a/cmd/hass/api.go b/cmd/hass/api.go index 95d0eb7e..54a20c94 100644 --- a/cmd/hass/api.go +++ b/cmd/hass/api.go @@ -6,6 +6,7 @@ import ( "github.com/AlexxIT/go2rtc/cmd/api" "github.com/AlexxIT/go2rtc/cmd/streams" "github.com/AlexxIT/go2rtc/cmd/webrtc" + "net" "net/http" "net/url" "strings" @@ -133,6 +134,25 @@ func initAPI() { }) } +func HassioAddr() string { + ints, _ := net.Interfaces() + + for _, i := range ints { + if i.Name != "hassio" { + continue + } + + addrs, _ := i.Addrs() + for _, addr := range addrs { + if addr, ok := addr.(*net.IPNet); ok { + return addr.IP.String() + } + } + } + + return "" +} + func rtspStream(url string) *streams.Stream { if strings.HasPrefix(url, "rtsp://") { if i := strings.IndexByte(url[7:], '/'); i > 0 { diff --git a/cmd/hass/hass.go b/cmd/hass/hass.go index 79c8be88..ddbfe995 100644 --- a/cmd/hass/hass.go +++ b/cmd/hass/hass.go @@ -17,6 +17,9 @@ import ( func Init() { var conf struct { + API struct { + Listen string `json:"listen"` + } `yaml:"api"` Mod struct { Config string `yaml:"config"` } `yaml:"hass"` @@ -28,35 +31,68 @@ func Init() { initAPI() - // support load cameras from Hass config file - filename := path.Join(conf.Mod.Config, ".storage/core.config_entries") - b, err := os.ReadFile(filename) - if err != nil { + entries := importEntries(conf.Mod.Config) + if entries == nil { + api.HandleFunc("api/hass", func(w http.ResponseWriter, _ *http.Request) { + http.Error(w, "no hass config", http.StatusNotFound) + }) return } - storage := new(entries) - if err = json.Unmarshal(b, storage); err != nil { - return - } - - urls := map[string]string{} - - api.HandleFunc("api/hass", func(w http.ResponseWriter, r *http.Request) { + api.HandleFunc("api/hass", func(w http.ResponseWriter, _ *http.Request) { var items []api.Stream - for name, url := range urls { + for name, url := range entries { items = append(items, api.Stream{Name: name, URL: url}) } api.ResponseStreams(w, items) }) streams.HandleFunc("hass", func(url string) (core.Producer, error) { - if hurl := urls[url[5:]]; hurl != "" { + if hurl := entries[url[5:]]; hurl != "" { return streams.GetProducer(hurl) } return nil, fmt.Errorf("can't get url: %s", url) }) + // for Addon listen on hassio interface, so WebUI feature will work + if conf.API.Listen == "127.0.0.1:1984" { + if addr := HassioAddr(); addr != "" { + addr += ":1984" + go func() { + log.Info().Str("addr", addr).Msg("[hass] listen") + if err := http.ListenAndServe(addr, api.Handler); err != nil { + log.Error().Err(err).Caller().Send() + } + }() + } + } +} + +func importEntries(config string) map[string]string { + // support load cameras from Hass config file + filename := path.Join(config, ".storage/core.config_entries") + b, err := os.ReadFile(filename) + if err != nil { + return nil + } + + var storage struct { + Data struct { + Entries []struct { + Title string `json:"title"` + Domain string `json:"domain"` + Data json.RawMessage `json:"data"` + Options json.RawMessage `json:"options"` + } `json:"entries"` + } `json:"data"` + } + + if err = json.Unmarshal(b, &storage); err != nil { + return nil + } + + urls := map[string]string{} + for _, entrie := range storage.Data.Entries { switch entrie.Domain { case "generic": @@ -102,17 +138,8 @@ func Init() { log.Info().Str("url", "hass:"+entrie.Title).Msg("[hass] load stream") //streams.Get("hass:" + entrie.Title) } + + return urls } var log zerolog.Logger - -type entries struct { - Data struct { - Entries []struct { - Title string `json:"title"` - Domain string `json:"domain"` - Data json.RawMessage `json:"data"` - Options json.RawMessage `json:"options"` - } `json:"entries"` - } `json:"data"` -}