kunmeng пре 5 дана
родитељ
комит
4036fd6000
23 измењених фајлова са 1177 додато и 84 уклоњено
  1. 1 0
      Common/Resty.go
  2. 6 0
      Common/micro.go
  3. 54 0
      Docker/test.go
  4. 2 1
      GPS.go
  5. 7 0
      Monitor/model/monitor.proto
  6. 229 0
      NTP/NTPSvr.go
  7. 134 0
      Process/monitor.go
  8. 51 0
      SystemInfo/Timestamp.go
  9. 130 0
      SystemInfo/nmcli.go
  10. 10 7
      cfg.toml
  11. 1 1
      gRPC_Model/NetworkManager.proto
  12. 39 11
      go.mod
  13. 121 42
      go.sum
  14. 140 14
      main.go
  15. 1 1
      monitor.go
  16. 44 0
      nmcli/Device.go
  17. 63 0
      nmcli/Ethernet.go
  18. 74 7
      nmcli/WIFI.go
  19. 5 0
      nmcli/model/Device.go
  20. 16 0
      nmcli/model/Ethernet.go
  21. 6 0
      nmcli/model/General.go
  22. 7 0
      nmcli/model/Wifi.go
  23. 36 0
      nmcli/nmcli.go

+ 1 - 0
Common/Resty.go

@@ -3,3 +3,4 @@ package Common
 import "github.com/go-resty/resty/v2"
 
 var HTTPClient3s = resty.New()
+var Address = []string{}

+ 6 - 0
Common/micro.go

@@ -0,0 +1,6 @@
+package Common
+
+import "go-micro.dev/v5/registry"
+
+var Micro registry.Registry
+var Machine string

+ 54 - 0
Docker/test.go

@@ -0,0 +1,54 @@
+package Docker
+
+import (
+	"context"
+	"github.com/docker/docker/api/types/container"
+	"github.com/docker/docker/client"
+	"regexp"
+	"sync"
+	"time"
+)
+
+var OnlineContainerID map[string]container.Summary
+var OnlineContainerMux sync.RWMutex
+var isMonitoring bool
+var monitorTimer *time.Timer
+var debounceDuration = 5 * time.Second // 设置消抖时间为5秒
+
+func DockerOnlineContainer() {
+	if isMonitoring {
+		return
+	}
+	isMonitoring = true
+	ctx := context.Background()
+	cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
+	if err != nil {
+		return
+	}
+	// 查看正在运行的容器
+	containers, err := cli.ContainerList(ctx, container.ListOptions{})
+	if err != nil {
+		return
+	}
+	OnlineContainerMux.Lock()
+	OnlineContainerID = make(map[string]container.Summary)
+	compile, err := regexp.Compile("business-go")
+	if err != nil {
+		return
+	}
+
+	for _, info := range containers {
+		if !compile.MatchString(info.Image) {
+			continue
+		}
+		OnlineContainerID[info.ID] = info
+	}
+	OnlineContainerMux.Unlock()
+	if monitorTimer != nil {
+		monitorTimer.Stop()
+	}
+	monitorTimer = time.AfterFunc(debounceDuration, func() {
+		isMonitoring = false
+	})
+	return
+}

+ 2 - 1
GPS.go

