From 8d7b47a7de7e55576390ab137ac5d8072bb45f1e Mon Sep 17 00:00:00 2001 From: Akizon77 Date: Mon, 8 Sep 2025 13:38:47 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=85=BC=E5=AE=B9=E5=93=AA=E5=90=92Age?= =?UTF-8?q?nt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/ws.go | 4 +- cmd/nezha_compat.go | 336 ++++++++ cmd/server.go | 15 + compat/nezha/nezha.proto | 83 ++ compat/nezha/proto/nezha.pb.go | 1104 +++++++++++++++++++++++++++ compat/nezha/proto/nezha_grpc.pb.go | 374 +++++++++ database/config/config.go | 20 +- database/models/config.go | 3 + go.mod | 16 +- go.sum | 52 +- ws/existingConnection.go | 60 +- 11 files changed, 2034 insertions(+), 33 deletions(-) create mode 100644 cmd/nezha_compat.go create mode 100644 compat/nezha/nezha.proto create mode 100644 compat/nezha/proto/nezha.pb.go create mode 100644 compat/nezha/proto/nezha_grpc.pb.go diff --git a/api/ws.go b/api/ws.go index b791c9a..db6a88f 100644 --- a/api/ws.go +++ b/api/ws.go @@ -87,8 +87,8 @@ func GetClients(c *gin.Context) { } } - // 已建立连接的客户端uuid列表 - for key := range ws.GetConnectedClients() { + // 在线客户端uuid列表(WebSocket 与非 WebSocket) + for _, key := range ws.GetAllOnlineUUIDs() { if !isLogin && hiddenMap[key] { continue } diff --git a/cmd/nezha_compat.go b/cmd/nezha_compat.go new file mode 100644 index 0000000..244d148 --- /dev/null +++ b/cmd/nezha_compat.go @@ -0,0 +1,336 @@ +package cmd + +import ( + "context" + "errors" + "io" + "log" + "math" + "net" + "strings" + "time" + + apiClient "github.com/komari-monitor/komari/api/client" + "github.com/komari-monitor/komari/common" + "github.com/komari-monitor/komari/database/config" + "github.com/komari-monitor/komari/database/dbcore" + "github.com/komari-monitor/komari/database/models" + "github.com/komari-monitor/komari/utils/geoip" + "github.com/komari-monitor/komari/utils/notifier" + "github.com/komari-monitor/komari/ws" + + "github.com/komari-monitor/komari/compat/nezha/proto" + "google.golang.org/grpc" + "google.golang.org/grpc/keepalive" + "google.golang.org/grpc/metadata" + "gorm.io/gorm/clause" +) + +// StartNezhaCompatServer starts a gRPC server compatible with Nezha Agent. +func StartNezhaCompatServer(addr string) error { + boot := uint64(time.Now().Unix()) + lis, err := net.Listen("tcp", addr) + if err != nil { + return err + } + srv := &nezhaCompatServer{bootTime: boot} + + // Interceptors for metadata auth presence (lightweight; validation is inside handlers too) + unary := func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { + return handler(ctx, req) + } + stream := func(srvIface interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { + return handler(srvIface, ss) + } + // Enable gRPC keepalive to tolerate long-idle streams + gs := grpc.NewServer( + grpc.UnaryInterceptor(unary), + grpc.StreamInterceptor(stream), + // Keepalive: allow client pings and keep connections stable without app traffic + grpc.KeepaliveParams(keepalive.ServerParameters{ + Time: 2 * time.Minute, + Timeout: 20 * time.Second, + }), + grpc.KeepaliveEnforcementPolicy(keepalive.EnforcementPolicy{ + MinTime: 20 * time.Second, + PermitWithoutStream: true, + }), + ) + proto.RegisterNezhaServiceServer(gs, srv) + log.Printf("Nezha compat gRPC listening on %s", addr) + return gs.Serve(lis) +} + +type nezhaCompatServer struct { + proto.UnimplementedNezhaServiceServer + bootTime uint64 +} + +// authentication helpers +func getAuth(ctx context.Context) (uuid string, secret string, err error) { + md, ok := metadata.FromIncomingContext(ctx) + if !ok { + return "", "", errors.New("missing metadata") + } + getFirst := func(key string) string { + vals := md.Get(key) + if len(vals) > 0 { + return vals[0] + } + return "" + } + uuid = getFirst("client_uuid") + secret = getFirst("client_secret") + if uuid == "" || secret == "" { + return "", "", errors.New("unauthorized: missing client_uuid/client_secret") + } + return uuid, secret, nil +} + +// ReportSystemInfo: upsert static host info +func (s *nezhaCompatServer) ReportSystemInfo(ctx context.Context, host *proto.Host) (*proto.Receipt, error) { + uuid, secret, err := getAuth(ctx) + if err != nil { + return nil, err + } + if err := upsertClientFromHost(uuid, secret, host); err != nil { + return nil, err + } + return &proto.Receipt{Proced: true}, nil +} + +// ReportSystemInfo2: same as above but returns dashboard boot time +func (s *nezhaCompatServer) ReportSystemInfo2(ctx context.Context, host *proto.Host) (*proto.Uint64Receipt, error) { + uuid, secret, err := getAuth(ctx) + if err != nil { + return nil, err + } + if err := upsertClientFromHost(uuid, secret, host); err != nil { + return nil, err + } + return &proto.Uint64Receipt{Data: s.bootTime}, nil +} + +// ReportSystemState: ingest time-series records +func (s *nezhaCompatServer) ReportSystemState(stream proto.NezhaService_ReportSystemStateServer) error { + ctx := stream.Context() + uuid, _, err := getAuth(ctx) + if err != nil { + return err + } + // presence start + connID := time.Now().UnixNano() + ws.SetPresence(uuid, connID, true) + go notifier.OnlineNotification(uuid, connID) + defer func() { + ws.SetPresence(uuid, connID, false) + notifier.OfflineNotification(uuid, connID) + }() + for { + st, err := stream.Recv() + if err == io.EOF { + return nil + } + if err != nil { + return err + } + // refresh presence TTL on every frame + ws.KeepAlivePresence(uuid, connID, 30*time.Second) + if err := ingestState(uuid, st); err != nil { + // still ack to avoid client stuck; log error + log.Printf("Nezha ingest state error: %v", err) + } + if err := stream.Send(&proto.Receipt{Proced: true}); err != nil { + return err + } + } +} + +// RequestTask: do not dispatch tasks, just drain results to avoid Unimplemented +func (s *nezhaCompatServer) RequestTask(stream proto.NezhaService_RequestTaskServer) error { + ctx := stream.Context() + uuid, _, err := getAuth(ctx) + if err != nil { + return err + } + ticker := time.NewTicker(10 * time.Second) + defer ticker.Stop() + connID := time.Now().UnixNano() + ws.SetPresence(uuid, connID, true) + defer ws.SetPresence(uuid, connID, false) + // receive results in background + recvErr := make(chan error, 1) + go func() { + for { + _, rerr := stream.Recv() + if rerr == io.EOF { + recvErr <- nil + return + } + if rerr != nil { + recvErr <- rerr + return + } + // refresh presence TTL when result received + ws.KeepAlivePresence(uuid, connID, 30*time.Second) + } + }() + // send heartbeat tasks periodically + for { + select { + case <-ctx.Done(): + return ctx.Err() + case err := <-recvErr: + return err + case <-ticker.C: + if err := stream.Send(&proto.Task{}); err != nil { + return err + } + } + } +} + +// Unimplemented methods intentionally left as default (IOStream, ReportGeoIP) + +// upsertClientFromHost maps Host into models.Client and upserts by UUID +func upsertClientFromHost(uuid, secret string, h *proto.Host) error { + db := dbcore.GetDBInstance() + now := models.FromTime(time.Now()) + // token guard: if existing record has different token, reject + var exist models.Client + if err := db.Where("uuid = ?", uuid).First(&exist).Error; err == nil { + if exist.Token != "" && exist.Token != secret { + return errors.New("unauthorized: token mismatch") + } + } + cpuName := "" + if len(h.Cpu) > 0 { + cpuName = h.Cpu[0] + } + gpuName := strings.Join(h.Gpu, "; ") + osName := h.Platform + if h.PlatformVersion != "" { + osName = h.Platform + " " + h.PlatformVersion + } + // clamp uint64 to int64 safely + clamp := func(v uint64) int64 { + if v > uint64(math.MaxInt64) { + return math.MaxInt64 + } + return int64(v) + } + c := models.Client{ + UUID: uuid, + Token: secret, + Name: "nezha_" + uuid[0:8], + CpuName: cpuName, + Arch: h.Arch, + CpuCores: len(h.Cpu), + OS: osName, + KernelVersion: h.PlatformVersion, + Virtualization: h.Virtualization, + GpuName: gpuName, + MemTotal: clamp(h.MemTotal), + SwapTotal: clamp(h.SwapTotal), + DiskTotal: clamp(h.DiskTotal), + Version: h.Version, + UpdatedAt: now, + } + // Upsert by UUID; don't override existing Token if already set + updates := map[string]interface{}{ + "cpu_name": c.CpuName, + "arch": c.Arch, + "cpu_cores": c.CpuCores, + "os": c.OS, + "kernel_version": c.KernelVersion, + "virtualization": c.Virtualization, + "gpu_name": c.GpuName, + "mem_total": c.MemTotal, + "swap_total": c.SwapTotal, + "disk_total": c.DiskTotal, + "version": c.Version, + "updated_at": time.Now(), + } + return db.Clauses(clause.OnConflict{ + Columns: []clause.Column{{Name: "uuid"}}, + DoUpdates: clause.Assignments(updates), + }).Create(&c).Error +} + +// ingestState maps Nezha State into common.Report then saves a Record +func ingestState(uuid string, st *proto.State) error { + // we may need totals from client + db := dbcore.GetDBInstance() + var client models.Client + if err := db.Where("uuid = ?", uuid).First(&client).Error; err != nil { + // If missing, create with minimal defaults to avoid failing ingestion + client = models.Client{UUID: uuid, Token: "", Name: "nezha_" + uuid[0:8]} + _ = db.Create(&client).Error + } + rep := common.Report{ + CPU: common.CPUReport{Usage: st.Cpu}, + Ram: common.RamReport{Total: client.MemTotal, Used: int64(st.MemUsed)}, + Swap: common.RamReport{Total: client.SwapTotal, Used: int64(st.SwapUsed)}, + Load: common.LoadReport{Load1: st.Load1, Load5: st.Load5, Load15: st.Load15}, + Disk: common.DiskReport{Total: client.DiskTotal, Used: int64(st.DiskUsed)}, + Network: common.NetworkReport{ + Up: int64(st.NetOutSpeed), + Down: int64(st.NetInSpeed), + TotalUp: int64(st.NetOutTransfer), + TotalDown: int64(st.NetInTransfer), + }, + Uptime: int64(st.Uptime), + Process: int(st.ProcessCount), + UpdatedAt: time.Now(), + } + // 更新实时缓存供前端使用 + ws.SetLatestReport(uuid, &rep) + // 写入内存缓存,入库交由定时聚合任务处理 + return apiClient.SaveClientReport(uuid, rep) +} + +// ReportGeoIP: 保存 Agent 上报的 IP,并回填国家码/面板启动时间 +func (s *nezhaCompatServer) ReportGeoIP(ctx context.Context, in *proto.GeoIP) (*proto.GeoIP, error) { + uuid, _, err := getAuth(ctx) + if err != nil { + return nil, err + } + updates := map[string]interface{}{ + "updated_at": time.Now(), + } + var iso string + if in != nil && in.Ip != nil { + if v4 := strings.TrimSpace(in.Ip.Ipv4); v4 != "" { + updates["ipv4"] = v4 + if cfg, err := config.Get(); err == nil && cfg.GeoIpEnabled { + if ip := net.ParseIP(v4); ip != nil { + if gi, _ := geoip.GetGeoInfo(ip); gi != nil { + iso = gi.ISOCode + } + } + } + } + if v6 := strings.TrimSpace(in.Ip.Ipv6); v6 != "" { + updates["ipv6"] = v6 + if iso == "" { // 优先使用 v4 的国家码 + if cfg, err := config.Get(); err == nil && cfg.GeoIpEnabled { + if ip := net.ParseIP(v6); ip != nil { + if gi, _ := geoip.GetGeoInfo(ip); gi != nil { + iso = gi.ISOCode + } + } + } + } + } + } + if iso != "" { + // UI 使用旗帜 emoji + updates["region"] = geoip.GetRegionUnicodeEmoji(iso) + } + if len(updates) > 0 { + _ = dbcore.GetDBInstance().Model(&models.Client{}).Where("uuid = ?", uuid).Updates(updates).Error + } + // 回写 GeoIP(包含国家码与面板启动时间) + resp := &proto.GeoIP{Use6: in.GetUse6(), Ip: in.GetIp(), CountryCode: iso, DashboardBootTime: s.bootTime} + return resp, nil +} diff --git a/cmd/server.go b/cmd/server.go index 251d20f..1ec2c68 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -328,6 +328,21 @@ func RunServer() { log.Fatalf("listen: %s\n", err) } }() + // Optionally start Nezha gRPC compatibility server on separate port + if nzAddr := GetEnv("KOMARI_NEZHA_LISTEN", ""); nzAddr != "" { + go func() { + if err := StartNezhaCompatServer(nzAddr); err != nil { + log.Printf("Nezha compat server error: %v", err) + auditlog.EventLog("error", fmt.Sprintf("Nezha compat server error: %v", err)) + } + }() + } else if conf.NezhaCompatEnabled && conf.NezhaCompatListen != "" { + go func() { + if err := StartNezhaCompatServer(conf.NezhaCompatListen); err != nil { + auditlog.EventLog("error", fmt.Sprintf("Nezha compat server error: %v", err)) + } + }() + } quit := make(chan os.Signal, 1) signal.Notify(quit, os.Interrupt, syscall.SIGTERM) <-quit diff --git a/compat/nezha/nezha.proto b/compat/nezha/nezha.proto new file mode 100644 index 0000000..a8ed258 --- /dev/null +++ b/compat/nezha/nezha.proto @@ -0,0 +1,83 @@ +syntax = "proto3"; +package proto; +option go_package = "github.com/komari-monitor/komari/compat/nezha/proto"; + +service NezhaService { + rpc ReportSystemState(stream State) returns (stream Receipt) {} + rpc ReportSystemInfo(Host) returns (Receipt) {} + rpc RequestTask(stream TaskResult) returns (stream Task) {} + rpc IOStream(stream IOStreamData) returns (stream IOStreamData) {} + rpc ReportGeoIP(GeoIP) returns (GeoIP) {} + rpc ReportSystemInfo2(Host) returns (Uint64Receipt) {} +} + +message Host { + string platform = 1; + string platform_version = 2; + repeated string cpu = 3; + uint64 mem_total = 4; + uint64 disk_total = 5; + uint64 swap_total = 6; + string arch = 7; + string virtualization = 8; + uint64 boot_time = 9; + string version = 10; + repeated string gpu = 11; +} + +message State { + double cpu = 1; + uint64 mem_used = 2; + uint64 swap_used = 3; + uint64 disk_used = 4; + uint64 net_in_transfer = 5; + uint64 net_out_transfer = 6; + uint64 net_in_speed = 7; + uint64 net_out_speed = 8; + uint64 uptime = 9; + double load1 = 10; + double load5 = 11; + double load15 = 12; + uint64 tcp_conn_count = 13; + uint64 udp_conn_count = 14; + uint64 process_count = 15; + repeated State_SensorTemperature temperatures = 16; + repeated double gpu = 17; +} + +message State_SensorTemperature { + string name = 1; + double temperature = 2; +} + +message Task { + uint64 id = 1; + uint64 type = 2; + string data = 3; +} + +message TaskResult { + uint64 id = 1; + uint64 type = 2; + float delay = 3; + string data = 4; + bool successful = 5; +} + +message Receipt { bool proced = 1; } + +message Uint64Receipt { uint64 data = 1; } + +message IOStreamData { bytes data = 1; } + +message GeoIP { + bool use6 = 1; + IP ip = 2; + string country_code = 3; + uint64 dashboard_boot_time = 4; +} + +message IP { + string ipv4 = 1; + string ipv6 = 2; +} diff --git a/compat/nezha/proto/nezha.pb.go b/compat/nezha/proto/nezha.pb.go new file mode 100644 index 0000000..d1bc56d --- /dev/null +++ b/compat/nezha/proto/nezha.pb.go @@ -0,0 +1,1104 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.28.1 +// protoc v3.21.12 +// source: compat/nezha/nezha.proto + +package proto + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Host struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Platform string `protobuf:"bytes,1,opt,name=platform,proto3" json:"platform,omitempty"` + PlatformVersion string `protobuf:"bytes,2,opt,name=platform_version,json=platformVersion,proto3" json:"platform_version,omitempty"` + Cpu []string `protobuf:"bytes,3,rep,name=cpu,proto3" json:"cpu,omitempty"` + MemTotal uint64 `protobuf:"varint,4,opt,name=mem_total,json=memTotal,proto3" json:"mem_total,omitempty"` + DiskTotal uint64 `protobuf:"varint,5,opt,name=disk_total,json=diskTotal,proto3" json:"disk_total,omitempty"` + SwapTotal uint64 `protobuf:"varint,6,opt,name=swap_total,json=swapTotal,proto3" json:"swap_total,omitempty"` + Arch string `protobuf:"bytes,7,opt,name=arch,proto3" json:"arch,omitempty"` + Virtualization string `protobuf:"bytes,8,opt,name=virtualization,proto3" json:"virtualization,omitempty"` + BootTime uint64 `protobuf:"varint,9,opt,name=boot_time,json=bootTime,proto3" json:"boot_time,omitempty"` + Version string `protobuf:"bytes,10,opt,name=version,proto3" json:"version,omitempty"` + Gpu []string `protobuf:"bytes,11,rep,name=gpu,proto3" json:"gpu,omitempty"` +} + +func (x *Host) Reset() { + *x = Host{} + if protoimpl.UnsafeEnabled { + mi := &file_compat_nezha_nezha_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Host) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Host) ProtoMessage() {} + +func (x *Host) ProtoReflect() protoreflect.Message { + mi := &file_compat_nezha_nezha_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Host.ProtoReflect.Descriptor instead. +func (*Host) Descriptor() ([]byte, []int) { + return file_compat_nezha_nezha_proto_rawDescGZIP(), []int{0} +} + +func (x *Host) GetPlatform() string { + if x != nil { + return x.Platform + } + return "" +} + +func (x *Host) GetPlatformVersion() string { + if x != nil { + return x.PlatformVersion + } + return "" +} + +func (x *Host) GetCpu() []string { + if x != nil { + return x.Cpu + } + return nil +} + +func (x *Host) GetMemTotal() uint64 { + if x != nil { + return x.MemTotal + } + return 0 +} + +func (x *Host) GetDiskTotal() uint64 { + if x != nil { + return x.DiskTotal + } + return 0 +} + +func (x *Host) GetSwapTotal() uint64 { + if x != nil { + return x.SwapTotal + } + return 0 +} + +func (x *Host) GetArch() string { + if x != nil { + return x.Arch + } + return "" +} + +func (x *Host) GetVirtualization() string { + if x != nil { + return x.Virtualization + } + return "" +} + +func (x *Host) GetBootTime() uint64 { + if x != nil { + return x.BootTime + } + return 0 +} + +func (x *Host) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *Host) GetGpu() []string { + if x != nil { + return x.Gpu + } + return nil +} + +type State struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Cpu float64 `protobuf:"fixed64,1,opt,name=cpu,proto3" json:"cpu,omitempty"` + MemUsed uint64 `protobuf:"varint,2,opt,name=mem_used,json=memUsed,proto3" json:"mem_used,omitempty"` + SwapUsed uint64 `protobuf:"varint,3,opt,name=swap_used,json=swapUsed,proto3" json:"swap_used,omitempty"` + DiskUsed uint64 `protobuf:"varint,4,opt,name=disk_used,json=diskUsed,proto3" json:"disk_used,omitempty"` + NetInTransfer uint64 `protobuf:"varint,5,opt,name=net_in_transfer,json=netInTransfer,proto3" json:"net_in_transfer,omitempty"` + NetOutTransfer uint64 `protobuf:"varint,6,opt,name=net_out_transfer,json=netOutTransfer,proto3" json:"net_out_transfer,omitempty"` + NetInSpeed uint64 `protobuf:"varint,7,opt,name=net_in_speed,json=netInSpeed,proto3" json:"net_in_speed,omitempty"` + NetOutSpeed uint64 `protobuf:"varint,8,opt,name=net_out_speed,json=netOutSpeed,proto3" json:"net_out_speed,omitempty"` + Uptime uint64 `protobuf:"varint,9,opt,name=uptime,proto3" json:"uptime,omitempty"` + Load1 float64 `protobuf:"fixed64,10,opt,name=load1,proto3" json:"load1,omitempty"` + Load5 float64 `protobuf:"fixed64,11,opt,name=load5,proto3" json:"load5,omitempty"` + Load15 float64 `protobuf:"fixed64,12,opt,name=load15,proto3" json:"load15,omitempty"` + TcpConnCount uint64 `protobuf:"varint,13,opt,name=tcp_conn_count,json=tcpConnCount,proto3" json:"tcp_conn_count,omitempty"` + UdpConnCount uint64 `protobuf:"varint,14,opt,name=udp_conn_count,json=udpConnCount,proto3" json:"udp_conn_count,omitempty"` + ProcessCount uint64 `protobuf:"varint,15,opt,name=process_count,json=processCount,proto3" json:"process_count,omitempty"` + Temperatures []*State_SensorTemperature `protobuf:"bytes,16,rep,name=temperatures,proto3" json:"temperatures,omitempty"` + Gpu []float64 `protobuf:"fixed64,17,rep,packed,name=gpu,proto3" json:"gpu,omitempty"` +} + +func (x *State) Reset() { + *x = State{} + if protoimpl.UnsafeEnabled { + mi := &file_compat_nezha_nezha_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *State) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*State) ProtoMessage() {} + +func (x *State) ProtoReflect() protoreflect.Message { + mi := &file_compat_nezha_nezha_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use State.ProtoReflect.Descriptor instead. +func (*State) Descriptor() ([]byte, []int) { + return file_compat_nezha_nezha_proto_rawDescGZIP(), []int{1} +} + +func (x *State) GetCpu() float64 { + if x != nil { + return x.Cpu + } + return 0 +} + +func (x *State) GetMemUsed() uint64 { + if x != nil { + return x.MemUsed + } + return 0 +} + +func (x *State) GetSwapUsed() uint64 { + if x != nil { + return x.SwapUsed + } + return 0 +} + +func (x *State) GetDiskUsed() uint64 { + if x != nil { + return x.DiskUsed + } + return 0 +} + +func (x *State) GetNetInTransfer() uint64 { + if x != nil { + return x.NetInTransfer + } + return 0 +} + +func (x *State) GetNetOutTransfer() uint64 { + if x != nil { + return x.NetOutTransfer + } + return 0 +} + +func (x *State) GetNetInSpeed() uint64 { + if x != nil { + return x.NetInSpeed + } + return 0 +} + +func (x *State) GetNetOutSpeed() uint64 { + if x != nil { + return x.NetOutSpeed + } + return 0 +} + +func (x *State) GetUptime() uint64 { + if x != nil { + return x.Uptime + } + return 0 +} + +func (x *State) GetLoad1() float64 { + if x != nil { + return x.Load1 + } + return 0 +} + +func (x *State) GetLoad5() float64 { + if x != nil { + return x.Load5 + } + return 0 +} + +func (x *State) GetLoad15() float64 { + if x != nil { + return x.Load15 + } + return 0 +} + +func (x *State) GetTcpConnCount() uint64 { + if x != nil { + return x.TcpConnCount + } + return 0 +} + +func (x *State) GetUdpConnCount() uint64 { + if x != nil { + return x.UdpConnCount + } + return 0 +} + +func (x *State) GetProcessCount() uint64 { + if x != nil { + return x.ProcessCount + } + return 0 +} + +func (x *State) GetTemperatures() []*State_SensorTemperature { + if x != nil { + return x.Temperatures + } + return nil +} + +func (x *State) GetGpu() []float64 { + if x != nil { + return x.Gpu + } + return nil +} + +type State_SensorTemperature struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Temperature float64 `protobuf:"fixed64,2,opt,name=temperature,proto3" json:"temperature,omitempty"` +} + +func (x *State_SensorTemperature) Reset() { + *x = State_SensorTemperature{} + if protoimpl.UnsafeEnabled { + mi := &file_compat_nezha_nezha_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *State_SensorTemperature) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*State_SensorTemperature) ProtoMessage() {} + +func (x *State_SensorTemperature) ProtoReflect() protoreflect.Message { + mi := &file_compat_nezha_nezha_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use State_SensorTemperature.ProtoReflect.Descriptor instead. +func (*State_SensorTemperature) Descriptor() ([]byte, []int) { + return file_compat_nezha_nezha_proto_rawDescGZIP(), []int{2} +} + +func (x *State_SensorTemperature) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *State_SensorTemperature) GetTemperature() float64 { + if x != nil { + return x.Temperature + } + return 0 +} + +type Task struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + Type uint64 `protobuf:"varint,2,opt,name=type,proto3" json:"type,omitempty"` + Data string `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` +} + +func (x *Task) Reset() { + *x = Task{} + if protoimpl.UnsafeEnabled { + mi := &file_compat_nezha_nezha_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Task) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Task) ProtoMessage() {} + +func (x *Task) ProtoReflect() protoreflect.Message { + mi := &file_compat_nezha_nezha_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Task.ProtoReflect.Descriptor instead. +func (*Task) Descriptor() ([]byte, []int) { + return file_compat_nezha_nezha_proto_rawDescGZIP(), []int{3} +} + +func (x *Task) GetId() uint64 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *Task) GetType() uint64 { + if x != nil { + return x.Type + } + return 0 +} + +func (x *Task) GetData() string { + if x != nil { + return x.Data + } + return "" +} + +type TaskResult struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + Type uint64 `protobuf:"varint,2,opt,name=type,proto3" json:"type,omitempty"` + Delay float32 `protobuf:"fixed32,3,opt,name=delay,proto3" json:"delay,omitempty"` + Data string `protobuf:"bytes,4,opt,name=data,proto3" json:"data,omitempty"` + Successful bool `protobuf:"varint,5,opt,name=successful,proto3" json:"successful,omitempty"` +} + +func (x *TaskResult) Reset() { + *x = TaskResult{} + if protoimpl.UnsafeEnabled { + mi := &file_compat_nezha_nezha_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TaskResult) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TaskResult) ProtoMessage() {} + +func (x *TaskResult) ProtoReflect() protoreflect.Message { + mi := &file_compat_nezha_nezha_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TaskResult.ProtoReflect.Descriptor instead. +func (*TaskResult) Descriptor() ([]byte, []int) { + return file_compat_nezha_nezha_proto_rawDescGZIP(), []int{4} +} + +func (x *TaskResult) GetId() uint64 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *TaskResult) GetType() uint64 { + if x != nil { + return x.Type + } + return 0 +} + +func (x *TaskResult) GetDelay() float32 { + if x != nil { + return x.Delay + } + return 0 +} + +func (x *TaskResult) GetData() string { + if x != nil { + return x.Data + } + return "" +} + +func (x *TaskResult) GetSuccessful() bool { + if x != nil { + return x.Successful + } + return false +} + +type Receipt struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Proced bool `protobuf:"varint,1,opt,name=proced,proto3" json:"proced,omitempty"` +} + +func (x *Receipt) Reset() { + *x = Receipt{} + if protoimpl.UnsafeEnabled { + mi := &file_compat_nezha_nezha_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Receipt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Receipt) ProtoMessage() {} + +func (x *Receipt) ProtoReflect() protoreflect.Message { + mi := &file_compat_nezha_nezha_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Receipt.ProtoReflect.Descriptor instead. +func (*Receipt) Descriptor() ([]byte, []int) { + return file_compat_nezha_nezha_proto_rawDescGZIP(), []int{5} +} + +func (x *Receipt) GetProced() bool { + if x != nil { + return x.Proced + } + return false +} + +type Uint64Receipt struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Data uint64 `protobuf:"varint,1,opt,name=data,proto3" json:"data,omitempty"` +} + +func (x *Uint64Receipt) Reset() { + *x = Uint64Receipt{} + if protoimpl.UnsafeEnabled { + mi := &file_compat_nezha_nezha_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Uint64Receipt) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Uint64Receipt) ProtoMessage() {} + +func (x *Uint64Receipt) ProtoReflect() protoreflect.Message { + mi := &file_compat_nezha_nezha_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Uint64Receipt.ProtoReflect.Descriptor instead. +func (*Uint64Receipt) Descriptor() ([]byte, []int) { + return file_compat_nezha_nezha_proto_rawDescGZIP(), []int{6} +} + +func (x *Uint64Receipt) GetData() uint64 { + if x != nil { + return x.Data + } + return 0 +} + +type IOStreamData struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` +} + +func (x *IOStreamData) Reset() { + *x = IOStreamData{} + if protoimpl.UnsafeEnabled { + mi := &file_compat_nezha_nezha_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *IOStreamData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IOStreamData) ProtoMessage() {} + +func (x *IOStreamData) ProtoReflect() protoreflect.Message { + mi := &file_compat_nezha_nezha_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use IOStreamData.ProtoReflect.Descriptor instead. +func (*IOStreamData) Descriptor() ([]byte, []int) { + return file_compat_nezha_nezha_proto_rawDescGZIP(), []int{7} +} + +func (x *IOStreamData) GetData() []byte { + if x != nil { + return x.Data + } + return nil +} + +type GeoIP struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Use6 bool `protobuf:"varint,1,opt,name=use6,proto3" json:"use6,omitempty"` + Ip *IP `protobuf:"bytes,2,opt,name=ip,proto3" json:"ip,omitempty"` + CountryCode string `protobuf:"bytes,3,opt,name=country_code,json=countryCode,proto3" json:"country_code,omitempty"` + DashboardBootTime uint64 `protobuf:"varint,4,opt,name=dashboard_boot_time,json=dashboardBootTime,proto3" json:"dashboard_boot_time,omitempty"` +} + +func (x *GeoIP) Reset() { + *x = GeoIP{} + if protoimpl.UnsafeEnabled { + mi := &file_compat_nezha_nezha_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GeoIP) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GeoIP) ProtoMessage() {} + +func (x *GeoIP) ProtoReflect() protoreflect.Message { + mi := &file_compat_nezha_nezha_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GeoIP.ProtoReflect.Descriptor instead. +func (*GeoIP) Descriptor() ([]byte, []int) { + return file_compat_nezha_nezha_proto_rawDescGZIP(), []int{8} +} + +func (x *GeoIP) GetUse6() bool { + if x != nil { + return x.Use6 + } + return false +} + +func (x *GeoIP) GetIp() *IP { + if x != nil { + return x.Ip + } + return nil +} + +func (x *GeoIP) GetCountryCode() string { + if x != nil { + return x.CountryCode + } + return "" +} + +func (x *GeoIP) GetDashboardBootTime() uint64 { + if x != nil { + return x.DashboardBootTime + } + return 0 +} + +type IP struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Ipv4 string `protobuf:"bytes,1,opt,name=ipv4,proto3" json:"ipv4,omitempty"` + Ipv6 string `protobuf:"bytes,2,opt,name=ipv6,proto3" json:"ipv6,omitempty"` +} + +func (x *IP) Reset() { + *x = IP{} + if protoimpl.UnsafeEnabled { + mi := &file_compat_nezha_nezha_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *IP) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*IP) ProtoMessage() {} + +func (x *IP) ProtoReflect() protoreflect.Message { + mi := &file_compat_nezha_nezha_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use IP.ProtoReflect.Descriptor instead. +func (*IP) Descriptor() ([]byte, []int) { + return file_compat_nezha_nezha_proto_rawDescGZIP(), []int{9} +} + +func (x *IP) GetIpv4() string { + if x != nil { + return x.Ipv4 + } + return "" +} + +func (x *IP) GetIpv6() string { + if x != nil { + return x.Ipv6 + } + return "" +} + +var File_compat_nezha_nezha_proto protoreflect.FileDescriptor + +var file_compat_nezha_nezha_proto_rawDesc = []byte{ + 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x2f, 0x6e, 0x65, 0x7a, 0x68, 0x61, 0x2f, 0x6e, + 0x65, 0x7a, 0x68, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x05, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x22, 0xbf, 0x02, 0x0a, 0x04, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x29, 0x0a, 0x10, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, + 0x72, 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0f, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x63, 0x70, 0x75, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, + 0x63, 0x70, 0x75, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x65, 0x6d, 0x5f, 0x74, 0x6f, 0x74, 0x61, 0x6c, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x65, 0x6d, 0x54, 0x6f, 0x74, 0x61, 0x6c, + 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x69, 0x73, 0x6b, 0x5f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x64, 0x69, 0x73, 0x6b, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x12, + 0x1d, 0x0a, 0x0a, 0x73, 0x77, 0x61, 0x70, 0x5f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x09, 0x73, 0x77, 0x61, 0x70, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x12, + 0x0a, 0x04, 0x61, 0x72, 0x63, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x72, + 0x63, 0x68, 0x12, 0x26, 0x0a, 0x0e, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x69, 0x7a, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x76, 0x69, 0x72, 0x74, + 0x75, 0x61, 0x6c, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x62, 0x6f, + 0x6f, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x62, + 0x6f, 0x6f, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x67, 0x70, 0x75, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x09, 0x52, 0x03, + 0x67, 0x70, 0x75, 0x22, 0xa9, 0x04, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x10, 0x0a, + 0x03, 0x63, 0x70, 0x75, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x03, 0x63, 0x70, 0x75, 0x12, + 0x19, 0x0a, 0x08, 0x6d, 0x65, 0x6d, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x55, 0x73, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x77, + 0x61, 0x70, 0x5f, 0x75, 0x73, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, + 0x77, 0x61, 0x70, 0x55, 0x73, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x69, 0x73, 0x6b, 0x5f, + 0x75, 0x73, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x64, 0x69, 0x73, 0x6b, + 0x55, 0x73, 0x65, 0x64, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x74, 0x5f, 0x69, 0x6e, 0x5f, 0x74, + 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x6e, + 0x65, 0x74, 0x49, 0x6e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x10, + 0x6e, 0x65, 0x74, 0x5f, 0x6f, 0x75, 0x74, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x6e, 0x65, 0x74, 0x4f, 0x75, 0x74, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x12, 0x20, 0x0a, 0x0c, 0x6e, 0x65, 0x74, 0x5f, 0x69, 0x6e, + 0x5f, 0x73, 0x70, 0x65, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x6e, 0x65, + 0x74, 0x49, 0x6e, 0x53, 0x70, 0x65, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x6e, 0x65, 0x74, 0x5f, + 0x6f, 0x75, 0x74, 0x5f, 0x73, 0x70, 0x65, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x0b, 0x6e, 0x65, 0x74, 0x4f, 0x75, 0x74, 0x53, 0x70, 0x65, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, + 0x75, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x75, 0x70, + 0x74, 0x69, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x6f, 0x61, 0x64, 0x31, 0x18, 0x0a, 0x20, + 0x01, 0x28, 0x01, 0x52, 0x05, 0x6c, 0x6f, 0x61, 0x64, 0x31, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x6f, + 0x61, 0x64, 0x35, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x01, 0x52, 0x05, 0x6c, 0x6f, 0x61, 0x64, 0x35, + 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x6f, 0x61, 0x64, 0x31, 0x35, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x01, + 0x52, 0x06, 0x6c, 0x6f, 0x61, 0x64, 0x31, 0x35, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x63, 0x70, 0x5f, + 0x63, 0x6f, 0x6e, 0x6e, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x0c, 0x74, 0x63, 0x70, 0x43, 0x6f, 0x6e, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x24, + 0x0a, 0x0e, 0x75, 0x64, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x18, 0x0e, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x75, 0x64, 0x70, 0x43, 0x6f, 0x6e, 0x6e, 0x43, + 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x5f, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x70, 0x72, 0x6f, + 0x63, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x42, 0x0a, 0x0c, 0x74, 0x65, 0x6d, + 0x70, 0x65, 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x10, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x53, 0x65, + 0x6e, 0x73, 0x6f, 0x72, 0x54, 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x52, + 0x0c, 0x74, 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x10, 0x0a, + 0x03, 0x67, 0x70, 0x75, 0x18, 0x11, 0x20, 0x03, 0x28, 0x01, 0x52, 0x03, 0x67, 0x70, 0x75, 0x22, + 0x4f, 0x0a, 0x17, 0x53, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x53, 0x65, 0x6e, 0x73, 0x6f, 0x72, 0x54, + 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, + 0x0a, 0x0b, 0x74, 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x01, 0x52, 0x0b, 0x74, 0x65, 0x6d, 0x70, 0x65, 0x72, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x22, 0x3e, 0x0a, 0x04, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, + 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, + 0x22, 0x7a, 0x0a, 0x0a, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x0e, + 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, + 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x02, 0x52, 0x05, 0x64, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1e, 0x0a, 0x0a, + 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0a, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x22, 0x21, 0x0a, 0x07, + 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x6f, 0x63, 0x65, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x64, 0x22, + 0x23, 0x0a, 0x0d, 0x55, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, + 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, + 0x64, 0x61, 0x74, 0x61, 0x22, 0x22, 0x0a, 0x0c, 0x49, 0x4f, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x44, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x89, 0x01, 0x0a, 0x05, 0x47, 0x65, 0x6f, + 0x49, 0x50, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x36, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x04, 0x75, 0x73, 0x65, 0x36, 0x12, 0x19, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x49, 0x50, 0x52, 0x02, 0x69, + 0x70, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x64, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, + 0x43, 0x6f, 0x64, 0x65, 0x12, 0x2e, 0x0a, 0x13, 0x64, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, + 0x64, 0x5f, 0x62, 0x6f, 0x6f, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x11, 0x64, 0x61, 0x73, 0x68, 0x62, 0x6f, 0x61, 0x72, 0x64, 0x42, 0x6f, 0x6f, 0x74, + 0x54, 0x69, 0x6d, 0x65, 0x22, 0x2c, 0x0a, 0x02, 0x49, 0x50, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x70, + 0x76, 0x34, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x70, 0x76, 0x34, 0x12, 0x12, + 0x0a, 0x04, 0x69, 0x70, 0x76, 0x36, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x70, + 0x76, 0x36, 0x32, 0xd2, 0x02, 0x0a, 0x0c, 0x4e, 0x65, 0x7a, 0x68, 0x61, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x12, 0x37, 0x0a, 0x11, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x79, 0x73, + 0x74, 0x65, 0x6d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x1a, 0x0e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, + 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x12, 0x31, 0x0a, 0x10, + 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x49, 0x6e, 0x66, 0x6f, + 0x12, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x1a, 0x0e, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x22, 0x00, 0x12, + 0x33, 0x0a, 0x0b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x11, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x1a, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x61, 0x73, 0x6b, 0x22, 0x00, + 0x28, 0x01, 0x30, 0x01, 0x12, 0x3a, 0x0a, 0x08, 0x49, 0x4f, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x12, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x49, 0x4f, 0x53, 0x74, 0x72, 0x65, 0x61, + 0x6d, 0x44, 0x61, 0x74, 0x61, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x49, 0x4f, + 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x44, 0x61, 0x74, 0x61, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, + 0x12, 0x2b, 0x0a, 0x0b, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x12, + 0x0c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x1a, 0x0c, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x6f, 0x49, 0x50, 0x22, 0x00, 0x12, 0x38, 0x0a, + 0x11, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x49, 0x6e, 0x66, + 0x6f, 0x32, 0x12, 0x0b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x1a, + 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x55, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x52, 0x65, + 0x63, 0x65, 0x69, 0x70, 0x74, 0x22, 0x00, 0x42, 0x35, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x6f, 0x6d, 0x61, 0x72, 0x69, 0x2d, 0x6d, 0x6f, 0x6e, + 0x69, 0x74, 0x6f, 0x72, 0x2f, 0x6b, 0x6f, 0x6d, 0x61, 0x72, 0x69, 0x2f, 0x63, 0x6f, 0x6d, 0x70, + 0x61, 0x74, 0x2f, 0x6e, 0x65, 0x7a, 0x68, 0x61, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_compat_nezha_nezha_proto_rawDescOnce sync.Once + file_compat_nezha_nezha_proto_rawDescData = file_compat_nezha_nezha_proto_rawDesc +) + +func file_compat_nezha_nezha_proto_rawDescGZIP() []byte { + file_compat_nezha_nezha_proto_rawDescOnce.Do(func() { + file_compat_nezha_nezha_proto_rawDescData = protoimpl.X.CompressGZIP(file_compat_nezha_nezha_proto_rawDescData) + }) + return file_compat_nezha_nezha_proto_rawDescData +} + +var file_compat_nezha_nezha_proto_msgTypes = make([]protoimpl.MessageInfo, 10) +var file_compat_nezha_nezha_proto_goTypes = []interface{}{ + (*Host)(nil), // 0: proto.Host + (*State)(nil), // 1: proto.State + (*State_SensorTemperature)(nil), // 2: proto.State_SensorTemperature + (*Task)(nil), // 3: proto.Task + (*TaskResult)(nil), // 4: proto.TaskResult + (*Receipt)(nil), // 5: proto.Receipt + (*Uint64Receipt)(nil), // 6: proto.Uint64Receipt + (*IOStreamData)(nil), // 7: proto.IOStreamData + (*GeoIP)(nil), // 8: proto.GeoIP + (*IP)(nil), // 9: proto.IP +} +var file_compat_nezha_nezha_proto_depIdxs = []int32{ + 2, // 0: proto.State.temperatures:type_name -> proto.State_SensorTemperature + 9, // 1: proto.GeoIP.ip:type_name -> proto.IP + 1, // 2: proto.NezhaService.ReportSystemState:input_type -> proto.State + 0, // 3: proto.NezhaService.ReportSystemInfo:input_type -> proto.Host + 4, // 4: proto.NezhaService.RequestTask:input_type -> proto.TaskResult + 7, // 5: proto.NezhaService.IOStream:input_type -> proto.IOStreamData + 8, // 6: proto.NezhaService.ReportGeoIP:input_type -> proto.GeoIP + 0, // 7: proto.NezhaService.ReportSystemInfo2:input_type -> proto.Host + 5, // 8: proto.NezhaService.ReportSystemState:output_type -> proto.Receipt + 5, // 9: proto.NezhaService.ReportSystemInfo:output_type -> proto.Receipt + 3, // 10: proto.NezhaService.RequestTask:output_type -> proto.Task + 7, // 11: proto.NezhaService.IOStream:output_type -> proto.IOStreamData + 8, // 12: proto.NezhaService.ReportGeoIP:output_type -> proto.GeoIP + 6, // 13: proto.NezhaService.ReportSystemInfo2:output_type -> proto.Uint64Receipt + 8, // [8:14] is the sub-list for method output_type + 2, // [2:8] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_compat_nezha_nezha_proto_init() } +func file_compat_nezha_nezha_proto_init() { + if File_compat_nezha_nezha_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_compat_nezha_nezha_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Host); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_compat_nezha_nezha_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*State); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_compat_nezha_nezha_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*State_SensorTemperature); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_compat_nezha_nezha_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Task); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_compat_nezha_nezha_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TaskResult); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_compat_nezha_nezha_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Receipt); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_compat_nezha_nezha_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Uint64Receipt); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_compat_nezha_nezha_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*IOStreamData); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_compat_nezha_nezha_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GeoIP); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_compat_nezha_nezha_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*IP); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_compat_nezha_nezha_proto_rawDesc, + NumEnums: 0, + NumMessages: 10, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_compat_nezha_nezha_proto_goTypes, + DependencyIndexes: file_compat_nezha_nezha_proto_depIdxs, + MessageInfos: file_compat_nezha_nezha_proto_msgTypes, + }.Build() + File_compat_nezha_nezha_proto = out.File + file_compat_nezha_nezha_proto_rawDesc = nil + file_compat_nezha_nezha_proto_goTypes = nil + file_compat_nezha_nezha_proto_depIdxs = nil +} diff --git a/compat/nezha/proto/nezha_grpc.pb.go b/compat/nezha/proto/nezha_grpc.pb.go new file mode 100644 index 0000000..348ab6f --- /dev/null +++ b/compat/nezha/proto/nezha_grpc.pb.go @@ -0,0 +1,374 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. + +package proto + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion7 + +// NezhaServiceClient is the client API for NezhaService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type NezhaServiceClient interface { + ReportSystemState(ctx context.Context, opts ...grpc.CallOption) (NezhaService_ReportSystemStateClient, error) + ReportSystemInfo(ctx context.Context, in *Host, opts ...grpc.CallOption) (*Receipt, error) + RequestTask(ctx context.Context, opts ...grpc.CallOption) (NezhaService_RequestTaskClient, error) + IOStream(ctx context.Context, opts ...grpc.CallOption) (NezhaService_IOStreamClient, error) + ReportGeoIP(ctx context.Context, in *GeoIP, opts ...grpc.CallOption) (*GeoIP, error) + ReportSystemInfo2(ctx context.Context, in *Host, opts ...grpc.CallOption) (*Uint64Receipt, error) +} + +type nezhaServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewNezhaServiceClient(cc grpc.ClientConnInterface) NezhaServiceClient { + return &nezhaServiceClient{cc} +} + +func (c *nezhaServiceClient) ReportSystemState(ctx context.Context, opts ...grpc.CallOption) (NezhaService_ReportSystemStateClient, error) { + stream, err := c.cc.NewStream(ctx, &_NezhaService_serviceDesc.Streams[0], "/proto.NezhaService/ReportSystemState", opts...) + if err != nil { + return nil, err + } + x := &nezhaServiceReportSystemStateClient{stream} + return x, nil +} + +type NezhaService_ReportSystemStateClient interface { + Send(*State) error + Recv() (*Receipt, error) + grpc.ClientStream +} + +type nezhaServiceReportSystemStateClient struct { + grpc.ClientStream +} + +func (x *nezhaServiceReportSystemStateClient) Send(m *State) error { + return x.ClientStream.SendMsg(m) +} + +func (x *nezhaServiceReportSystemStateClient) Recv() (*Receipt, error) { + m := new(Receipt) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *nezhaServiceClient) ReportSystemInfo(ctx context.Context, in *Host, opts ...grpc.CallOption) (*Receipt, error) { + out := new(Receipt) + err := c.cc.Invoke(ctx, "/proto.NezhaService/ReportSystemInfo", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *nezhaServiceClient) RequestTask(ctx context.Context, opts ...grpc.CallOption) (NezhaService_RequestTaskClient, error) { + stream, err := c.cc.NewStream(ctx, &_NezhaService_serviceDesc.Streams[1], "/proto.NezhaService/RequestTask", opts...) + if err != nil { + return nil, err + } + x := &nezhaServiceRequestTaskClient{stream} + return x, nil +} + +type NezhaService_RequestTaskClient interface { + Send(*TaskResult) error + Recv() (*Task, error) + grpc.ClientStream +} + +type nezhaServiceRequestTaskClient struct { + grpc.ClientStream +} + +func (x *nezhaServiceRequestTaskClient) Send(m *TaskResult) error { + return x.ClientStream.SendMsg(m) +} + +func (x *nezhaServiceRequestTaskClient) Recv() (*Task, error) { + m := new(Task) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *nezhaServiceClient) IOStream(ctx context.Context, opts ...grpc.CallOption) (NezhaService_IOStreamClient, error) { + stream, err := c.cc.NewStream(ctx, &_NezhaService_serviceDesc.Streams[2], "/proto.NezhaService/IOStream", opts...) + if err != nil { + return nil, err + } + x := &nezhaServiceIOStreamClient{stream} + return x, nil +} + +type NezhaService_IOStreamClient interface { + Send(*IOStreamData) error + Recv() (*IOStreamData, error) + grpc.ClientStream +} + +type nezhaServiceIOStreamClient struct { + grpc.ClientStream +} + +func (x *nezhaServiceIOStreamClient) Send(m *IOStreamData) error { + return x.ClientStream.SendMsg(m) +} + +func (x *nezhaServiceIOStreamClient) Recv() (*IOStreamData, error) { + m := new(IOStreamData) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *nezhaServiceClient) ReportGeoIP(ctx context.Context, in *GeoIP, opts ...grpc.CallOption) (*GeoIP, error) { + out := new(GeoIP) + err := c.cc.Invoke(ctx, "/proto.NezhaService/ReportGeoIP", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *nezhaServiceClient) ReportSystemInfo2(ctx context.Context, in *Host, opts ...grpc.CallOption) (*Uint64Receipt, error) { + out := new(Uint64Receipt) + err := c.cc.Invoke(ctx, "/proto.NezhaService/ReportSystemInfo2", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// NezhaServiceServer is the server API for NezhaService service. +// All implementations must embed UnimplementedNezhaServiceServer +// for forward compatibility +type NezhaServiceServer interface { + ReportSystemState(NezhaService_ReportSystemStateServer) error + ReportSystemInfo(context.Context, *Host) (*Receipt, error) + RequestTask(NezhaService_RequestTaskServer) error + IOStream(NezhaService_IOStreamServer) error + ReportGeoIP(context.Context, *GeoIP) (*GeoIP, error) + ReportSystemInfo2(context.Context, *Host) (*Uint64Receipt, error) + mustEmbedUnimplementedNezhaServiceServer() +} + +// UnimplementedNezhaServiceServer must be embedded to have forward compatible implementations. +type UnimplementedNezhaServiceServer struct { +} + +func (UnimplementedNezhaServiceServer) ReportSystemState(NezhaService_ReportSystemStateServer) error { + return status.Errorf(codes.Unimplemented, "method ReportSystemState not implemented") +} +func (UnimplementedNezhaServiceServer) ReportSystemInfo(context.Context, *Host) (*Receipt, error) { + return nil, status.Errorf(codes.Unimplemented, "method ReportSystemInfo not implemented") +} +func (UnimplementedNezhaServiceServer) RequestTask(NezhaService_RequestTaskServer) error { + return status.Errorf(codes.Unimplemented, "method RequestTask not implemented") +} +func (UnimplementedNezhaServiceServer) IOStream(NezhaService_IOStreamServer) error { + return status.Errorf(codes.Unimplemented, "method IOStream not implemented") +} +func (UnimplementedNezhaServiceServer) ReportGeoIP(context.Context, *GeoIP) (*GeoIP, error) { + return nil, status.Errorf(codes.Unimplemented, "method ReportGeoIP not implemented") +} +func (UnimplementedNezhaServiceServer) ReportSystemInfo2(context.Context, *Host) (*Uint64Receipt, error) { + return nil, status.Errorf(codes.Unimplemented, "method ReportSystemInfo2 not implemented") +} +func (UnimplementedNezhaServiceServer) mustEmbedUnimplementedNezhaServiceServer() {} + +// UnsafeNezhaServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to NezhaServiceServer will +// result in compilation errors. +type UnsafeNezhaServiceServer interface { + mustEmbedUnimplementedNezhaServiceServer() +} + +func RegisterNezhaServiceServer(s *grpc.Server, srv NezhaServiceServer) { + s.RegisterService(&_NezhaService_serviceDesc, srv) +} + +func _NezhaService_ReportSystemState_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(NezhaServiceServer).ReportSystemState(&nezhaServiceReportSystemStateServer{stream}) +} + +type NezhaService_ReportSystemStateServer interface { + Send(*Receipt) error + Recv() (*State, error) + grpc.ServerStream +} + +type nezhaServiceReportSystemStateServer struct { + grpc.ServerStream +} + +func (x *nezhaServiceReportSystemStateServer) Send(m *Receipt) error { + return x.ServerStream.SendMsg(m) +} + +func (x *nezhaServiceReportSystemStateServer) Recv() (*State, error) { + m := new(State) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func _NezhaService_ReportSystemInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Host) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(NezhaServiceServer).ReportSystemInfo(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.NezhaService/ReportSystemInfo", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(NezhaServiceServer).ReportSystemInfo(ctx, req.(*Host)) + } + return interceptor(ctx, in, info, handler) +} + +func _NezhaService_RequestTask_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(NezhaServiceServer).RequestTask(&nezhaServiceRequestTaskServer{stream}) +} + +type NezhaService_RequestTaskServer interface { + Send(*Task) error + Recv() (*TaskResult, error) + grpc.ServerStream +} + +type nezhaServiceRequestTaskServer struct { + grpc.ServerStream +} + +func (x *nezhaServiceRequestTaskServer) Send(m *Task) error { + return x.ServerStream.SendMsg(m) +} + +func (x *nezhaServiceRequestTaskServer) Recv() (*TaskResult, error) { + m := new(TaskResult) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func _NezhaService_IOStream_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(NezhaServiceServer).IOStream(&nezhaServiceIOStreamServer{stream}) +} + +type NezhaService_IOStreamServer interface { + Send(*IOStreamData) error + Recv() (*IOStreamData, error) + grpc.ServerStream +} + +type nezhaServiceIOStreamServer struct { + grpc.ServerStream +} + +func (x *nezhaServiceIOStreamServer) Send(m *IOStreamData) error { + return x.ServerStream.SendMsg(m) +} + +func (x *nezhaServiceIOStreamServer) Recv() (*IOStreamData, error) { + m := new(IOStreamData) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func _NezhaService_ReportGeoIP_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GeoIP) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(NezhaServiceServer).ReportGeoIP(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.NezhaService/ReportGeoIP", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(NezhaServiceServer).ReportGeoIP(ctx, req.(*GeoIP)) + } + return interceptor(ctx, in, info, handler) +} + +func _NezhaService_ReportSystemInfo2_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Host) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(NezhaServiceServer).ReportSystemInfo2(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/proto.NezhaService/ReportSystemInfo2", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(NezhaServiceServer).ReportSystemInfo2(ctx, req.(*Host)) + } + return interceptor(ctx, in, info, handler) +} + +var _NezhaService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "proto.NezhaService", + HandlerType: (*NezhaServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "ReportSystemInfo", + Handler: _NezhaService_ReportSystemInfo_Handler, + }, + { + MethodName: "ReportGeoIP", + Handler: _NezhaService_ReportGeoIP_Handler, + }, + { + MethodName: "ReportSystemInfo2", + Handler: _NezhaService_ReportSystemInfo2_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "ReportSystemState", + Handler: _NezhaService_ReportSystemState_Handler, + ServerStreams: true, + ClientStreams: true, + }, + { + StreamName: "RequestTask", + Handler: _NezhaService_RequestTask_Handler, + ServerStreams: true, + ClientStreams: true, + }, + { + StreamName: "IOStream", + Handler: _NezhaService_IOStream_Handler, + ServerStreams: true, + ClientStreams: true, + }, + }, + Metadata: "compat/nezha/nezha.proto", +} diff --git a/database/config/config.go b/database/config/config.go index fb25864..91b6da7 100644 --- a/database/config/config.go +++ b/database/config/config.go @@ -25,15 +25,17 @@ func Get() (models.Config, error) { if err := db.First(&config).Error; err != nil { if err == gorm.ErrRecordNotFound { config = models.Config{ - ID: 1, - Sitename: "Komari", - Description: "Komari Monitor, a simple server monitoring tool.", - AllowCors: false, - OAuthEnabled: false, - GeoIpEnabled: true, - GeoIpProvider: "ip-api", - UpdatedAt: models.FromTime(time.Now()), - CreatedAt: models.FromTime(time.Now()), + ID: 1, + Sitename: "Komari", + Description: "Komari Monitor, a simple server monitoring tool.", + AllowCors: false, + OAuthEnabled: false, + GeoIpEnabled: true, + GeoIpProvider: "ip-api", + NezhaCompatEnabled: false, + NezhaCompatListen: "", + UpdatedAt: models.FromTime(time.Now()), + CreatedAt: models.FromTime(time.Now()), } if err := db.Create(&config).Error; err != nil { log.Fatal("Failed to create default config:", err) diff --git a/database/models/config.go b/database/models/config.go index e039538..edd110a 100644 --- a/database/models/config.go +++ b/database/models/config.go @@ -12,6 +12,9 @@ type Config struct { // GeoIP 配置 GeoIpEnabled bool `json:"geo_ip_enabled" gorm:"default:true"` GeoIpProvider string `json:"geo_ip_provider" gorm:"type:varchar(20);default:'ip-api'"` // empty, mmdb, ip-api, geojs + // Nezha 兼容(Agent gRPC) + NezhaCompatEnabled bool `json:"nezha_compat_enabled" gorm:"default:false"` + NezhaCompatListen string `json:"nezha_compat_listen" gorm:"type:varchar(100);default:''"` // 例如 0.0.0.0:5555 // OAuth 配置 OAuthEnabled bool `json:"o_auth_enabled" gorm:"default:false"` OAuthProvider string `json:"o_auth_provider" gorm:"type:varchar(50);default:'github'"` diff --git a/go.mod b/go.mod index 68349dc..74058d9 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,8 @@ require ( github.com/pquerna/otp v1.5.0 github.com/spf13/cobra v1.9.1 github.com/stretchr/testify v1.10.0 + google.golang.org/grpc v1.75.0 + google.golang.org/protobuf v1.36.6 gorm.io/driver/mysql v1.5.7 gorm.io/driver/sqlite v1.5.7 gorm.io/gorm v1.26.1 @@ -20,11 +22,11 @@ require ( // Misuse of ServerConfig.PublicKeyCallback may cause authorization bypass in golang.org/x/crypto #1 // golang.org/x/crypto Vulnerable to Denial of Service (DoS) via Slow or Incomplete Key Exchange #3 -require golang.org/x/crypto v0.37.0 // indirect +require golang.org/x/crypto v0.39.0 // indirect // HTTP Proxy bypass using IPv6 Zone IDs in golang.org/x/net #2 // golang.org/x/net vulnerable to Cross-site Scripting #4 -require golang.org/x/net v0.39.0 // indirect +require golang.org/x/net v0.41.0 // indirect require ( filippo.io/edwards25519 v1.1.0 // indirect @@ -35,7 +37,7 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/gabriel-vasile/mimetype v1.4.8 // indirect github.com/gin-contrib/sse v1.0.0 // indirect - github.com/go-jose/go-jose/v4 v4.0.5 // indirect + github.com/go-jose/go-jose/v4 v4.1.1 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.26.0 // indirect @@ -59,10 +61,10 @@ require ( github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect golang.org/x/arch v0.15.0 // indirect - golang.org/x/oauth2 v0.28.0 // indirect - golang.org/x/sys v0.32.0 // indirect - golang.org/x/text v0.25.0 // indirect - google.golang.org/protobuf v1.36.6 // indirect + golang.org/x/oauth2 v0.30.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/text v0.26.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index be99c10..1e14c7b 100644 --- a/go.sum +++ b/go.sum @@ -23,8 +23,12 @@ github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0= github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= -github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE= -github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA= +github.com/go-jose/go-jose/v4 v4.1.1 h1:JYhSgy4mXXzAdF3nUx3ygx347LRXJRrpgyU3adRmkAI= +github.com/go-jose/go-jose/v4 v4.1.1/go.mod h1:BdsZGqgdO3b6tTc6LSE56wcDbMMLuPsw5d4ZD5f94kA= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/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-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= @@ -38,8 +42,10 @@ github.com/go-sql-driver/mysql v1.9.2 h1:4cNKDYQ1I84SXslGddlsrMhc8k4LeDVj6Ad6WRj github.com/go-sql-driver/mysql v1.9.2/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= -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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +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= @@ -111,19 +117,37 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +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/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= +go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= +go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= +go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= +go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= +go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg= +go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc= +go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= +go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= +go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= golang.org/x/arch v0.15.0 h1:QtOrQd0bTUnhNVNndMpLHNWrDmYzZ2KDqSrEymqInZw= golang.org/x/arch v0.15.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE= -golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= -golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= -golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= -golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= -golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= -golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= +golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= +golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= -golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= -golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4= +google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/ws/existingConnection.go b/ws/existingConnection.go index f42295a..65e85a0 100644 --- a/ws/existingConnection.go +++ b/ws/existingConnection.go @@ -2,6 +2,7 @@ package ws import ( "sync" + "time" "github.com/gorilla/websocket" "github.com/komari-monitor/komari/common" @@ -11,7 +12,13 @@ var ( connectedClients = make(map[string]*SafeConn) ConnectedUsers = []*websocket.Conn{} latestReport = make(map[string]*common.Report) - mu = sync.RWMutex{} + // presenceOnly stores online state for non-WebSocket agents (e.g., Nezha gRPC) + // value keeps connectionID and a soft expiration to avoid flicker + presenceOnly = make(map[string]struct { + id int64 + expire time.Time + }) + mu = sync.RWMutex{} ) func GetConnectedClients() map[string]*SafeConn { @@ -44,6 +51,57 @@ func DeleteConnectedClients(uuid string) { // 只从 map 中删除,不再负责关闭连接 delete(connectedClients, uuid) } + +// SetPresence sets or clears presence for non-WebSocket agents. +// When present=false, it only clears if the connectionID matches current one. +// KeepAlivePresence sets presence with TTL for non-WebSocket agents. +func KeepAlivePresence(uuid string, connectionID int64, ttl time.Duration) { + mu.Lock() + defer mu.Unlock() + presenceOnly[uuid] = struct { + id int64 + expire time.Time + }{id: connectionID, expire: time.Now().Add(ttl)} +} + +var defaultPresenceTTL = 20 * time.Second + +// SetPresence keeps compatibility with existing callers. +func SetPresence(uuid string, connectionID int64, present bool) { + mu.Lock() + defer mu.Unlock() + if present { + presenceOnly[uuid] = struct { + id int64 + expire time.Time + }{id: connectionID, expire: time.Now().Add(defaultPresenceTTL)} + return + } + if cur, ok := presenceOnly[uuid]; ok && cur.id == connectionID { + delete(presenceOnly, uuid) + } +} + +// GetAllOnlineUUIDs returns a de-duplicated list of online UUIDs from both WebSocket and non-WebSocket agents. +func GetAllOnlineUUIDs() []string { + mu.RLock() + defer mu.RUnlock() + set := make(map[string]struct{}) + for k := range connectedClients { + set[k] = struct{}{} + } + now := time.Now() + for k, v := range presenceOnly { + if v.expire.After(now) { + set[k] = struct{}{} + } + } + res := make([]string, 0, len(set)) + for k := range set { + res = append(res, k) + } + return res +} func GetLatestReport() map[string]*common.Report { mu.RLock() defer mu.RUnlock()