155 lines
3.5 KiB
Go
155 lines
3.5 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"flag"
|
|
"fmt"
|
|
"net"
|
|
"net/http"
|
|
"net/url"
|
|
"os"
|
|
"os/signal"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
"sync"
|
|
"syscall"
|
|
"time"
|
|
|
|
"rk3588sys/agent/internal/config"
|
|
"rk3588sys/agent/internal/discovery"
|
|
"rk3588sys/agent/internal/httpapi"
|
|
"rk3588sys/agent/internal/log"
|
|
"rk3588sys/agent/internal/mediaserver"
|
|
"rk3588sys/agent/internal/modelstore"
|
|
"rk3588sys/agent/internal/sysinfo"
|
|
)
|
|
|
|
var Version = "0.0.0-dev"
|
|
var GitSHA = ""
|
|
|
|
func main() {
|
|
cfgPath := flag.String("config", "", "config file path")
|
|
flag.Parse()
|
|
if strings.TrimSpace(*cfgPath) == "" {
|
|
log.Error("missing --config")
|
|
os.Exit(2)
|
|
}
|
|
|
|
cfg, err := config.Load(*cfgPath)
|
|
if err != nil {
|
|
log.Error("load config failed: " + err.Error())
|
|
os.Exit(2)
|
|
}
|
|
|
|
agentPort, err := portFromListen(cfg.Agent.Listen)
|
|
if err != nil {
|
|
log.Error("invalid agent.listen: " + err.Error())
|
|
os.Exit(2)
|
|
}
|
|
mediaPort, err := portFromBaseURL(cfg.Agent.MediaServerBaseURL)
|
|
if err != nil {
|
|
log.Error("invalid agent.media_server_base_url: " + err.Error())
|
|
os.Exit(2)
|
|
}
|
|
|
|
deviceID, err := sysinfo.DeviceID(cfg.Agent.DeviceIDPath)
|
|
if err != nil {
|
|
log.Error("device_id failed: " + err.Error())
|
|
os.Exit(2)
|
|
}
|
|
|
|
ms, err := mediaserver.New(cfg.Agent.MediaServerBaseURL, cfg.Agent.MediaServerTimeout, cfg.Agent.MediaServerRetry.MaxAttempts, cfg.Agent.MediaServerRetry.BackoffMS)
|
|
if err != nil {
|
|
log.Error("media-server client init failed: " + err.Error())
|
|
os.Exit(2)
|
|
}
|
|
store := modelstore.New(cfg.Agent.ModelsDir, cfg.Agent.MaxUploadMB)
|
|
|
|
baseDir := filepath.Dir(*cfgPath)
|
|
if abs, err := filepath.Abs(*cfgPath); err == nil {
|
|
baseDir = filepath.Dir(abs)
|
|
}
|
|
|
|
h := httpapi.New(cfg.Agent, baseDir, ms, store, deviceID, agentPort, mediaPort, Version, GitSHA)
|
|
|
|
httpSrv := &http.Server{
|
|
Addr: cfg.Agent.Listen,
|
|
Handler: h,
|
|
ReadHeaderTimeout: 5 * time.Second,
|
|
}
|
|
|
|
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
|
defer stop()
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
log.Info("http listening on " + cfg.Agent.Listen)
|
|
if err := httpSrv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
|
log.Error("http server error: " + err.Error())
|
|
stop()
|
|
}
|
|
}()
|
|
|
|
if cfg.Agent.DiscoveryEnable {
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
resp := &discovery.Responder{
|
|
Port: cfg.Agent.DiscoveryPort,
|
|
DeviceID: deviceID,
|
|
DeviceName: cfg.Agent.DeviceName,
|
|
Hostname: sysinfo.Hostname(),
|
|
AgentPort: agentPort,
|
|
MediaPort: mediaPort,
|
|
Version: Version,
|
|
GitSHA: GitSHA,
|
|
}
|
|
log.Info("udp discovery listening on :" + strconv.Itoa(cfg.Agent.DiscoveryPort))
|
|
if err := resp.Run(ctx); err != nil {
|
|
log.Error("udp discovery error: " + err.Error())
|
|
stop()
|
|
}
|
|
}()
|
|
}
|
|
|
|
<-ctx.Done()
|
|
shutdownCtx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
|
_ = httpSrv.Shutdown(shutdownCtx)
|
|
cancel()
|
|
wg.Wait()
|
|
}
|
|
|
|
func portFromListen(listen string) (int, error) {
|
|
_, portStr, err := net.SplitHostPort(listen)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
p, err := strconv.Atoi(portStr)
|
|
if err != nil || p <= 0 || p > 65535 {
|
|
return 0, fmt.Errorf("invalid port: %q", portStr)
|
|
}
|
|
return p, nil
|
|
}
|
|
|
|
func portFromBaseURL(base string) (int, error) {
|
|
u, err := url.Parse(base)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if u.Port() != "" {
|
|
p, err := strconv.Atoi(u.Port())
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return p, nil
|
|
}
|
|
if u.Scheme == "https" {
|
|
return 443, nil
|
|
}
|
|
return 80, nil
|
|
}
|