@@ -14,6 +14,7 @@ import (
 type GPS struct {
 	ConnectionType   string       `toml:"ConnectionType"`
 	ConnectionString string       `toml:"ConnectionString"`
+	ConnectionSerial string       `toml:"ConnectionSerial"`
 	serial           interface{}  `toml:"-"`
 	latitude         float64      `toml:"-"`
 	longitude        float64      `toml:"-"`
@@ -23,7 +24,7 @@ type GPS struct {
 func (g *GPS) Open() (err error) {
 	if g.ConnectionType == "serial" {
 		g.serial, err = serial.OpenPort(&serial.Config{
-			Name: "/dev/ttyS3", Baud: 9600,
+			Name: g.ConnectionSerial, Baud: 9600,
 		})
 		if err != nil {
 			return

+ 7 - 0
Monitor/model/monitor.proto

@@ -0,0 +1,7 @@
+syntax = "proto3";
+
+package monitor;
+
+service MonitorService {
+
+}

+ 229 - 0
NTP/NTPSvr.go

@@ -0,0 +1,229 @@
+package NTP
+
+import (
+	"encoding/binary"
+	"fmt"
+	"log"
+	"net"
+	"sync"
+	"time"
+)
+
+const (
+	STANDARD_PACKET_SIZE = 48 // 标准NTP的报文大小
+)
+
+type NTPServer struct {
+	srvAddress string
+
+	conn *net.UDPConn
+	wait sync.WaitGroup
+
+	ntpPack      NtpPacket // NTP协议报文
+	requestCount uint64    // 请求计数
+}
+
+type NtpPacket struct {
+	/*
+		LI: 2bit      00   Leap Indicator(0)
+		VN: 3bit      100  NTP Version(4)
+		Mode: 3bit    100  Mode: server(4), client(3)
+	*/
+	Header    uint8 // 报文头: 包含LI、VN、Mode
+	Stratum   uint8 // Peer Clock Stratum: primary reference (1)
+	Poll      uint8 // Peer Polling Interval: invalid (0)
+	Precision uint8 // Peer Clock Precision: 0.000000 seconds
+
+	RootDelay uint32 // Root Delay
+	RootDisp  uint32 // Root Dispersion
+	RefID     uint32 // Reference Identifier
+
+	RefTS   uint64 // Reference Timestamp 参考时间戳
+	OrigTS  uint64 // Originate Timestamp 起始时间戳
+	RecvTS  uint64 // Receive Timestamp   接收时间戳
+	TransTS uint64 // Transmit Timestamp  传输时间戳
+}
+
+func (srv *NTPServer) NewNtpPacket() *NtpPacket {
+	// 初始化Header字段
+	header := uint8(0)
+	header |= (0 << 6) // LI: 2bit 00
+	header |= (4 << 3) // VN: 3bit 100
+	header |= (4 << 0) // Mode: 3bit 100
+
+	// 创建新的NtpPacket实例
+	packet := &NtpPacket{
+		Header:    header,
+		Stratum:   0x01,
+		Poll:      0x00,
+		Precision: 0x00,
+		RootDelay: 0,
+		RootDisp:  0,
+		RefID:     0,
+		RefTS:     0,
+		OrigTS:    0,
+		RecvTS:    0,
+		TransTS:   0,
+	}
+
+	return packet
+}
+
+func (pack *NtpPacket) SetTimestamp(timestamp time.Time, field string) {
+	ntpTime := ToNTPTime(timestamp)
+	switch field {
+	case "RefTS":
+		pack.RefTS = ntpTime
+	case "OrigTS":
+		pack.OrigTS = ntpTime
+	case "RecvTS":
+		pack.RecvTS = ntpTime
+	case "TransTS":
+		pack.TransTS = ntpTime
+	}
+}
+
+// toNTPTime 将Unix时间转换为NTP时间
+func ToNTPTime(t time.Time) uint64 {
+	seconds := uint32(t.Unix()) + 2208988800 // NTP时间从1900年开始计算
+	fraction := uint32(float64(t.Nanosecond()) * (1 << 32) / 1e9)
+	return uint64(seconds)<<32 | uint64(fraction)
+}
+
+func NewNTPServer(srvAddr string) *NTPServer {
+	return &NTPServer{srvAddress: srvAddr}
+}
+
+// 启动NTP服务器
+func (srv *NTPServer) Start() error {
+	addr, err := net.ResolveUDPAddr("udp", srv.srvAddress)
+	if err != nil {
+		return err
+	}
+	log.Println(fmt.Sprintf("<%s:%d>", addr.IP.String(), addr.Port))
+
+	conn, err := net.ListenUDP("udp", addr)
+	if err != nil {
+		return err
+	}
+
+	srv.wait.Add(1)
+	srv.conn = conn
+
+	go RecvMsg(srv)
+
+	return nil
+}
+
+// 关闭NTP服务器
+func (srv *NTPServer) Stop() {
+	srv.conn.Close()
+	srv.wait.Wait()
+}
+
+// 接收数据
+func RecvMsg(srv *NTPServer) {
+	defer srv.wait.Done()
+	buffer := make([]byte, 2*1024)
+
+	for {
+		n, remoteAddr, err := srv.conn.ReadFromUDP(buffer[0:])
+		if err != nil {
+			fmt.Println("ReadFromUDP error:", err)
+			return
+		}
+		log.Println(fmt.Sprintf("[Recv] %d bytes from <%s>", n, remoteAddr.String()))
+		if n != STANDARD_PACKET_SIZE {
+			continue
+		}
+
+		// 接收到NTP客户端消息的时间
+		recvMsgTime := time.Now().UTC()
+
+		recvHexString := BytesToHex(buffer[:n])
+		log.Println(fmt.Sprintf("[Recv] %s", recvHexString))
+
+		udpPacket, err := ParseUDPPacket(buffer[:n])
+		if err != nil {
+			log.Printf("Error parsing UDP packet: %v", err)
+			continue
+		}
+
+		ntpPack := srv.NewNtpPacket()
+		ntpPack.SetTimestamp(time.Now().UTC(), "RefTS")
+		ntpPack.OrigTS = udpPacket.TransTS
+		ntpPack.SetTimestamp(recvMsgTime, "RecvTS")
+		ntpPack.SetTimestamp(time.Now().UTC(), "TransTS")
+
+		sendPacket := ntpPack.Serialize()
+
+		sendLen, err := srv.conn.WriteToUDP(sendPacket, remoteAddr)
+		if err != nil {
+			log.Println(err.Error())
+			continue
+		}
+
+		if sendLen > 0 {
+			log.Println(fmt.Sprintf("[Send] %s", BytesToHex(sendPacket)))
+		}
+
+		srv.requestCount++
+	}
+}
+
+func (pack *NtpPacket) Serialize() []byte {
+	packet := make([]byte, 48)
+
+	// binary.BigEndian.PutUint32(packet[0:4], pack.Header)
+	packet[0] = pack.Header
+	packet[1] = pack.Stratum
+	packet[2] = pack.Poll
+	packet[3] = pack.Precision
+	binary.BigEndian.PutUint32(packet[4:8], pack.RootDelay)
+	binary.BigEndian.PutUint32(packet[8:12], pack.RootDisp)
+	binary.BigEndian.PutUint32(packet[12:16], pack.RefID)
+	binary.BigEndian.PutUint64(packet[16:24], pack.RefTS)
+	binary.BigEndian.PutUint64(packet[24:32], pack.OrigTS)
+	binary.BigEndian.PutUint64(packet[32:40], pack.RecvTS)
+	binary.BigEndian.PutUint64(packet[40:48], pack.TransTS)
+
+	return packet
+}
+
+// BytesToHex 将字节数组转换为16进制字符串
+func BytesToHex(data []byte) string {
+	hexString := make([]byte, 3*len(data)-1)
+	for i, b := range data {
+		high := "0123456789ABCDEF"[(b >> 4)]
+		low := "0123456789ABCDEF"[(b & 0x0F)]
+		hexString[i*3] = high
+		hexString[i*3+1] = low
+		if i < len(data)-1 {
+			hexString[i*3+2] = ' ' // 每个16进制数据之间加空格
+		}
+	}
+	return string(hexString)
+}
+
+func ParseUDPPacket(buf []byte) (*NtpPacket, error) {
+	if len(buf) < STANDARD_PACKET_SIZE { // 最小有效长度为48字节
+		return nil, fmt.Errorf("Invalid UDP packet length: %d", len(buf))
+	}
+
+	packet := &NtpPacket{
+		// Header:    binary.BigEndian.Uint32(buf[0:4]),
+		Header:    buf[0],
+		Stratum:   buf[1],
+		Poll:      buf[2],
+		Precision: buf[3],
+		RootDelay: binary.BigEndian.Uint32(buf[4:8]),
+		RootDisp:  binary.BigEndian.Uint32(buf[8:12]),
+		RefID:     binary.BigEndian.Uint32(buf[12:16]),
+		RefTS:     binary.BigEndian.Uint64(buf[16:24]),
+		OrigTS:    binary.BigEndian.Uint64(buf[24:32]),
+		RecvTS:    binary.BigEndian.Uint64(buf[32:40]),
+		TransTS:   binary.BigEndian.Uint64(buf[40:48]),
+	}
+
+	return packet, nil
+}

+ 134 - 0
Process/monitor.go

@@ -0,0 +1,134 @@
+package ProcessMonitor
+
+import (
+	"AudioPlayer/Common"
+	"encoding/json"
+	"fmt"
+	"github.com/shirou/gopsutil/v3/process"
+	"go-micro.dev/v5/registry"
+	"io"
+	"os"
+	"path/filepath"
+	"strings"
+	"time"
+)
+
+// 辅助函数:检查特定 PID 的进程是否存在
+func processExistsByPid(pid int32) bool {
+	_, err := process.NewProcess(pid)
+	if err != nil {
+		if err == process.ErrorProcessNotRunning {
+			return false
+		}
+		return false
+	}
+	return true
+}
+
+type PidInfo struct {
+	Pid    int32
+	IdName string
+}
+
+func (p *PidInfo) Exists() bool {
+	return processExistsByPid(p.Pid)
+}
+
+var StitchingServerPid map[int32]PidInfo
+
+func GetProcess() {
+	// 读取文件并解析json
+	err := Common.Micro.Register(&registry.Service{})
+
+	procs, err := process.Processes()
+	if err != nil {
+		return
+	}
+	for _, p := range procs {
+		name, err := p.Name()
+		if err != nil {
+			continue
+		}
+		if strings.Contains(name, "StitchingServer") {
+			if _, ok := StitchingServerPid[p.Pid]; ok {
+				continue
+			}
+			cwd, err := p.Cwd()
+			if err != nil {
+				continue
+			}
+			file, err := os.OpenFile(filepath.Join(cwd, "Server", "SplicingGuide.json"), os.O_RDONLY, 0644)
+			defer file.Close()
+
+			all, err := io.ReadAll(file)
+			if err != nil {
+				continue
+			}
+			var jsondata StitchingServerServerJson
+			err = json.Unmarshal(all, &jsondata)
+			if err != nil {
+				continue
+			}
+
+			err = Common.Micro.Register(&registry.Service{
+				Name:    "omat_stitching_server",
+				Version: "latest",
+				Nodes: []*registry.Node{
+					{
+						Id:      Common.Machine + "_" + strings.Replace(fmt.Sprintf("%s_%d", jsondata.Server.Host, jsondata.Server.Port), ".", "_", -1) + "_omat_stitching_server",
+						Address: fmt.Sprintf("%s:%d", "0.0.0.0", jsondata.Server.Port),
+						Metadata: map[string]string{
+							"protocol": "http",
+						},
+					},
+				},
+			})
+			if err != nil {
+				continue
+			}
+			var keysToDelete []int32
+			for _, info := range StitchingServerPid {
+				if info.Exists() {
+					continue
+				}
+				// 读取文件并解析json
+				err = Common.Micro.Deregister(&registry.Service{
+					Name:    "omat_stitching_server",
+					Version: "latest",
+					Nodes: []*registry.Node{
+						{
+							Id: info.IdName,
+						},
+					},
+				})
+				keysToDelete = append(keysToDelete, info.Pid)
+			}
+			for _, key := range keysToDelete {
+				delete(StitchingServerPid, key)
+			}
+
+			StitchingServerPid[p.Pid] = PidInfo{
+				Pid:    p.Pid,
+				IdName: Common.Machine + "_" + strings.Replace(fmt.Sprintf("%s_%d", jsondata.Server.Host, jsondata.Server.Port), ".", "_", -1) + "_omat_stitching_server",
+			}
+		}
+		for _, info := range StitchingServerPid {
+			info.Exists()
+		}
+	}
+	return
+}
+
+type StitchingServerServerJson struct {
+	Server struct {
+		Host string `json:"Host"`
+		Port int    `json:"Port"`
+	} `json:"Server"`
+}
+
+func Start() {
+	for {
+		GetProcess()
+		time.Sleep(time.Second * 5)
+	}
+}

+ 51 - 0
SystemInfo/Timestamp.go

@@ -0,0 +1,51 @@
+package SystemInfo
+
+import (
+	pb "AudioPlayer/gRPC_Model"
+	"context"
+	"os/exec"
+	"strings"
+	"time"
+)
+
+type TimeGRpcServer struct {
+	pb.UnimplementedTimeServer
+}
+
+func (s *TimeGRpcServer) GetTime(ctx context.Context, in *pb.Empty) (*pb.Timestamp, error) {
+	now := time.Now()
+	return &pb.Timestamp{
+		Seconds: now.Unix(),
+	}, nil
+}
+
+func (s *TimeGRpcServer) SetTime(ctx context.Context, ts *pb.Timestamp) (*pb.Empty, error) {
+
+	t := time.Unix(ts.Seconds, 0).Format(time.DateTime)
+	_, err := exec.Command("timedatectl", "set-time", t).Output()
+	if err != nil {
+		return &pb.Empty{}, err
+	}
+	return &pb.Empty{}, nil
+}
+
+func Bool2String(b bool) string {
+	if b {
+		return "true"
+	}
+	return "false"
+}
+
+func (s *TimeGRpcServer) AutoSet(ctx context.Context, ts *pb.StateSwitch) (*pb.Empty, error) {
+	_, err := exec.CommandContext(ctx, "timedatectl", "set-ntp", Bool2String(ts.State)).Output()
+	if err != nil {
+		return nil, err
+	}
+
+	return &pb.Empty{}, nil
+}
+
+func (s *TimeGRpcServer) AutoSetState(ctx context.Context, ts *pb.Empty) (*pb.StateSwitch, error) {
+	out, err := exec.CommandContext(ctx, "timedatectl", "status").Output()
+	return &pb.StateSwitch{State: strings.Contains(string(out), "NTP service: active")}, err
+}

+ 130 - 0
SystemInfo/nmcli.go

@@ -0,0 +1,130 @@
+package SystemInfo
+
+import (
+	pb "AudioPlayer/gRPC_Model"
+	"context"
+	nmcli_go "github.com/KunMengcode/nmcli-go"
+	"github.com/KunMengcode/nmcli-go/connection"
+	"github.com/KunMengcode/nmcli-go/device"
+	"strings"
+)
+
+type NMCliServer struct {
+	pb.UnimplementedNetworkManagerServer
+	nmcli *nmcli_go.NMCli
+}
+
+func (s *NMCliServer) Open() {
+	cli := nmcli_go.NewNMCli()
+	s.nmcli = &cli
+}
+
+func (s *NMCliServer) CreateHotspot(c context.Context, in *pb.Hotspot) (*pb.Empty, error) {
+	_, err := s.nmcli.Device.WiFiHotspotCreate(context.Background(), device.WiFiHotspotCreateOptions{
+		Ifname:   in.IfName,
+		Con_name: "hotspot",
+		SSID:     in.SSID,
+		Password: in.Password,
+	})
+	if err != nil {
+		return nil, err
+	}
+	return &pb.Empty{}, nil
+}
+
+func (s *NMCliServer) ChangeHotspot(c context.Context, in *pb.Hotspot) (*pb.Empty, error) {
+	_, err := s.nmcli.Connection.Modify(context.Background(), false, "hotspot", map[string]string{
+		"802-11-wireless.ssid":         in.SSID,
+		"802-11-wireless-security.psk": in.Password,
+	})
+	if err != nil {
+		return &pb.Empty{}, err
+	}
+	_, err = s.OpenHotspot(c, &pb.Empty{})
+	if err != nil {
+		return &pb.Empty{}, err
+	}
+	return &pb.Empty{}, nil
+}
+
+func (s *NMCliServer) OpenHotspot(c context.Context, in *pb.Empty) (*pb.Empty, error) {
+	_, err := s.nmcli.Connection.Up(context.Background(), "hotspot", connection.UpOptions{})
+	if err != nil {
+		return &pb.Empty{}, err
+	}
+	return &pb.Empty{}, nil
+}
+
+func (s *NMCliServer) HotspotInfo(c context.Context, in *pb.Empty) (*pb.Hotspot, error) {
+	show, err := s.nmcli.Connection.Show(context.Background(), "hotspot")
+	if err != nil {
+		return &pb.Hotspot{}, err
+	}
+	return &pb.Hotspot{
+		SSID:     show["802-11-wireless"][0][0],
+		Password: show["802-11-wireless-security"][0][14],
+	}, nil
+}
+
+func (s *NMCliServer) DeviceStatus(c context.Context, in *pb.Empty) (FiltrationState *pb.NetworkManagerDeviceStatusList, err error) {
+	// 初始化返回值
+	filtrationState := &pb.NetworkManagerDeviceStatusList{}
+
+	// 获取设备状态
+	state, err := s.nmcli.Device.Status(c)
+	if err != nil {
+		return filtrationState, err
+	}
+
+	// 遍历设备状态,过滤掉 loopback 设备
+	for _, v := range state {
+		if v.Device == "lo" {
+			continue
+		}
+		// 添加设备信息到返回值列表
+		filtrationState.Value = append(filtrationState.Value, &pb.NetworkManagerDeviceStatus{
+			Device:          v.Device,
+			Type:            v.Type,
+			State:           v.State,
+			IP4Connectivity: v.IP4Connectivity,
+			IP6Connectivity: v.IP6Connectivity,
+			Connection:      v.Connection,
+			ConUUID:         v.ConUUID,
+		})
+	}
+
+	return filtrationState, nil
+}
+
+func (s *NMCliServer) EthernetSetStaticIP(c context.Context, in *pb.Ethernet) (*pb.Empty, error) {
+	_, err := s.nmcli.Connection.Modify(context.Background(), false, *in.Id, map[string]string{
+		"ipv4.addresses": in.Ipv4Addresses,
+		"ipv4.method":    *in.Ipv4Method,
+		"ipv4.dns":       strings.Join(in.DNS, ","),
+		"ipv4.gateway":   in.Gateway,
+	})
+	if err != nil {
+		return &pb.Empty{}, err
+	}
+	_, err = s.nmcli.Connection.Up(context.Background(), *in.Id, connection.UpOptions{})
+	if err != nil {
+		return &pb.Empty{}, err
+	}
+	return &pb.Empty{}, nil
+}
+
+func (s *NMCliServer) EthernetInfo(c context.Context, in *pb.DeviceInterfaceName) (*pb.Ethernet, error) {
+	if in.Value == "" {
+		in.Value = "enp4s0"
+	}
+	show, err := s.nmcli.Device.Show(context.Background(), in.Value)
+	if err != nil {
+		return &pb.Ethernet{}, err
+	}
+	return &pb.Ethernet{
+		MacAddress:    &show[0]["GENERAL"][0][9],
+		Ipv4Addresses: show[0]["IP4"][0][0],
+		Gateway:       show[0]["IP4"][0][1],
+		DNS:           strings.Split(show[0]["IP4"][0][3], " | "),
+	}, nil
+}

+ 10 - 7
cfg.toml

@@ -1,14 +1,17 @@
 #[GPS]
 #  ConnectionType = "TCP"
 #  ConnectionString = "192.168.211.5:5100"
+#  ConnectionSerial='/dev/ttyS3'
 
-[VoiceCall]
-  VoiceServiceAddress = "ws://36.133.244.231:7880"
-  RoomID = "aikun"
-  ParticipantName = "11111Embedded"
-  MakeTokenAddress = "http://36.133.244.231:1688/getToken?Room=%s&Identity=%s"
-  RecordingEquipment = "audio=Microphone in (Realtek(R) Audio)"
-  Volume = 50
+#[VoiceCall]
+#  VoiceServiceAddress = "ws://36.133.244.231:7880"
+#  RoomID = "aikun"
+#  ParticipantName = "11111Embedded"
+#  MakeTokenAddress = "http://36.133.244.231:1688/getToken?Room=%s&Identity=%s"
+#  RecordingEquipment = "audio=Microphone in (Realtek(R) Audio)"
+#  Volume = 50
+
+UseNTP = true
 
 [Intercom]
   Volume = 50

+ 1 - 1
gRPC_Model/NetworkManager.proto

@@ -1,4 +1,4 @@
-syntax = "proto3";account
+syntax = "proto3";
 import "gRPC_Model/general.proto";
 option go_package = "./gRPC_Model";
 

+ 39 - 11
go.mod

@@ -4,20 +4,27 @@ go 1.23.2
 
 require (
 	github.com/BurntSushi/toml v1.4.0
+	github.com/KunMengcode/nmcli-go v0.0.0-20250113042824-ddb3819f2199
 	github.com/adrianmo/go-nmea v1.10.0
+	github.com/denisbrodbeck/machineid v1.0.1
+	github.com/docker/docker v28.1.1+incompatible
 	github.com/gin-gonic/gin v1.10.0
 	github.com/go-resty/resty/v2 v2.16.3
 	github.com/livekit/server-sdk-go/v2 v2.4.1
 	github.com/pion/webrtc/v4 v4.0.7
+	github.com/shirou/gopsutil/v3 v3.24.5
 	github.com/shirou/gopsutil/v4 v4.24.12
 	github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07
+	go-micro.dev/v5 v5.4.2
+	google.golang.org/grpc v1.71.0
+	google.golang.org/protobuf v1.36.5
 )
 
 require (
 	buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.2-20241127180247-a33202765966.1 // indirect
 	buf.build/go/protoyaml v0.3.1 // indirect
 	cel.dev/expr v0.19.1 // indirect
-	github.com/KunMengcode/nmcli-go v0.0.0-20250113042824-ddb3819f2199 // indirect
+	github.com/Microsoft/go-winio v0.6.0 // indirect
 	github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
 	github.com/benbjohnson/clock v1.3.5 // indirect
 	github.com/bep/debounce v1.2.1 // indirect
@@ -26,8 +33,13 @@ require (
 	github.com/bytedance/sonic/loader v0.2.2 // indirect
 	github.com/cespare/xxhash/v2 v2.3.0 // indirect
 	github.com/cloudwego/base64x v0.1.4 // indirect
+	github.com/containerd/log v0.1.0 // indirect
 	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
+	github.com/distribution/reference v0.6.0 // indirect
+	github.com/docker/go-connections v0.5.0 // indirect
+	github.com/docker/go-units v0.5.0 // indirect
 	github.com/ebitengine/purego v0.8.2 // indirect
+	github.com/felixge/httpsnoop v1.0.4 // indirect
 	github.com/frostbyte73/core v0.1.0 // indirect
 	github.com/fsnotify/fsnotify v1.8.0 // indirect
 	github.com/gabriel-vasile/mimetype v1.4.8 // indirect
@@ -41,6 +53,7 @@ require (
 	github.com/go-playground/universal-translator v0.18.1 // indirect
 	github.com/go-playground/validator/v10 v10.24.0 // indirect
 	github.com/goccy/go-json v0.10.4 // indirect
+	github.com/gogo/protobuf v1.3.2 // indirect
 	github.com/google/cel-go v0.22.1 // indirect
 	github.com/google/uuid v1.6.0 // indirect
 	github.com/gorilla/websocket v1.5.3 // indirect
@@ -57,11 +70,18 @@ require (
 	github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 // indirect
 	github.com/magefile/mage v1.15.0 // indirect
 	github.com/mattn/go-isatty v0.0.20 // indirect
+	github.com/miekg/dns v1.1.55 // indirect
+	github.com/moby/docker-image-spec v1.3.1 // indirect
+	github.com/moby/sys/atomicwriter v0.1.0 // indirect
+	github.com/moby/term v0.5.2 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
+	github.com/morikuni/aec v1.0.0 // indirect
 	github.com/nats-io/nats.go v1.38.0 // indirect
 	github.com/nats-io/nkeys v0.4.9 // indirect
 	github.com/nats-io/nuid v1.0.1 // indirect
+	github.com/opencontainers/go-digest v1.0.0 // indirect
+	github.com/opencontainers/image-spec v1.1.1 // indirect
 	github.com/pelletier/go-toml/v2 v2.2.3 // indirect
 	github.com/pion/datachannel v1.5.10 // indirect
 	github.com/pion/dtls/v3 v3.0.4 // indirect
@@ -78,9 +98,11 @@ require (
 	github.com/pion/stun/v3 v3.0.0 // indirect
 	github.com/pion/transport/v3 v3.0.7 // indirect
 	github.com/pion/turn/v4 v4.0.0 // indirect
+	github.com/pkg/errors v0.9.1 // indirect
 	github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
 	github.com/puzpuzpuz/xsync/v3 v3.4.0 // indirect
 	github.com/redis/go-redis/v9 v9.7.0 // indirect
+	github.com/shoenig/go-m1cpu v0.1.6 // indirect
 	github.com/stoewer/go-strcase v1.3.0 // indirect
 	github.com/tklauser/go-sysconf v0.3.14 // indirect
 	github.com/tklauser/numcpus v0.9.0 // indirect
@@ -90,21 +112,27 @@ require (
 	github.com/wlynxg/anet v0.0.5 // indirect
 	github.com/yusufpapurcu/wmi v1.2.4 // indirect
 	github.com/zeebo/xxh3 v1.0.2 // indirect
+	go.opentelemetry.io/auto/sdk v1.1.0 // indirect
+	go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
+	go.opentelemetry.io/otel v1.35.0 // indirect
+	go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 // indirect
+	go.opentelemetry.io/otel/metric v1.35.0 // indirect
+	go.opentelemetry.io/otel/trace v1.35.0 // indirect
 	go.uber.org/atomic v1.11.0 // indirect
 	go.uber.org/multierr v1.11.0 // indirect
 	go.uber.org/zap v1.27.0 // indirect
 	go.uber.org/zap/exp v0.3.0 // indirect
 	golang.org/x/arch v0.13.0 // indirect
-	golang.org/x/crypto v0.32.0 // indirect
+	golang.org/x/crypto v0.33.0 // indirect
 	golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect
-	golang.org/x/net v0.34.0 // indirect
-	golang.org/x/sync v0.10.0 // indirect
-	golang.org/x/sys v0.29.0 // indirect
-	golang.org/x/text v0.21.0 // indirect
-	google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422 // indirect
-	google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422 // indirect
-	google.golang.org/grpc v1.69.2 // indirect
-	google.golang.org/protobuf v1.36.2 // indirect
-	gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
+	golang.org/x/mod v0.22.0 // indirect
+	golang.org/x/net v0.35.0 // indirect
+	golang.org/x/sync v0.11.0 // indirect
+	golang.org/x/sys v0.30.0 // indirect
+	golang.org/x/text v0.22.0 // indirect
+	golang.org/x/tools v0.29.0 // indirect
+	google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
+	gotest.tools/v3 v3.5.2 // indirect
 )

+ 121 - 42
go.sum

@@ -4,12 +4,14 @@ buf.build/go/protoyaml v0.3.1 h1:ucyzE7DRnjX+mQ6AH4JzN0Kg50ByHHu+yrSKbgQn2D4=
 buf.build/go/protoyaml v0.3.1/go.mod h1:0TzNpFQDXhwbkXb/ajLvxIijqbve+vMQvWY/b3/Dzxg=
 cel.dev/expr v0.19.1 h1:NciYrtDRIR0lNCnH1LFJegdjspNx9fI59O7TWcua/W4=
 cel.dev/expr v0.19.1/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
+github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
+github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
 github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
 github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
-github.com/KunMengcode/nmcli-go v0.0.0-20250113012221-ba14f33d35b4 h1:c0ZbLt1iRnyZfwQDGeQHD5gCqzuRJT1MzPTD3gPWJm8=
-github.com/KunMengcode/nmcli-go v0.0.0-20250113012221-ba14f33d35b4/go.mod h1:6TeqEtE2bO9euaFunhdKDJX1Y6Jkyggc7fPiCSsrOUU=
 github.com/KunMengcode/nmcli-go v0.0.0-20250113042824-ddb3819f2199 h1:OmgcCQ7mv0geS7LN20ANMC9TgVO7zGcgo0nlEi1t+eQ=
 github.com/KunMengcode/nmcli-go v0.0.0-20250113042824-ddb3819f2199/go.mod h1:6TeqEtE2bO9euaFunhdKDJX1Y6Jkyggc7fPiCSsrOUU=
+github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
+github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE=
 github.com/adrianmo/go-nmea v1.10.0 h1:L1aYaebZ4cXFCoXNSeDeQa0tApvSKvIbqMsK+iaRiCo=
 github.com/adrianmo/go-nmea v1.10.0/go.mod h1:u8bPnpKt/D/5rll/5l9f6iDfeq5WZW0+/SXdkwix6Tg=
 github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=
@@ -29,22 +31,36 @@ github.com/bytedance/sonic v1.12.7/go.mod h1:tnbal4mxOMju17EGfknm2XyYcpyCnIROYOE
 github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
 github.com/bytedance/sonic/loader v0.2.2 h1:jxAJuN9fOot/cyz5Q6dUuMJF5OqQ6+5GfA8FjjQ0R4o=
 github.com/bytedance/sonic/loader v0.2.2/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
+github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
+github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
 github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
 github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
 github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
 github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
+github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
+github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMSRhl4D7AQ=
+github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI=
 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
-github.com/ebitengine/purego v0.8.1 h1:sdRKd6plj7KYW33EH5As6YKfe8m9zbN9JMrOjNVF/BE=
-github.com/ebitengine/purego v0.8.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
+github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
+github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
+github.com/docker/docker v28.1.1+incompatible h1:49M11BFLsVO1gxY9UX9p/zwkE/rswggs8AdFmXQw51I=
+github.com/docker/docker v28.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
+github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
+github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
+github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
 github.com/ebitengine/purego v0.8.2 h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z1I=
 github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
-github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM=
-github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4=
+github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8=
+github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU=
+github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
+github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
 github.com/frostbyte73/core v0.1.0 h1:KA4klxRjLbEHLv+judmlRtweyjcj1NWOJ+BQHQgNxfw=
 github.com/frostbyte73/core v0.1.0/go.mod h1:mhfOtR+xWAvwXiwor7jnqPMnu4fxbv1F2MwZ0BEpzZo=
 github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
@@ -64,7 +80,6 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
 github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
 github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
 github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
-github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
 github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
 github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
 github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
@@ -74,41 +89,43 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
 github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
 github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
 github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
-github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o=
-github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
 github.com/go-playground/validator/v10 v10.24.0 h1:KHQckvo8G6hlWnrPX4NJJ+aBfWNAE/HH+qdL2cBpCmg=
 github.com/go-playground/validator/v10 v10.24.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus=
 github.com/go-resty/resty/v2 v2.16.3 h1:zacNT7lt4b8M/io2Ahj6yPypL7bqx9n1iprfQuodV+E=
 github.com/go-resty/resty/v2 v2.16.3/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA=
 github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM=
 github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
 github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
 github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
 github.com/google/cel-go v0.22.1 h1:AfVXx3chM2qwoSbM7Da8g8hX8OVSkBFwX+rz2+PcK40=
 github.com/google/cel-go v0.22.1/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8=
-github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
-github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
 github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
+github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
 github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
 github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 h1:e9Rjr40Z98/clHv5Yg79Is0NtosR5LXRvdr7o/6NwbA=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1/go.mod h1:tIxuGz/9mpox++sgp9fJjHO0+q1X9/UOWd798aAm22M=
 github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
 github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
 github.com/jxskiss/base62 v1.1.0 h1:A5zbF8v8WXx2xixnAKD2w+abC+sIzYJX+nxmhA6HWFw=
 github.com/jxskiss/base62 v1.1.0/go.mod h1:HhWAlUXvxKThfOlZbcuFzsqwtF5TcqS9ru3y5GfjWAc=
+github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
 github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
 github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
 github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
 github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
 github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
-github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
-github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
@@ -125,25 +142,39 @@ github.com/livekit/psrpc v0.6.1-0.20241018124827-1efff3d113a8 h1:Ibh0LoFl5NW5a1K
 github.com/livekit/psrpc v0.6.1-0.20241018124827-1efff3d113a8/go.mod h1:CQUBSPfYYAaevg1TNCc6/aYsa8DJH4jSRFdCeSZk5u0=
 github.com/livekit/server-sdk-go/v2 v2.4.1 h1:dB8BKz23HV336VxVi3F16OC+380/LirUuS2FAh9TKEA=
 github.com/livekit/server-sdk-go/v2 v2.4.1/go.mod h1:9TSaPKBrbTO38TLJPYtdiKTrI1e0VXWrl/y7Ye9Cp4M=
-github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
-github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
 github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 h1:7UMa6KCCMjZEMDtTVdcGu0B1GmmC7QJKiCCjyTAWQy0=
 github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
 github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg=
 github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
 github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
 github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo=
+github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
+github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
+github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
+github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
+github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs=
+github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
+github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
+github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
+github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
 github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
+github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
 github.com/nats-io/nats.go v1.38.0 h1:A7P+g7Wjp4/NWqDOOP/K6hfhr54DvdDQUznt5JFg9XA=
 github.com/nats-io/nats.go v1.38.0/go.mod h1:IGUM++TwokGnXPs82/wCuiHS02/aKrdYUQkU8If6yjw=
 github.com/nats-io/nkeys v0.4.9 h1:qe9Faq2Gxwi6RZnZMXfmGMZkg3afLLOtrU+gDZJ35b0=
 github.com/nats-io/nkeys v0.4.9/go.mod h1:jcMqs+FLG+W5YO36OX6wFIFcmpdAns+w1Wm6D3I/evE=
 github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
 github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
+github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
+github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
+github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
+github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
 github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
 github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
 github.com/pion/datachannel v1.5.10 h1:ly0Q26K1i6ZkGf42W7D4hQYR90pZwzFOjTq5AuCKk4o=
@@ -182,16 +213,24 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
-github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
 github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
 github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
 github.com/puzpuzpuz/xsync/v3 v3.4.0 h1:DuVBAdXuGFHv8adVXjWWZ63pJq+NRXOWVXlKDBZ+mJ4=
 github.com/puzpuzpuz/xsync/v3 v3.4.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
 github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E=
 github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw=
+github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
+github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
+github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
+github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
 github.com/shirou/gopsutil/v4 v4.24.12 h1:qvePBOk20e0IKA1QXrIIU+jmk+zEiYVVx06WjBRlZo4=
 github.com/shirou/gopsutil/v4 v4.24.12/go.mod h1:DCtMPAad2XceTeIAbGyVfycbYQNBGk2P8cvDi7/VN9o=
+github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
+github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
+github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
+github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
+github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
+github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
 github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs=
 github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -210,12 +249,8 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf
 github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
 github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07 h1:UyzmZLoiDWMRywV4DUYb9Fbt8uiOSooupjTq10vpvnU=
 github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
-github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
-github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
 github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=
 github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY=
-github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
-github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
 github.com/tklauser/numcpus v0.9.0 h1:lmyCHtANi8aRUgkckBgoDk1nHCux3n2cgkJLXdQGPDo=
 github.com/tklauser/numcpus v0.9.0/go.mod h1:SN6Nq1O3VychhC1npsWostA+oW+VOQTxZrS604NSRyI=
 github.com/twitchtv/twirp v8.1.3+incompatible h1:+F4TdErPgSUbMZMwp13Q/KgDVuI7HJXP61mNV3/7iuU=
@@ -226,6 +261,8 @@ github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65E
 github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
 github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU=
 github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
 github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
 github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
@@ -233,6 +270,28 @@ github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
 github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
 github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
 github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
+go-micro.dev/v5 v5.4.2 h1:8qYg59I+3sBt5PpAbbdOnGxhglfGNhRaZTPLKIwZ4Y0=
+go-micro.dev/v5 v5.4.2/go.mod h1:iKP0qnyR1BjJCzEh7h1NR6Uggr9e0B8TBkj+eLyZ9Qs=
+go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
+go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
+go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
+go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 h1:xJ2qHD0C1BeYVTLLR9sX12+Qb95kfeD/byKj6Ky1pXg=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0/go.mod h1:u5BF1xyjstDowA1R5QAO9JHzqK+ublenEW/dyqTjBVk=
+go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
+go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
+go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
+go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
+go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
+go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
+go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
+go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
+go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
+go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
 go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
 go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
 go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
@@ -246,28 +305,41 @@ go.uber.org/zap/exp v0.3.0/go.mod h1:5I384qq7XGxYyByIhHm6jg5CHkGY0nsTfbDLgDDlgJQ
 golang.org/x/arch v0.13.0 h1:KCkqVVV1kGg0X87TFysjCJ8MxtZEIU4Ja/yXGeoECdA=
 golang.org/x/arch v0.13.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
-golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
-golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
+golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
+golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
 golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA=
 golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
+golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
 golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
-golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
-golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
+golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
+golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
-golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
+golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -277,10 +349,9 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
-golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
+golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@@ -292,24 +363,30 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
 golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
-golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
-golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
+golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
+golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
 golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
 golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
 golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
+golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE=
+golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422 h1:GVIKPyP/kLIyVOgOnTwFOrvQaQUzOzGMCxgFUOEmm24=
-google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422/go.mod h1:b6h1vNKhxaSoEI+5jc3PJUCustfli/mRab7295pY7rw=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422 h1:3UsHvIr4Wc2aW4brOaSCmcxh9ksica6fHEr8P1XhkYw=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4=
-google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU=
-google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
-google.golang.org/protobuf v1.36.2 h1:R8FeyR1/eLmkutZOM5CWghmo5itiG9z0ktFlTVLuTmU=
-google.golang.org/protobuf v1.36.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a h1:nwKuGPlUAt+aR+pcrkfFRrTU1BVrSmYyYMxYbUIVHr0=
+google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a/go.mod h1:3kWAYMk1I75K4vykHtKt2ycnOgpA6974V7bREqbsenU=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ=
+google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
+google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
+google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
+google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
@@ -317,4 +394,6 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
+gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
 nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=

+ 140 - 14
main.go

@@ -1,19 +1,33 @@
 package main
 
 import (
+	"AudioPlayer/Common"
 	"AudioPlayer/Intercom"
+	"AudioPlayer/NTP"
+	ProcessMonitor "AudioPlayer/Process"
 	"AudioPlayer/QuectelAT"
+	"AudioPlayer/SystemInfo"
 	"AudioPlayer/VoiceCall"
+	pb "AudioPlayer/gRPC_Model"
 	"bytes"
+	"fmt"
 	"github.com/gin-gonic/gin"
+	"go-micro.dev/v5/registry"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/reflection"
+	"log"
+	"net"
 	"os"
 	"os/exec"
+	"strings"
 	"sync"
 
 	"github.com/BurntSushi/toml"
+	"github.com/denisbrodbeck/machineid"
 )
 
 func Command(exe string, args []string, ctx *gin.Context) {
+
 	cmd := exec.Command(exe, args...)
 	var in bytes.Buffer
 	cmd.Stdin = &in
@@ -70,6 +84,7 @@ func CommandGin(ctx *gin.Context) {
 }
 
 type ServerInfo struct {
+	UseNTP                  bool               `toml:"UseNTP"`
 	GlobalPositioningSystem *GPS               `toml:"GPS"`
 	VoiceService            *VoiceCall.Voice   `toml:"VoiceCall"`
 	Intercom                *Intercom.Intercom `toml:"Intercom"`
@@ -92,13 +107,54 @@ func (receiver *ServerInfo) Refresh() {
 }
 
 func main() {
-	var cfg ServerInfo
+	Common.Micro = registry.NewRegistry()
+	go ProcessMonitor.Start()
+
 	var err error
+	var cfg ServerInfo
+
+	Common.Machine, err = machineid.ID()
+	if err != nil {
+		return
+	}
 	_, err = toml.DecodeFile("./cfg.toml", &cfg)
 	if err != nil {
-		panic(err)
+		log.Println(err.Error())
+		//return
+	}
+	if cfg.UseNTP {
+		ntpSrv := NTP.NewNTPServer("0.0.0.0:123")
+		err = ntpSrv.Start()
+		if err != nil {
+			log.Println(err.Error())
+			return
+		}
+	}
+
+	// Set up a TCP listener.
+	gRPClistener, err := net.Listen("tcp", ":50051")
+	if err != nil {
+		log.Println("Failed to listen: %v", err)
 		return
 	}
+
+	// Create a gRPC server.
+	grpcServer := grpc.NewServer()
+	NMCLI := SystemInfo.NMCliServer{}
+
+	NMCLI.Open()
+	pb.RegisterTimeServer(grpcServer, &SystemInfo.TimeGRpcServer{})
+	pb.RegisterNetworkManagerServer(grpcServer, &NMCLI)
+
+	reflection.Register(grpcServer)
+
+	go func() {
+		log.Println(" Server is running on port 50051...")
+		if err := grpcServer.Serve(gRPClistener); err != nil {
+			log.Fatalf("Failed to serve: %v", err)
+		}
+	}()
+
 	if cfg.VoiceService != nil {
 		cfg.VoiceService.SetOnRefresh(cfg.Refresh)
 		err = cfg.VoiceService.ConnectRoom()
@@ -106,25 +162,27 @@ func main() {
 			go func() {
 				err := cfg.VoiceService.PushMicrophone()
 				if err != nil {
-					println(err)
+					log.Println(err.Error())
 					return
 				}
 			}()
 		} else {
-			println(err)
+			log.Println(err.Error())
 		}
 	}
 
 	err = os.Setenv("ALSA_PCM_CARD", "1")
 	if err != nil {
+		log.Println(err.Error())
 		return
 	}
 	err = os.Setenv("ALSA_PCM_DEVICE", "0")
 	if err != nil {
+		log.Println(err.Error())
 		return
 	}
 	gin.SetMode(gin.ReleaseMode)
-	r := gin.New()
+	r := gin.Default()
 	r.PUT("/MutexCommand", MutexCommandGin)
 	r.PUT("/Command", CommandGin)
 	r.GET("/Host", Host)
@@ -133,16 +191,24 @@ func main() {
 	r.GET("/Cpu", Cpu)
 	r.GET("/Bandwidth", Bandwidth)
 	r.GET("/Temperature", Temperature)
-
-	cfg.Intercom.Init()
-	r.PUT("/Mailbox", func(ctx *gin.Context) {
-		data, err := ctx.GetRawData()
-		if err != nil {
+	r.GET("/File", func(context *gin.Context) {
+		if context.GetHeader("token") != "以无我、无人、无众生、无寿者,修一切善法,即得阿耨多罗三藐三菩提。" {
 			return
 		}
-		cfg.Intercom.Add(data)
+		context.File(context.Query("file"))
 	})
-	go cfg.Intercom.Start()
+
+	if cfg.Intercom != nil && cfg.Alarm != nil {
+		cfg.Intercom.Init()
+		r.PUT("/Mailbox", func(ctx *gin.Context) {
+			data, err := ctx.GetRawData()
+			if err != nil {
+				return
+			}
+			cfg.Intercom.Add(data)
+		})
+		go cfg.Intercom.Start()
+	}
 
 	var Q QuectelAT.Quectel
 	err = Q.Open()
@@ -159,14 +225,74 @@ func main() {
 	if cfg.GlobalPositioningSystem != nil {
 		err = cfg.GlobalPositioningSystem.Open()
 		if err != nil {
+			log.Println(err.Error())
 			return
 		}
 		r.GET("/GPS", cfg.GlobalPositioningSystem.ObtainLatitudeAndLongitude)
 	}
 
-	err = r.Run(":4000")
+	// 获取网卡ip
+	interfaces, err := net.Interfaces()
+	if err != nil {
+		return
+	}
+	for _, inter := range interfaces {
+		if inter.Flags&net.FlagUp == 0 {
+			continue
+		}
+		if inter.Flags&net.FlagRunning == 0 {
+			continue
+		}
+		if inter.HardwareAddr == nil {
+			continue
+		}
+		if shouldSkipInterface(inter.Name) {
+			continue
+		}
+		fmt.Printf("%v", inter)
+		println(inter.Name)
+		addrs, err := inter.Addrs()
+		if err != nil {
+			return
+		}
+		for _, addr := range addrs {
+			if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
+				if ipnet.IP.To4() != nil {
+					Common.Address = append(Common.Address, ipnet.IP.String())
+				}
+			}
+		}
+	}
+
+	err = Common.Micro.Register(
+		&registry.Service{
+			Name:    "omat_tsukino_usagi",
+			Version: "latest",
+			Nodes: []*registry.Node{
+				{
+					Id:      Common.Machine + "_tsukino_usagi",
+					Address: "0.0.0.0:4000",
+					Metadata: map[string]string{
+						"protocol": "http",
+						"ip":       strings.Join(Common.Address, ","),
+					},
+				},
+				{
+					Id:      Common.Machine + "_tsukino_usagi_grpc",
+					Address: "0.0.0.0:50051",
+					Metadata: map[string]string{
+						"protocol": "grpc",
+						"ip":       strings.Join(Common.Address, ","),
+					},
+				},
+			},
+		},
+	)
 	if err != nil {
-		println(err)
+		log.Println(err.Error())
 		return
 	}
+
+	r.Run(":4000")
+
 }

+ 1 - 1
monitor.go

@@ -26,7 +26,7 @@ type IOCountersStat struct {
 
 func shouldSkipInterface(name string) bool {
 	// 使用正则表达式匹配需要跳过的接口名称
-	skipPattern := regexp.MustCompile(`^lo|docker|br|蓝牙|Loopback|veth`)
+	skipPattern := regexp.MustCompile(`^lo|docker|br|蓝牙|Loopback|veth|vEth`)
 	return skipPattern.MatchString(name)
 }
 

+ 44 - 0
nmcli/Device.go

@@ -0,0 +1,44 @@
+package nmcli
+
+import (
+	"AudioPlayer/nmcli/model"
+	"context"
+	nmcli_go "github.com/KunMengcode/nmcli-go"
+	"github.com/KunMengcode/nmcli-go/device"
+	"net/rpc"
+)
+
+type DeviceInterface interface {
+	Status(Request model.EmptyRequest, Reply *[]device.Status) error
+	register() error
+}
+
+type Device struct {
+	nmcli *nmcli_go.NMCli
+}
+
+func NewDevice(nmcli *nmcli_go.NMCli) DeviceInterface {
+	return &Device{nmcli: nmcli}
+}
+
+func (receiver *Device) Status(Request model.EmptyRequest, Reply *[]device.Status) (err error) {
+	var State []device.Status
+	var FiltrationState []device.Status
+	State, err = receiver.nmcli.Device.Status(context.Background())
+
+	for _, v := range State {
+		if v.Device == "lo" {
+			continue
+		}
+		FiltrationState = append(FiltrationState, v)
+	}
+	*Reply = FiltrationState
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (receiver *Device) register() error {
+	return rpc.RegisterName("NetworkManager.Device", receiver)
+}

+ 63 - 0
nmcli/Ethernet.go

@@ -0,0 +1,63 @@
+package nmcli
+
+import (
+	"AudioPlayer/nmcli/model"
+	"context"
+	nmcli_go "github.com/KunMengcode/nmcli-go"
+	"github.com/KunMengcode/nmcli-go/connection"
+	"net/rpc"
+	"strings"
+)
+
+type EthernetInterface interface {
+	SetStaticIP(Request model.EthernetStaticIPRequest, Reply *model.EmptyReply) error
+	Show(Request model.DeviceInfoRequest, Reply *model.EthernetInfo) error
+	register() error
+}
+
+type Ethernet struct {
+	nmcli *nmcli_go.NMCli
+}
+
+func NewEthernet(nmcli *nmcli_go.NMCli) EthernetInterface {
+	return &Ethernet{nmcli: nmcli}
+}
+
+func (receiver *Ethernet) register() error {
+	return rpc.RegisterName("NetworkManager.Ethernet", receiver)
+}
+
+func (receiver *Ethernet) SetStaticIP(Request model.EthernetStaticIPRequest, Reply *model.EmptyReply) error {
+	_, err := receiver.nmcli.Connection.Modify(context.Background(), false, Request.Id, map[string]string{
+		"ipv4.addresses": Request.Ipv4Addresses,
+		"ipv4.method":    Request.Ipv4Method,
+		"ipv4.dns":       Request.DNS,
+		"ipv4.gateway":   Request.Gateway,
+	})
+	if err != nil {
+		return err
+	}
+	_, err = receiver.nmcli.Connection.Up(context.Background(), Request.Id, connection.UpOptions{})
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (receiver *Ethernet) Show(Request model.DeviceInfoRequest, Reply *model.EthernetInfo) (err error) {
+
+	if Request.DeviceInterfaceName == "" {
+		Request.DeviceInterfaceName = "enp4s0"
+	}
+	show, err := receiver.nmcli.Device.Show(context.Background(), Request.DeviceInterfaceName)
+	if err != nil {
+		return err
+	}
+	*Reply = model.EthernetInfo{
+		MacAddress:    show[0]["GENERAL"][0][9],
+		Ipv4Addresses: show[0]["IP4"][0][0],
+		Gateway:       show[0]["IP4"][0][1],
+		DNS:           strings.Split(show[0]["IP4"][0][3], "|"),
+	}
+	return nil
+}

+ 74 - 7
nmcli/WIFI.go

@@ -1,16 +1,83 @@
 package nmcli
 
-import "github.com/gin-gonic/gin"
+import (
+	"AudioPlayer/nmcli/model"
+	"context"
+	nmcli_go "github.com/KunMengcode/nmcli-go"
+	"github.com/KunMengcode/nmcli-go/connection"
+	"github.com/KunMengcode/nmcli-go/device"
+	"net/rpc"
+)
 
-func WifiList(c *gin.Context) {
+type WIFIInterface interface {
+	CreateHotspot(Request model.HotspotInfoRequest, Reply *model.EmptyReply) error
+	ChangeHotspot(Request model.HotspotInfoRequest, Reply *model.EmptyReply) error
+	OpenHotspot(Request model.HotspotInfoRequest, Reply *model.EmptyReply) error
+	HotspotInfo(Request model.EmptyRequest, Reply *WifiInfo) error
+	register() error
+}
+
+type WIFI struct {
+	nmcli *nmcli_go.NMCli
+}
+
+func NewWIFI(nmcli *nmcli_go.NMCli) WIFIInterface {
+	return &WIFI{nmcli: nmcli}
+}
+
+func (receiver *WIFI) register() error {
+	return rpc.RegisterName("NetworkManager.WIFI", receiver)
+}
+
+func (receiver *WIFI) CreateHotspot(Request model.HotspotInfoRequest, Reply *model.EmptyReply) error {
+	_, err := receiver.nmcli.Device.WiFiHotspotCreate(context.Background(), device.WiFiHotspotCreateOptions{
+		Ifname:   Request.IfName,
+		Con_name: "hotspot",
+		SSID:     Request.SSID,
+		Password: Request.Password,
+	})
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+func (receiver *WIFI) OpenHotspot(Request model.HotspotInfoRequest, Reply *model.EmptyReply) error {
+	_, err := receiver.nmcli.Connection.Up(context.Background(), "hotspot", connection.UpOptions{})
+	if err != nil {
+		return err
+	}
+	return nil
+}
 
+func (receiver *WIFI) ChangeHotspot(Request model.HotspotInfoRequest, Reply *model.EmptyReply) error {
+	_, err := receiver.nmcli.Connection.Modify(context.Background(), false, "hotspot", map[string]string{
+		"802-11-wireless.ssid":         Request.SSID,
+		"802-11-wireless-security.psk": Request.Password,
+	})
+	if err != nil {
+		return err
+	}
+	err = receiver.OpenHotspot(Request, Reply)
+	if err != nil {
+		return err
+	}
+	return nil
 }
 
-func WifiConnect(c *gin.Context) {
-	//SSID string, password string
+type WifiInfo struct {
+	SSID     string
+	Password string
 }
 
-func Routing(c *gin.RouterGroup) {
-	c.GET("/WifiList", WifiList)
-	c.PUT("/WifiConnect", WifiConnect)
+func (receiver *WIFI) HotspotInfo(Request model.EmptyRequest, Reply *WifiInfo) error {
+	show, err := receiver.nmcli.Connection.Show(context.Background(), "hotspot")
+	if err != nil {
+		return err
+	}
+	*Reply = WifiInfo{
+		SSID:     show["802-11-wireless"][0][0],
+		Password: show["802-11-wireless-security"][0][14],
+	}
+	return nil
 }

+ 5 - 0
nmcli/model/Device.go

@@ -0,0 +1,5 @@
+package model
+
+type DeviceInfoRequest struct {
+	DeviceInterfaceName string
+}

+ 16 - 0
nmcli/model/Ethernet.go

@@ -0,0 +1,16 @@
+package model
+
+type EthernetStaticIPRequest struct {
+	Id            string
+	Ipv4Addresses string
+	Ipv4Method    string
+	DNS           string
+	Gateway       string
+}
+
+type EthernetInfo struct {
+	MacAddress    string
+	Ipv4Addresses string
+	Gateway       string
+	DNS           []string
+}

+ 6 - 0
nmcli/model/General.go

@@ -0,0 +1,6 @@
+package model
+
+type EmptyReply struct {
+}
+type EmptyRequest struct {
+}

+ 7 - 0
nmcli/model/Wifi.go

@@ -0,0 +1,7 @@
+package model
+
+type HotspotInfoRequest struct {
+	IfName   string
+	SSID     string
+	Password string
+}

+ 36 - 0
nmcli/nmcli.go

@@ -0,0 +1,36 @@
+package nmcli
+
+import (
+	nmcli_go "github.com/KunMengcode/nmcli-go"
+)
+
+type NMClient struct {
+	wifi     WIFIInterface
+	device   DeviceInterface
+	ethernet EthernetInterface
+}
+
+func NewNMCli() NMClient {
+	cli := nmcli_go.NewNMCli()
+	return NMClient{
+		wifi:     NewWIFI(&cli),
+		device:   NewDevice(&cli),
+		ethernet: NewEthernet(&cli),
+	}
+}
+
+func (receiver *NMClient) Register() (err error) {
+	err = receiver.wifi.register()
+	if err != nil {
+		return
+	}
+	err = receiver.device.register()
+	if err != nil {
+		return
+	}
+	err = receiver.ethernet.register()
+	if err != nil {
+		return
+	}
+	return
+}