- Rename Agent binary: rk3588-agent → safesight-agent - Update Go module: rk3588sys/agent → safesight-agent - Rename CMake project: rk3588_media_server → safesight_media - Rename Media binary: media-server → safesight-media - Update all install paths, scripts, and config references
172 lines
4.1 KiB
Go
172 lines
4.1 KiB
Go
package main
|
||
|
||
import (
|
||
"context"
|
||
"flag"
|
||
"fmt"
|
||
"net"
|
||
"net/http"
|
||
"net/url"
|
||
"os"
|
||
"os/signal"
|
||
"path/filepath"
|
||
"strconv"
|
||
"strings"
|
||
"sync"
|
||
"syscall"
|
||
"time"
|
||
|
||
"safesight-agent/internal/config"
|
||
"safesight-agent/internal/discovery"
|
||
"safesight-agent/internal/httpapi"
|
||
"safesight-agent/internal/log"
|
||
"safesight-agent/internal/mediaserver"
|
||
"safesight-agent/internal/modelstore"
|
||
"safesight-agent/internal/sysinfo"
|
||
)
|
||
|
||
var Version = "0.0.0-dev"
|
||
var BuildID = "dev"
|
||
var BuildType = "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, BuildID, BuildType, GitSHA)
|
||
log.Info("rk3588-agent version=" + Version + " build_id=" + BuildID + " build_type=" + BuildType + " git_sha=" + 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()
|
||
}
|
||
}()
|
||
|
||
// 自动启动 media-server(如果启用)
|
||
if cfg.Agent.MediaServerProcess.Enable {
|
||
time.Sleep(500 * time.Millisecond) // 等待 HTTP 服务启动
|
||
log.Info("auto-starting media-server...")
|
||
if err := h.StartMediaServer(""); err != nil {
|
||
log.Error("auto-start media-server failed: " + err.Error())
|
||
} else {
|
||
log.Info("media-server auto-started")
|
||
}
|
||
}
|
||
|
||
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,
|
||
BuildID: BuildID,
|
||
BuildType: BuildType,
|
||
GitSHA: GitSHA,
|
||
ConfigPath: cfg.Agent.ConfigPath,
|
||
}
|
||
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
|
||
}
|