- 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
167 lines
3.1 KiB
Go
167 lines
3.1 KiB
Go
package sysinfo
|
|
|
|
import (
|
|
"bufio"
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"safesight-agent/internal/files"
|
|
)
|
|
|
|
func Hostname() string {
|
|
h, err := os.Hostname()
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
return h
|
|
}
|
|
|
|
func UptimeSec() int64 {
|
|
if runtime.GOOS != "linux" {
|
|
return 0
|
|
}
|
|
b, err := os.ReadFile("/proc/uptime")
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
fields := strings.Fields(string(b))
|
|
if len(fields) == 0 {
|
|
return 0
|
|
}
|
|
f, err := strconv.ParseFloat(fields[0], 64)
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
if f < 0 {
|
|
return 0
|
|
}
|
|
return int64(f)
|
|
}
|
|
|
|
func DeviceID(deviceIDPath string) (string, error) {
|
|
if id, err := readFirstLine("/etc/machine-id"); err == nil {
|
|
id = strings.TrimSpace(id)
|
|
if id != "" {
|
|
return id, nil
|
|
}
|
|
}
|
|
|
|
if strings.TrimSpace(deviceIDPath) == "" {
|
|
return "", errors.New("device_id_path is empty")
|
|
}
|
|
if id, err := readFirstLine(deviceIDPath); err == nil {
|
|
id = strings.TrimSpace(id)
|
|
if id != "" {
|
|
return id, nil
|
|
}
|
|
}
|
|
|
|
id, err := newUUID()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if err := files.EnsureDir(filepath.Dir(deviceIDPath), 0o755); err != nil {
|
|
return "", err
|
|
}
|
|
if err := files.WriteFileAtomic(deviceIDPath, []byte(id+"\n"), 0o644); err != nil {
|
|
return "", fmt.Errorf("persist device_id: %w", err)
|
|
}
|
|
return id, nil
|
|
}
|
|
|
|
func PrimaryIPv4() string {
|
|
ifaces, err := net.Interfaces()
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
for _, iface := range ifaces {
|
|
if (iface.Flags&net.FlagUp) == 0 || (iface.Flags&net.FlagLoopback) != 0 {
|
|
continue
|
|
}
|
|
addrs, err := iface.Addrs()
|
|
if err != nil {
|
|
continue
|
|
}
|
|
for _, a := range addrs {
|
|
ip := addrIP(a)
|
|
if ip == nil {
|
|
continue
|
|
}
|
|
v4 := ip.To4()
|
|
if v4 == nil || v4.IsLoopback() {
|
|
continue
|
|
}
|
|
return v4.String()
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func LocalIPTo(remoteIP string) (string, error) {
|
|
raddr := &net.UDPAddr{IP: net.ParseIP(remoteIP), Port: 9}
|
|
if raddr.IP == nil {
|
|
return "", fmt.Errorf("invalid remote ip: %q", remoteIP)
|
|
}
|
|
c, err := net.DialUDP("udp4", nil, raddr)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer c.Close()
|
|
_ = c.SetDeadline(time.Now().Add(200 * time.Millisecond))
|
|
if la, ok := c.LocalAddr().(*net.UDPAddr); ok {
|
|
if la.IP != nil {
|
|
if v4 := la.IP.To4(); v4 != nil {
|
|
return v4.String(), nil
|
|
}
|
|
}
|
|
}
|
|
return "", errors.New("failed to determine local ip")
|
|
}
|
|
|
|
func readFirstLine(path string) (string, error) {
|
|
f, err := os.Open(path)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
defer f.Close()
|
|
s := bufio.NewScanner(f)
|
|
if !s.Scan() {
|
|
if err := s.Err(); err != nil {
|
|
return "", err
|
|
}
|
|
return "", errors.New("empty")
|
|
}
|
|
return s.Text(), nil
|
|
}
|
|
|
|
func addrIP(a net.Addr) net.IP {
|
|
switch v := a.(type) {
|
|
case *net.IPNet:
|
|
return v.IP
|
|
case *net.IPAddr:
|
|
return v.IP
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func newUUID() (string, error) {
|
|
b := make([]byte, 16)
|
|
if _, err := rand.Read(b); err != nil {
|
|
return "", fmt.Errorf("rand: %w", err)
|
|
}
|
|
b[6] = (b[6] & 0x0f) | 0x40
|
|
b[8] = (b[8] & 0x3f) | 0x80
|
|
hexStr := hex.EncodeToString(b)
|
|
return fmt.Sprintf("%s-%s-%s-%s-%s", hexStr[0:8], hexStr[8:12], hexStr[12:16], hexStr[16:20], hexStr[20:32]), nil
|
|
}
|