131 lines
2.9 KiB
Go
131 lines
2.9 KiB
Go
package discovery
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"strings"
|
|
"time"
|
|
|
|
"rk3588sys/agent/internal/sysinfo"
|
|
)
|
|
|
|
const Magic = "RK3588SYS_DISCOVERY_V1"
|
|
|
|
type Responder struct {
|
|
Port int
|
|
DeviceID string
|
|
DeviceName string
|
|
Hostname string
|
|
AgentPort int
|
|
MediaPort int
|
|
Version string
|
|
BuildID string
|
|
BuildType string
|
|
GitSHA string
|
|
}
|
|
|
|
type discoverReq struct {
|
|
Type string `json:"type"`
|
|
ReqID string `json:"req_id"`
|
|
ReplyPort int `json:"reply_port"`
|
|
}
|
|
|
|
type discoverReply struct {
|
|
Type string `json:"type"`
|
|
ReqID string `json:"req_id"`
|
|
DeviceID string `json:"device_id"`
|
|
DeviceName string `json:"device_name"`
|
|
Hostname string `json:"hostname"`
|
|
IP string `json:"ip"`
|
|
AgentPort int `json:"agent_port"`
|
|
MediaPort int `json:"media_port"`
|
|
Version string `json:"version"`
|
|
BuildID string `json:"build_id"`
|
|
BuildType string `json:"build_type"`
|
|
GitSHA string `json:"git_sha"`
|
|
UptimeSec int64 `json:"uptime_sec"`
|
|
}
|
|
|
|
func (r *Responder) Run(ctx context.Context) error {
|
|
addr := &net.UDPAddr{IP: net.IPv4zero, Port: r.Port}
|
|
conn, err := net.ListenUDP("udp4", addr)
|
|
if err != nil {
|
|
return fmt.Errorf("listen udp :%d: %w", r.Port, err)
|
|
}
|
|
defer conn.Close()
|
|
|
|
buf := make([]byte, 2048)
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return nil
|
|
default:
|
|
}
|
|
_ = conn.SetReadDeadline(time.Now().Add(500 * time.Millisecond))
|
|
n, remote, err := conn.ReadFromUDP(buf)
|
|
if err != nil {
|
|
var ne net.Error
|
|
if errors.As(err, &ne) && ne.Timeout() {
|
|
continue
|
|
}
|
|
return err
|
|
}
|
|
if remote == nil || remote.IP == nil {
|
|
continue
|
|
}
|
|
msg := string(buf[:n])
|
|
line1, line2, ok := split2lines(msg)
|
|
if !ok || strings.TrimSpace(line1) != Magic {
|
|
continue
|
|
}
|
|
var req discoverReq
|
|
if err := json.Unmarshal([]byte(line2), &req); err != nil {
|
|
continue
|
|
}
|
|
if req.Type != "discover" || strings.TrimSpace(req.ReqID) == "" {
|
|
continue
|
|
}
|
|
|
|
remoteIP := remote.IP.String()
|
|
ip := sysinfo.PrimaryIPv4()
|
|
if v, err := sysinfo.LocalIPTo(remoteIP); err == nil && v != "" {
|
|
ip = v
|
|
}
|
|
|
|
reply := discoverReply{
|
|
Type: "discover_reply",
|
|
ReqID: req.ReqID,
|
|
DeviceID: r.DeviceID,
|
|
DeviceName: r.DeviceName,
|
|
Hostname: r.Hostname,
|
|
IP: ip,
|
|
AgentPort: r.AgentPort,
|
|
MediaPort: r.MediaPort,
|
|
Version: r.Version,
|
|
BuildID: r.BuildID,
|
|
BuildType: r.BuildType,
|
|
GitSHA: r.GitSHA,
|
|
UptimeSec: sysinfo.UptimeSec(),
|
|
}
|
|
b, _ := json.Marshal(reply)
|
|
out := Magic + "\n" + string(b) + "\n"
|
|
_, _ = conn.WriteToUDP([]byte(out), remote)
|
|
}
|
|
}
|
|
|
|
func split2lines(s string) (string, string, bool) {
|
|
idx := strings.IndexByte(s, '\n')
|
|
if idx < 0 {
|
|
return "", "", false
|
|
}
|
|
line1 := strings.TrimRight(s[:idx], "\r")
|
|
line2 := strings.TrimSpace(strings.TrimRight(s[idx+1:], "\r"))
|
|
if line2 == "" {
|
|
return "", "", false
|
|
}
|
|
return line1, line2, true
|
|
}
|