mirror of
https://github.com/lorsanstand/HomeOps-Hub.git
synced 2026-09-18 16:18:21 +03:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0c69080a79 | |||
| 5f72d2dcb4 | |||
| 8d3509b2d8 | |||
| 5a42b918e0 | |||
| 43c43673a9 | |||
| b43575f390 | |||
| aae15f6599 | |||
| 07669d43c8 | |||
| dff83c6b60 | |||
| 593475f2cf | |||
| 8a3da3b017 | |||
| 0c2fdfee2a | |||
| 088ebcc51e | |||
| 2ca5e7fa8c | |||
| c41cbc3c2f | |||
| b157d7c32d | |||
| 6077e4c37d | |||
| 4f4d213aca | |||
| f0c3a67826 | |||
| ef67ccd7b2 | |||
| 8705f8708d |
@@ -1,3 +1,4 @@
|
|||||||
PORT=6756
|
PORT=6756
|
||||||
LOG_LEVEL=DEBUG
|
LOG_LEVEL=DEBUG
|
||||||
MODE=DEV
|
MODE=DEV
|
||||||
|
HEARTBEAT=5
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
|
|
||||||
Проект состоит из трех основных компонентов:
|
Проект состоит из трех основных компонентов:
|
||||||
|
|
||||||
1. **Hub (The Brain):** Центральный сервис на Go/Python. Хранит конфигурации, управляет состоянием, оркестрирует Runbooks и управляет Telegram-ботом. База данных — Postgres.
|
1. **Hub (The Brain):** Центральный сервис на Go/Python. Хранит конфигурации, управляет состоянием, оркестрирует Runbooks и управляет Telegram-ботом. База данных — SQLite.
|
||||||
2. **Agent (The Executor):** Легковесный бинарный файл, работающий непосредственно на целевом хосте. Связь с Хабом через **gRPC Stream**.
|
2. **Agent (The Executor):** Легковесный бинарный файл, работающий непосредственно на целевом хосте. Связь с Хабом через **gRPC Stream**.
|
||||||
3. **Telegram Interface:** Основной UI для оперативного управления с использованием Inline-кнопок для быстрых действий (Ack, Mute, Restart).
|
3. **Telegram Interface:** Основной UI для оперативного управления с использованием Inline-кнопок для быстрых действий (Ack, Mute, Restart).
|
||||||
|
|
||||||
@@ -66,7 +66,6 @@
|
|||||||
|
|
||||||
## 🔒 Безопасность
|
## 🔒 Безопасность
|
||||||
* **No Inbound Ports:** Агент не слушает порты. Соединение всегда инициируется изнутри вашей сети.
|
* **No Inbound Ports:** Агент не слушает порты. Соединение всегда инициируется изнутри вашей сети.
|
||||||
* **mTLS / Token Auth:** Весь трафик между Агентом и Хабом зашифрован.
|
|
||||||
* **Hardened Commands:** Невозможно выполнить `rm -rf /` — доступны только те команды, что описаны в коде агента.
|
* **Hardened Commands:** Невозможно выполнить `rm -rf /` — доступны только те команды, что описаны в коде агента.
|
||||||
|
|
||||||
*Created with ❤️ for Stasik.*
|
*Created with ❤️ for Stasik.*
|
||||||
@@ -32,7 +32,6 @@ func NewApp() (*App, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger := log.NewLogger(cfg)
|
logger := log.NewLogger(cfg)
|
||||||
logger = logger.With().Str("component", "internal.app").Logger()
|
|
||||||
logger = logger.With().Str("name", cfg.AppName).Logger()
|
logger = logger.With().Str("name", cfg.AppName).Logger()
|
||||||
|
|
||||||
sett, err := settings.ReadSettings(cfg.SettingsPath)
|
sett, err := settings.ReadSettings(cfg.SettingsPath)
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package domain
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
domainHub "github.com/lorsanstand/HomeOps-Hub/shared/domain"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Command struct {
|
||||||
|
domainHub.CapabilityCommand
|
||||||
|
Execute func(ctx context.Context, args map[string]string) (string, error)
|
||||||
|
}
|
||||||
@@ -2,9 +2,11 @@ package rpc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
pb "github.com/lorsanstand/HomeOps-Hub/api/gen/homeops"
|
pb "github.com/lorsanstand/HomeOps-Hub/api/gen/homeops"
|
||||||
"github.com/lorsanstand/HomeOps-Hub/shared/domain"
|
"github.com/lorsanstand/HomeOps-Hub/shared/domain"
|
||||||
|
"github.com/lorsanstand/HomeOps-Hub/shared/mappers/rpc"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -27,6 +29,13 @@ func (c *Connection) Hub() pb.HubClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Connection) RegisterAgent(ctx context.Context, RegisterData domain.RegisterAgentRequest) (domain.RegisterAgentResponse, error) {
|
func (c *Connection) RegisterAgent(ctx context.Context, RegisterData domain.RegisterAgentRequest) (domain.RegisterAgentResponse, error) {
|
||||||
ResponseData, err := c.Hub().RegisterAgent(ctx, new(domain.ToGRPCAgentRequest(RegisterData)))
|
ResponseData, err := c.Hub().RegisterAgent(ctx, rpc.ToGRPCAgentRequest(RegisterData))
|
||||||
return domain.ToDomainAgentResponse(ResponseData), err
|
if err != nil {
|
||||||
|
return domain.RegisterAgentResponse{}, fmt.Errorf("send register agent: %w", err)
|
||||||
|
}
|
||||||
|
response, err := rpc.ToDomainAgentResponse(ResponseData)
|
||||||
|
if err != nil {
|
||||||
|
return domain.RegisterAgentResponse{}, fmt.Errorf("casting response: %w", err)
|
||||||
|
}
|
||||||
|
return response, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,19 +9,6 @@ import (
|
|||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Collector interface {
|
|
||||||
GatherInfoSystem() (domain.HostInfo, []domain.Capability)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Settings interface {
|
|
||||||
InsertAgentID(agentID string) error
|
|
||||||
GetAgentID() string
|
|
||||||
}
|
|
||||||
|
|
||||||
type HubConnection interface {
|
|
||||||
RegisterAgent(ctx context.Context, RegisterData domain.RegisterAgentRequest) (domain.RegisterAgentResponse, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type AgentService struct {
|
type AgentService struct {
|
||||||
collect Collector
|
collect Collector
|
||||||
conn HubConnection
|
conn HubConnection
|
||||||
@@ -38,8 +25,6 @@ func NewAgentService(
|
|||||||
cfg *config_yaml.AgentConfig,
|
cfg *config_yaml.AgentConfig,
|
||||||
logger zerolog.Logger,
|
logger zerolog.Logger,
|
||||||
) *AgentService {
|
) *AgentService {
|
||||||
logger = logger.With().Str("component", "internal.service.agent_serivce").Logger()
|
|
||||||
|
|
||||||
return &AgentService{collect: collector, conn: conn, cfg: cfg, log: logger, settings: settings}
|
return &AgentService{collect: collector, conn: conn, cfg: cfg, log: logger, settings: settings}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package agent_service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/lorsanstand/HomeOps-Hub/shared/domain"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Collector interface {
|
||||||
|
GatherInfoSystem() (domain.HostInfo, []domain.Capability)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Settings interface {
|
||||||
|
InsertAgentID(agentID string) error
|
||||||
|
GetAgentID() string
|
||||||
|
}
|
||||||
|
|
||||||
|
type HubConnection interface {
|
||||||
|
RegisterAgent(ctx context.Context, RegisterData domain.RegisterAgentRequest) (domain.RegisterAgentResponse, error)
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package docker_service
|
||||||
|
|
||||||
|
import domainHub "github.com/lorsanstand/HomeOps-Hub/shared/domain"
|
||||||
|
|
||||||
|
func (d *DockerService) Capability() domainHub.Capability {
|
||||||
|
capability := domainHub.Capability{
|
||||||
|
Available: true,
|
||||||
|
Version: "0",
|
||||||
|
Name: "docker",
|
||||||
|
Reason: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
for command := com
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package docker_service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/lorsanstand/HomeOps-Hub/agent/internal/domain"
|
||||||
|
domainHub "github.com/lorsanstand/HomeOps-Hub/shared/domain"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (d *DockerService) commands() []domain.Command {
|
||||||
|
return []domain.Command{
|
||||||
|
{Execute: d.CheckDockerDaemon, CapabilityCommand: domainHub.CapabilityCommand{
|
||||||
|
Name: "check",
|
||||||
|
OptionalArgs: []domainHub.CommandArgs{},
|
||||||
|
RequiredArgs: []domainHub.CommandArgs{},
|
||||||
|
Version: "0",
|
||||||
|
Description: "Check docker daemon",
|
||||||
|
TypeOutput: "string",
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,8 +5,6 @@ import (
|
|||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/lorsanstand/HomeOps-Hub/shared/domain"
|
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -23,14 +21,17 @@ type DockerService struct {
|
|||||||
func NewDockerService(api dockerAPI, logger zerolog.Logger) *DockerService {
|
func NewDockerService(api dockerAPI, logger zerolog.Logger) *DockerService {
|
||||||
return &DockerService{
|
return &DockerService{
|
||||||
dockerClient: api,
|
dockerClient: api,
|
||||||
log: logger.With().Str("component", "internal.serivce.docker").Logger(),
|
log: logger,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DockerService) CheckDockerDaemon(ctx context.Context) error {
|
func (d *DockerService) CheckDockerDaemon(ctx context.Context, args map[string]string) (string, error) {
|
||||||
_, err := d.dockerClient.Ping(ctx)
|
_, err := d.dockerClient.Ping(ctx)
|
||||||
d.log.Debug().Msg("ping docker")
|
d.log.Debug().Msg("ping docker")
|
||||||
return err
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return "successful", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DockerService) ContainersList(ctx context.Context) ([]container.Summary, error) {
|
func (d *DockerService) ContainersList(ctx context.Context) ([]container.Summary, error) {
|
||||||
@@ -38,12 +39,3 @@ func (d *DockerService) ContainersList(ctx context.Context) ([]container.Summary
|
|||||||
d.log.Debug().Msg("get container list")
|
d.log.Debug().Msg("get container list")
|
||||||
return ContainersList, err
|
return ContainersList, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DockerService) Capability() domain.Capability {
|
|
||||||
return domain.Capability{
|
|
||||||
Available: true,
|
|
||||||
Version: "0",
|
|
||||||
Name: "docker",
|
|
||||||
Reason: "",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package command_store
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/lorsanstand/HomeOps-Hub/agent/internal/domain"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CommandStore struct {
|
||||||
|
mutex sync.RWMutex
|
||||||
|
store map[string]*domain.Command
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CommandStore) Get(name string) (*domain.Command, bool) {
|
||||||
|
c.mutex.RLock()
|
||||||
|
function, ok := c.store[name]
|
||||||
|
c.mutex.Unlock()
|
||||||
|
return function, ok
|
||||||
|
}
|
||||||
+19
-843
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.36.11
|
// protoc-gen-go v1.36.11
|
||||||
// protoc v7.34.1
|
// protoc v7.35.0
|
||||||
// source: homeops/hub.proto
|
// source: homeops/hub.proto
|
||||||
|
|
||||||
package homeops
|
package homeops
|
||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
emptypb "google.golang.org/protobuf/types/known/emptypb"
|
emptypb "google.golang.org/protobuf/types/known/emptypb"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
sync "sync"
|
|
||||||
unsafe "unsafe"
|
unsafe "unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -22,855 +21,36 @@ const (
|
|||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
)
|
)
|
||||||
|
|
||||||
type PongResponse struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
Pong string `protobuf:"bytes,1,opt,name=pong,proto3" json:"pong,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *PongResponse) Reset() {
|
|
||||||
*x = PongResponse{}
|
|
||||||
mi := &file_homeops_hub_proto_msgTypes[0]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *PongResponse) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*PongResponse) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *PongResponse) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_homeops_hub_proto_msgTypes[0]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use PongResponse.ProtoReflect.Descriptor instead.
|
|
||||||
func (*PongResponse) Descriptor() ([]byte, []int) {
|
|
||||||
return file_homeops_hub_proto_rawDescGZIP(), []int{0}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *PongResponse) GetPong() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Pong
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
type RegisterAgentRequest struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
AgentId string `protobuf:"bytes,1,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"`
|
|
||||||
AgentName string `protobuf:"bytes,2,opt,name=agent_name,json=agentName,proto3" json:"agent_name,omitempty"`
|
|
||||||
Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"`
|
|
||||||
Host *HostInfo `protobuf:"bytes,4,opt,name=host,proto3" json:"host,omitempty"`
|
|
||||||
Capability []*Capability `protobuf:"bytes,5,rep,name=capability,proto3" json:"capability,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *RegisterAgentRequest) Reset() {
|
|
||||||
*x = RegisterAgentRequest{}
|
|
||||||
mi := &file_homeops_hub_proto_msgTypes[1]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *RegisterAgentRequest) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*RegisterAgentRequest) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *RegisterAgentRequest) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_homeops_hub_proto_msgTypes[1]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use RegisterAgentRequest.ProtoReflect.Descriptor instead.
|
|
||||||
func (*RegisterAgentRequest) Descriptor() ([]byte, []int) {
|
|
||||||
return file_homeops_hub_proto_rawDescGZIP(), []int{1}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *RegisterAgentRequest) GetAgentId() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.AgentId
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *RegisterAgentRequest) GetAgentName() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.AgentName
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *RegisterAgentRequest) GetVersion() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Version
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *RegisterAgentRequest) GetHost() *HostInfo {
|
|
||||||
if x != nil {
|
|
||||||
return x.Host
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *RegisterAgentRequest) GetCapability() []*Capability {
|
|
||||||
if x != nil {
|
|
||||||
return x.Capability
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type HostInfo struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
System string `protobuf:"bytes,1,opt,name=system,proto3" json:"system,omitempty"`
|
|
||||||
Hostname string `protobuf:"bytes,2,opt,name=hostname,proto3" json:"hostname,omitempty"`
|
|
||||||
Arch string `protobuf:"bytes,3,opt,name=arch,proto3" json:"arch,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HostInfo) Reset() {
|
|
||||||
*x = HostInfo{}
|
|
||||||
mi := &file_homeops_hub_proto_msgTypes[2]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HostInfo) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*HostInfo) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *HostInfo) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_homeops_hub_proto_msgTypes[2]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use HostInfo.ProtoReflect.Descriptor instead.
|
|
||||||
func (*HostInfo) Descriptor() ([]byte, []int) {
|
|
||||||
return file_homeops_hub_proto_rawDescGZIP(), []int{2}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HostInfo) GetSystem() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.System
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HostInfo) GetHostname() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Hostname
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *HostInfo) GetArch() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Arch
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
type Capability struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
Available bool `protobuf:"varint,1,opt,name=available,proto3" json:"available,omitempty"`
|
|
||||||
Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
|
|
||||||
Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
|
|
||||||
Reason string `protobuf:"bytes,4,opt,name=reason,proto3" json:"reason,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Capability) Reset() {
|
|
||||||
*x = Capability{}
|
|
||||||
mi := &file_homeops_hub_proto_msgTypes[3]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Capability) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*Capability) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *Capability) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_homeops_hub_proto_msgTypes[3]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use Capability.ProtoReflect.Descriptor instead.
|
|
||||||
func (*Capability) Descriptor() ([]byte, []int) {
|
|
||||||
return file_homeops_hub_proto_rawDescGZIP(), []int{3}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Capability) GetAvailable() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.Available
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Capability) GetVersion() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Version
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Capability) GetName() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Name
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Capability) GetReason() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Reason
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
type RegisterAgentResponse struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
HeartbeatIntervalSecond int64 `protobuf:"varint,1,opt,name=heartbeat_interval_second,json=heartbeatIntervalSecond,proto3" json:"heartbeat_interval_second,omitempty"`
|
|
||||||
AgentId string `protobuf:"bytes,2,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *RegisterAgentResponse) Reset() {
|
|
||||||
*x = RegisterAgentResponse{}
|
|
||||||
mi := &file_homeops_hub_proto_msgTypes[4]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *RegisterAgentResponse) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*RegisterAgentResponse) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *RegisterAgentResponse) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_homeops_hub_proto_msgTypes[4]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use RegisterAgentResponse.ProtoReflect.Descriptor instead.
|
|
||||||
func (*RegisterAgentResponse) Descriptor() ([]byte, []int) {
|
|
||||||
return file_homeops_hub_proto_rawDescGZIP(), []int{4}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *RegisterAgentResponse) GetHeartbeatIntervalSecond() int64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.HeartbeatIntervalSecond
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *RegisterAgentResponse) GetAgentId() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.AgentId
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
type ServerCommandRequest struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"`
|
|
||||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
|
||||||
Args map[string]string `protobuf:"bytes,3,rep,name=args,proto3" json:"args,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
|
|
||||||
TimeoutSeconds int64 `protobuf:"varint,4,opt,name=timeout_seconds,json=timeoutSeconds,proto3" json:"timeout_seconds,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ServerCommandRequest) Reset() {
|
|
||||||
*x = ServerCommandRequest{}
|
|
||||||
mi := &file_homeops_hub_proto_msgTypes[5]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ServerCommandRequest) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*ServerCommandRequest) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *ServerCommandRequest) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_homeops_hub_proto_msgTypes[5]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use ServerCommandRequest.ProtoReflect.Descriptor instead.
|
|
||||||
func (*ServerCommandRequest) Descriptor() ([]byte, []int) {
|
|
||||||
return file_homeops_hub_proto_rawDescGZIP(), []int{5}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ServerCommandRequest) GetRequestId() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.RequestId
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ServerCommandRequest) GetName() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Name
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ServerCommandRequest) GetArgs() map[string]string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Args
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ServerCommandRequest) GetTimeoutSeconds() int64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.TimeoutSeconds
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
type AgentEvent struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
AgentId string `protobuf:"bytes,1,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"`
|
|
||||||
// Types that are valid to be assigned to Event:
|
|
||||||
//
|
|
||||||
// *AgentEvent_Heartbeat
|
|
||||||
// *AgentEvent_CommandResponse
|
|
||||||
// *AgentEvent_Alert
|
|
||||||
Event isAgentEvent_Event `protobuf_oneof:"event"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *AgentEvent) Reset() {
|
|
||||||
*x = AgentEvent{}
|
|
||||||
mi := &file_homeops_hub_proto_msgTypes[6]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *AgentEvent) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*AgentEvent) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *AgentEvent) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_homeops_hub_proto_msgTypes[6]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use AgentEvent.ProtoReflect.Descriptor instead.
|
|
||||||
func (*AgentEvent) Descriptor() ([]byte, []int) {
|
|
||||||
return file_homeops_hub_proto_rawDescGZIP(), []int{6}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *AgentEvent) GetAgentId() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.AgentId
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *AgentEvent) GetEvent() isAgentEvent_Event {
|
|
||||||
if x != nil {
|
|
||||||
return x.Event
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *AgentEvent) GetHeartbeat() *Heartbeat {
|
|
||||||
if x != nil {
|
|
||||||
if x, ok := x.Event.(*AgentEvent_Heartbeat); ok {
|
|
||||||
return x.Heartbeat
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *AgentEvent) GetCommandResponse() *CommandResponse {
|
|
||||||
if x != nil {
|
|
||||||
if x, ok := x.Event.(*AgentEvent_CommandResponse); ok {
|
|
||||||
return x.CommandResponse
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *AgentEvent) GetAlert() *Alert {
|
|
||||||
if x != nil {
|
|
||||||
if x, ok := x.Event.(*AgentEvent_Alert); ok {
|
|
||||||
return x.Alert
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type isAgentEvent_Event interface {
|
|
||||||
isAgentEvent_Event()
|
|
||||||
}
|
|
||||||
|
|
||||||
type AgentEvent_Heartbeat struct {
|
|
||||||
Heartbeat *Heartbeat `protobuf:"bytes,2,opt,name=heartbeat,proto3,oneof"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AgentEvent_CommandResponse struct {
|
|
||||||
CommandResponse *CommandResponse `protobuf:"bytes,3,opt,name=command_response,json=commandResponse,proto3,oneof"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AgentEvent_Alert struct {
|
|
||||||
Alert *Alert `protobuf:"bytes,4,opt,name=alert,proto3,oneof"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*AgentEvent_Heartbeat) isAgentEvent_Event() {}
|
|
||||||
|
|
||||||
func (*AgentEvent_CommandResponse) isAgentEvent_Event() {}
|
|
||||||
|
|
||||||
func (*AgentEvent_Alert) isAgentEvent_Event() {}
|
|
||||||
|
|
||||||
type Heartbeat struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
|
|
||||||
Metrics *SystemMetrics `protobuf:"bytes,2,opt,name=metrics,proto3" json:"metrics,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Heartbeat) Reset() {
|
|
||||||
*x = Heartbeat{}
|
|
||||||
mi := &file_homeops_hub_proto_msgTypes[7]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Heartbeat) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*Heartbeat) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *Heartbeat) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_homeops_hub_proto_msgTypes[7]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use Heartbeat.ProtoReflect.Descriptor instead.
|
|
||||||
func (*Heartbeat) Descriptor() ([]byte, []int) {
|
|
||||||
return file_homeops_hub_proto_rawDescGZIP(), []int{7}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Heartbeat) GetTimestamp() int64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Timestamp
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Heartbeat) GetMetrics() *SystemMetrics {
|
|
||||||
if x != nil {
|
|
||||||
return x.Metrics
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type SystemMetrics struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
CpuUsage float32 `protobuf:"fixed32,1,opt,name=cpu_usage,json=cpuUsage,proto3" json:"cpu_usage,omitempty"`
|
|
||||||
MemoryUsage float32 `protobuf:"fixed32,2,opt,name=memory_usage,json=memoryUsage,proto3" json:"memory_usage,omitempty"`
|
|
||||||
DiskUsage float32 `protobuf:"fixed32,3,opt,name=disk_usage,json=diskUsage,proto3" json:"disk_usage,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *SystemMetrics) Reset() {
|
|
||||||
*x = SystemMetrics{}
|
|
||||||
mi := &file_homeops_hub_proto_msgTypes[8]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *SystemMetrics) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*SystemMetrics) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *SystemMetrics) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_homeops_hub_proto_msgTypes[8]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use SystemMetrics.ProtoReflect.Descriptor instead.
|
|
||||||
func (*SystemMetrics) Descriptor() ([]byte, []int) {
|
|
||||||
return file_homeops_hub_proto_rawDescGZIP(), []int{8}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *SystemMetrics) GetCpuUsage() float32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.CpuUsage
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *SystemMetrics) GetMemoryUsage() float32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.MemoryUsage
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *SystemMetrics) GetDiskUsage() float32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.DiskUsage
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
type CommandResponse struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"`
|
|
||||||
Success bool `protobuf:"varint,2,opt,name=success,proto3" json:"success,omitempty"`
|
|
||||||
Output string `protobuf:"bytes,3,opt,name=output,proto3" json:"output,omitempty"`
|
|
||||||
Error string `protobuf:"bytes,4,opt,name=error,proto3" json:"error,omitempty"`
|
|
||||||
ExecTimeMs int64 `protobuf:"varint,5,opt,name=exec_time_ms,json=execTimeMs,proto3" json:"exec_time_ms,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CommandResponse) Reset() {
|
|
||||||
*x = CommandResponse{}
|
|
||||||
mi := &file_homeops_hub_proto_msgTypes[9]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CommandResponse) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*CommandResponse) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *CommandResponse) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_homeops_hub_proto_msgTypes[9]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use CommandResponse.ProtoReflect.Descriptor instead.
|
|
||||||
func (*CommandResponse) Descriptor() ([]byte, []int) {
|
|
||||||
return file_homeops_hub_proto_rawDescGZIP(), []int{9}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CommandResponse) GetRequestId() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.RequestId
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CommandResponse) GetSuccess() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.Success
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CommandResponse) GetOutput() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Output
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CommandResponse) GetError() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Error
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *CommandResponse) GetExecTimeMs() int64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.ExecTimeMs
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
type Alert struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
|
|
||||||
Level string `protobuf:"bytes,2,opt,name=level,proto3" json:"level,omitempty"`
|
|
||||||
Title string `protobuf:"bytes,3,opt,name=title,proto3" json:"title,omitempty"`
|
|
||||||
Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Alert) Reset() {
|
|
||||||
*x = Alert{}
|
|
||||||
mi := &file_homeops_hub_proto_msgTypes[10]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Alert) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*Alert) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *Alert) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_homeops_hub_proto_msgTypes[10]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use Alert.ProtoReflect.Descriptor instead.
|
|
||||||
func (*Alert) Descriptor() ([]byte, []int) {
|
|
||||||
return file_homeops_hub_proto_rawDescGZIP(), []int{10}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Alert) GetTimestamp() int64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Timestamp
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Alert) GetLevel() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Level
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Alert) GetTitle() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Title
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Alert) GetDescription() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Description
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_homeops_hub_proto protoreflect.FileDescriptor
|
var File_homeops_hub_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
const file_homeops_hub_proto_rawDesc = "" +
|
const file_homeops_hub_proto_rawDesc = "" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"\x11homeops/hub.proto\x1a\x1bgoogle/protobuf/empty.proto\"\"\n" +
|
"\x11homeops/hub.proto\x1a\x1bgoogle/protobuf/empty.proto\x1a\x16homeops/register.proto\x1a\x14homeops/stream.proto2\xb6\x01\n" +
|
||||||
"\fPongResponse\x12\x12\n" +
|
|
||||||
"\x04pong\x18\x01 \x01(\tR\x04pong\"\xb6\x01\n" +
|
|
||||||
"\x14RegisterAgentRequest\x12\x19\n" +
|
|
||||||
"\bagent_id\x18\x01 \x01(\tR\aagentId\x12\x1d\n" +
|
|
||||||
"\n" +
|
|
||||||
"agent_name\x18\x02 \x01(\tR\tagentName\x12\x18\n" +
|
|
||||||
"\aversion\x18\x03 \x01(\tR\aversion\x12\x1d\n" +
|
|
||||||
"\x04host\x18\x04 \x01(\v2\t.HostInfoR\x04host\x12+\n" +
|
|
||||||
"\n" +
|
|
||||||
"capability\x18\x05 \x03(\v2\v.CapabilityR\n" +
|
|
||||||
"capability\"R\n" +
|
|
||||||
"\bHostInfo\x12\x16\n" +
|
|
||||||
"\x06system\x18\x01 \x01(\tR\x06system\x12\x1a\n" +
|
|
||||||
"\bhostname\x18\x02 \x01(\tR\bhostname\x12\x12\n" +
|
|
||||||
"\x04arch\x18\x03 \x01(\tR\x04arch\"p\n" +
|
|
||||||
"\n" +
|
|
||||||
"Capability\x12\x1c\n" +
|
|
||||||
"\tavailable\x18\x01 \x01(\bR\tavailable\x12\x18\n" +
|
|
||||||
"\aversion\x18\x02 \x01(\tR\aversion\x12\x12\n" +
|
|
||||||
"\x04name\x18\x03 \x01(\tR\x04name\x12\x16\n" +
|
|
||||||
"\x06reason\x18\x04 \x01(\tR\x06reason\"n\n" +
|
|
||||||
"\x15RegisterAgentResponse\x12:\n" +
|
|
||||||
"\x19heartbeat_interval_second\x18\x01 \x01(\x03R\x17heartbeatIntervalSecond\x12\x19\n" +
|
|
||||||
"\bagent_id\x18\x02 \x01(\tR\aagentId\"\xe0\x01\n" +
|
|
||||||
"\x14ServerCommandRequest\x12\x1d\n" +
|
|
||||||
"\n" +
|
|
||||||
"request_id\x18\x01 \x01(\tR\trequestId\x12\x12\n" +
|
|
||||||
"\x04name\x18\x02 \x01(\tR\x04name\x123\n" +
|
|
||||||
"\x04args\x18\x03 \x03(\v2\x1f.ServerCommandRequest.ArgsEntryR\x04args\x12'\n" +
|
|
||||||
"\x0ftimeout_seconds\x18\x04 \x01(\x03R\x0etimeoutSeconds\x1a7\n" +
|
|
||||||
"\tArgsEntry\x12\x10\n" +
|
|
||||||
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
|
|
||||||
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xbb\x01\n" +
|
|
||||||
"\n" +
|
|
||||||
"AgentEvent\x12\x19\n" +
|
|
||||||
"\bagent_id\x18\x01 \x01(\tR\aagentId\x12*\n" +
|
|
||||||
"\theartbeat\x18\x02 \x01(\v2\n" +
|
|
||||||
".HeartbeatH\x00R\theartbeat\x12=\n" +
|
|
||||||
"\x10command_response\x18\x03 \x01(\v2\x10.CommandResponseH\x00R\x0fcommandResponse\x12\x1e\n" +
|
|
||||||
"\x05alert\x18\x04 \x01(\v2\x06.AlertH\x00R\x05alertB\a\n" +
|
|
||||||
"\x05event\"S\n" +
|
|
||||||
"\tHeartbeat\x12\x1c\n" +
|
|
||||||
"\ttimestamp\x18\x01 \x01(\x03R\ttimestamp\x12(\n" +
|
|
||||||
"\ametrics\x18\x02 \x01(\v2\x0e.SystemMetricsR\ametrics\"n\n" +
|
|
||||||
"\rSystemMetrics\x12\x1b\n" +
|
|
||||||
"\tcpu_usage\x18\x01 \x01(\x02R\bcpuUsage\x12!\n" +
|
|
||||||
"\fmemory_usage\x18\x02 \x01(\x02R\vmemoryUsage\x12\x1d\n" +
|
|
||||||
"\n" +
|
|
||||||
"disk_usage\x18\x03 \x01(\x02R\tdiskUsage\"\x9a\x01\n" +
|
|
||||||
"\x0fCommandResponse\x12\x1d\n" +
|
|
||||||
"\n" +
|
|
||||||
"request_id\x18\x01 \x01(\tR\trequestId\x12\x18\n" +
|
|
||||||
"\asuccess\x18\x02 \x01(\bR\asuccess\x12\x16\n" +
|
|
||||||
"\x06output\x18\x03 \x01(\tR\x06output\x12\x14\n" +
|
|
||||||
"\x05error\x18\x04 \x01(\tR\x05error\x12 \n" +
|
|
||||||
"\fexec_time_ms\x18\x05 \x01(\x03R\n" +
|
|
||||||
"execTimeMs\"s\n" +
|
|
||||||
"\x05Alert\x12\x1c\n" +
|
|
||||||
"\ttimestamp\x18\x01 \x01(\x03R\ttimestamp\x12\x14\n" +
|
|
||||||
"\x05level\x18\x02 \x01(\tR\x05level\x12\x14\n" +
|
|
||||||
"\x05title\x18\x03 \x01(\tR\x05title\x12 \n" +
|
|
||||||
"\vdescription\x18\x04 \x01(\tR\vdescription2\xb6\x01\n" +
|
|
||||||
"\x03Hub\x12/\n" +
|
"\x03Hub\x12/\n" +
|
||||||
"\x04Ping\x12\x16.google.protobuf.Empty\x1a\r.PongResponse\"\x00\x12@\n" +
|
"\x04Ping\x12\x16.google.protobuf.Empty\x1a\r.PongResponse\"\x00\x12@\n" +
|
||||||
"\rRegisterAgent\x12\x15.RegisterAgentRequest\x1a\x16.RegisterAgentResponse\"\x00\x12<\n" +
|
"\rRegisterAgent\x12\x15.RegisterAgentRequest\x1a\x16.RegisterAgentResponse\"\x00\x12<\n" +
|
||||||
"\x10StreamConnection\x12\v.AgentEvent\x1a\x15.ServerCommandRequest\"\x00(\x010\x01B<Z:github.com/lorsanstand/HomeOps-Hub/api/gen/homeops;homeopsb\x06proto3"
|
"\x10StreamConnection\x12\v.AgentEvent\x1a\x15.ServerCommandRequest\"\x00(\x010\x01B<Z:github.com/lorsanstand/HomeOps-Hub/api/gen/homeops;homeopsb\x06proto3"
|
||||||
|
|
||||||
var (
|
|
||||||
file_homeops_hub_proto_rawDescOnce sync.Once
|
|
||||||
file_homeops_hub_proto_rawDescData []byte
|
|
||||||
)
|
|
||||||
|
|
||||||
func file_homeops_hub_proto_rawDescGZIP() []byte {
|
|
||||||
file_homeops_hub_proto_rawDescOnce.Do(func() {
|
|
||||||
file_homeops_hub_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_homeops_hub_proto_rawDesc), len(file_homeops_hub_proto_rawDesc)))
|
|
||||||
})
|
|
||||||
return file_homeops_hub_proto_rawDescData
|
|
||||||
}
|
|
||||||
|
|
||||||
var file_homeops_hub_proto_msgTypes = make([]protoimpl.MessageInfo, 12)
|
|
||||||
var file_homeops_hub_proto_goTypes = []any{
|
var file_homeops_hub_proto_goTypes = []any{
|
||||||
(*PongResponse)(nil), // 0: PongResponse
|
(*emptypb.Empty)(nil), // 0: google.protobuf.Empty
|
||||||
(*RegisterAgentRequest)(nil), // 1: RegisterAgentRequest
|
(*RegisterAgentRequest)(nil), // 1: RegisterAgentRequest
|
||||||
(*HostInfo)(nil), // 2: HostInfo
|
(*AgentEvent)(nil), // 2: AgentEvent
|
||||||
(*Capability)(nil), // 3: Capability
|
(*PongResponse)(nil), // 3: PongResponse
|
||||||
(*RegisterAgentResponse)(nil), // 4: RegisterAgentResponse
|
(*RegisterAgentResponse)(nil), // 4: RegisterAgentResponse
|
||||||
(*ServerCommandRequest)(nil), // 5: ServerCommandRequest
|
(*ServerCommandRequest)(nil), // 5: ServerCommandRequest
|
||||||
(*AgentEvent)(nil), // 6: AgentEvent
|
|
||||||
(*Heartbeat)(nil), // 7: Heartbeat
|
|
||||||
(*SystemMetrics)(nil), // 8: SystemMetrics
|
|
||||||
(*CommandResponse)(nil), // 9: CommandResponse
|
|
||||||
(*Alert)(nil), // 10: Alert
|
|
||||||
nil, // 11: ServerCommandRequest.ArgsEntry
|
|
||||||
(*emptypb.Empty)(nil), // 12: google.protobuf.Empty
|
|
||||||
}
|
}
|
||||||
var file_homeops_hub_proto_depIdxs = []int32{
|
var file_homeops_hub_proto_depIdxs = []int32{
|
||||||
2, // 0: RegisterAgentRequest.host:type_name -> HostInfo
|
0, // 0: Hub.Ping:input_type -> google.protobuf.Empty
|
||||||
3, // 1: RegisterAgentRequest.capability:type_name -> Capability
|
1, // 1: Hub.RegisterAgent:input_type -> RegisterAgentRequest
|
||||||
11, // 2: ServerCommandRequest.args:type_name -> ServerCommandRequest.ArgsEntry
|
2, // 2: Hub.StreamConnection:input_type -> AgentEvent
|
||||||
7, // 3: AgentEvent.heartbeat:type_name -> Heartbeat
|
3, // 3: Hub.Ping:output_type -> PongResponse
|
||||||
9, // 4: AgentEvent.command_response:type_name -> CommandResponse
|
4, // 4: Hub.RegisterAgent:output_type -> RegisterAgentResponse
|
||||||
10, // 5: AgentEvent.alert:type_name -> Alert
|
5, // 5: Hub.StreamConnection:output_type -> ServerCommandRequest
|
||||||
8, // 6: Heartbeat.metrics:type_name -> SystemMetrics
|
3, // [3:6] is the sub-list for method output_type
|
||||||
12, // 7: Hub.Ping:input_type -> google.protobuf.Empty
|
0, // [0:3] is the sub-list for method input_type
|
||||||
1, // 8: Hub.RegisterAgent:input_type -> RegisterAgentRequest
|
0, // [0:0] is the sub-list for extension type_name
|
||||||
6, // 9: Hub.StreamConnection:input_type -> AgentEvent
|
0, // [0:0] is the sub-list for extension extendee
|
||||||
0, // 10: Hub.Ping:output_type -> PongResponse
|
0, // [0:0] is the sub-list for field type_name
|
||||||
4, // 11: Hub.RegisterAgent:output_type -> RegisterAgentResponse
|
|
||||||
5, // 12: Hub.StreamConnection:output_type -> ServerCommandRequest
|
|
||||||
10, // [10:13] is the sub-list for method output_type
|
|
||||||
7, // [7:10] is the sub-list for method input_type
|
|
||||||
7, // [7:7] is the sub-list for extension type_name
|
|
||||||
7, // [7:7] is the sub-list for extension extendee
|
|
||||||
0, // [0:7] is the sub-list for field type_name
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_homeops_hub_proto_init() }
|
func init() { file_homeops_hub_proto_init() }
|
||||||
@@ -878,24 +58,20 @@ func file_homeops_hub_proto_init() {
|
|||||||
if File_homeops_hub_proto != nil {
|
if File_homeops_hub_proto != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
file_homeops_hub_proto_msgTypes[6].OneofWrappers = []any{
|
file_homeops_register_proto_init()
|
||||||
(*AgentEvent_Heartbeat)(nil),
|
file_homeops_stream_proto_init()
|
||||||
(*AgentEvent_CommandResponse)(nil),
|
|
||||||
(*AgentEvent_Alert)(nil),
|
|
||||||
}
|
|
||||||
type x struct{}
|
type x struct{}
|
||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_homeops_hub_proto_rawDesc), len(file_homeops_hub_proto_rawDesc)),
|
RawDescriptor: unsafe.Slice(unsafe.StringData(file_homeops_hub_proto_rawDesc), len(file_homeops_hub_proto_rawDesc)),
|
||||||
NumEnums: 0,
|
NumEnums: 0,
|
||||||
NumMessages: 12,
|
NumMessages: 0,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 1,
|
NumServices: 1,
|
||||||
},
|
},
|
||||||
GoTypes: file_homeops_hub_proto_goTypes,
|
GoTypes: file_homeops_hub_proto_goTypes,
|
||||||
DependencyIndexes: file_homeops_hub_proto_depIdxs,
|
DependencyIndexes: file_homeops_hub_proto_depIdxs,
|
||||||
MessageInfos: file_homeops_hub_proto_msgTypes,
|
|
||||||
}.Build()
|
}.Build()
|
||||||
File_homeops_hub_proto = out.File
|
File_homeops_hub_proto = out.File
|
||||||
file_homeops_hub_proto_goTypes = nil
|
file_homeops_hub_proto_goTypes = nil
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// - protoc-gen-go-grpc v1.6.1
|
// - protoc-gen-go-grpc v1.6.1
|
||||||
// - protoc v7.34.1
|
// - protoc v7.35.0
|
||||||
// source: homeops/hub.proto
|
// source: homeops/hub.proto
|
||||||
|
|
||||||
package homeops
|
package homeops
|
||||||
|
|||||||
@@ -0,0 +1,676 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go v1.36.11
|
||||||
|
// protoc v7.35.0
|
||||||
|
// source: homeops/register.proto
|
||||||
|
|
||||||
|
package homeops
|
||||||
|
|
||||||
|
import (
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
reflect "reflect"
|
||||||
|
sync "sync"
|
||||||
|
unsafe "unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
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 PongResponse struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
Pong string `protobuf:"bytes,1,opt,name=pong,proto3" json:"pong,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *PongResponse) Reset() {
|
||||||
|
*x = PongResponse{}
|
||||||
|
mi := &file_homeops_register_proto_msgTypes[0]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *PongResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*PongResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *PongResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_homeops_register_proto_msgTypes[0]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use PongResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*PongResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_homeops_register_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *PongResponse) GetPong() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Pong
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type RegisterAgentRequest struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
AgentId string `protobuf:"bytes,1,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"`
|
||||||
|
AgentName string `protobuf:"bytes,2,opt,name=agent_name,json=agentName,proto3" json:"agent_name,omitempty"`
|
||||||
|
Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"`
|
||||||
|
Host *HostInfo `protobuf:"bytes,4,opt,name=host,proto3" json:"host,omitempty"`
|
||||||
|
Capability map[string]*Capability `protobuf:"bytes,5,rep,name=capability,proto3" json:"capability,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *RegisterAgentRequest) Reset() {
|
||||||
|
*x = RegisterAgentRequest{}
|
||||||
|
mi := &file_homeops_register_proto_msgTypes[1]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *RegisterAgentRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*RegisterAgentRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *RegisterAgentRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_homeops_register_proto_msgTypes[1]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use RegisterAgentRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*RegisterAgentRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_homeops_register_proto_rawDescGZIP(), []int{1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *RegisterAgentRequest) GetAgentId() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.AgentId
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *RegisterAgentRequest) GetAgentName() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.AgentName
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *RegisterAgentRequest) GetVersion() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Version
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *RegisterAgentRequest) GetHost() *HostInfo {
|
||||||
|
if x != nil {
|
||||||
|
return x.Host
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *RegisterAgentRequest) GetCapability() map[string]*Capability {
|
||||||
|
if x != nil {
|
||||||
|
return x.Capability
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type HostInfo struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
System string `protobuf:"bytes,1,opt,name=system,proto3" json:"system,omitempty"`
|
||||||
|
Hostname string `protobuf:"bytes,2,opt,name=hostname,proto3" json:"hostname,omitempty"`
|
||||||
|
Arch string `protobuf:"bytes,3,opt,name=arch,proto3" json:"arch,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HostInfo) Reset() {
|
||||||
|
*x = HostInfo{}
|
||||||
|
mi := &file_homeops_register_proto_msgTypes[2]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HostInfo) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*HostInfo) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *HostInfo) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_homeops_register_proto_msgTypes[2]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use HostInfo.ProtoReflect.Descriptor instead.
|
||||||
|
func (*HostInfo) Descriptor() ([]byte, []int) {
|
||||||
|
return file_homeops_register_proto_rawDescGZIP(), []int{2}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HostInfo) GetSystem() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.System
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HostInfo) GetHostname() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Hostname
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *HostInfo) GetArch() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Arch
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type Capability struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
Available bool `protobuf:"varint,1,opt,name=available,proto3" json:"available,omitempty"` // доступен ли
|
||||||
|
Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"` // версия раздела
|
||||||
|
// string name = 3; // название раздела по типу докер или управление пк
|
||||||
|
Reason string `protobuf:"bytes,4,opt,name=reason,proto3" json:"reason,omitempty"` // причина если раздел не доступент
|
||||||
|
Command map[string]*CapabilityCommand `protobuf:"bytes,5,rep,name=command,proto3" json:"command,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // команды раздела
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Capability) Reset() {
|
||||||
|
*x = Capability{}
|
||||||
|
mi := &file_homeops_register_proto_msgTypes[3]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Capability) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Capability) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *Capability) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_homeops_register_proto_msgTypes[3]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use Capability.ProtoReflect.Descriptor instead.
|
||||||
|
func (*Capability) Descriptor() ([]byte, []int) {
|
||||||
|
return file_homeops_register_proto_rawDescGZIP(), []int{3}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Capability) GetAvailable() bool {
|
||||||
|
if x != nil {
|
||||||
|
return x.Available
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Capability) GetVersion() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Version
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Capability) GetReason() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Reason
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Capability) GetCommand() map[string]*CapabilityCommand {
|
||||||
|
if x != nil {
|
||||||
|
return x.Command
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type CapabilityCommand struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
// string name = 1; // название команды
|
||||||
|
OptArgs map[string]*CommandsArgs `protobuf:"bytes,2,rep,name=opt_args,json=optArgs,proto3" json:"opt_args,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // опциоанльные переменные
|
||||||
|
ReqArgs map[string]*CommandsArgs `protobuf:"bytes,3,rep,name=req_args,json=reqArgs,proto3" json:"req_args,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // обязательные переменные
|
||||||
|
Version string `protobuf:"bytes,4,opt,name=version,proto3" json:"version,omitempty"` // версия команды
|
||||||
|
Description string `protobuf:"bytes,5,opt,name=description,proto3" json:"description,omitempty"` // описание команды для документации
|
||||||
|
TypeOutput string `protobuf:"bytes,7,opt,name=type_output,json=typeOutput,proto3" json:"type_output,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CapabilityCommand) Reset() {
|
||||||
|
*x = CapabilityCommand{}
|
||||||
|
mi := &file_homeops_register_proto_msgTypes[4]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CapabilityCommand) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*CapabilityCommand) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *CapabilityCommand) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_homeops_register_proto_msgTypes[4]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use CapabilityCommand.ProtoReflect.Descriptor instead.
|
||||||
|
func (*CapabilityCommand) Descriptor() ([]byte, []int) {
|
||||||
|
return file_homeops_register_proto_rawDescGZIP(), []int{4}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CapabilityCommand) GetOptArgs() map[string]*CommandsArgs {
|
||||||
|
if x != nil {
|
||||||
|
return x.OptArgs
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CapabilityCommand) GetReqArgs() map[string]*CommandsArgs {
|
||||||
|
if x != nil {
|
||||||
|
return x.ReqArgs
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CapabilityCommand) GetVersion() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Version
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CapabilityCommand) GetDescription() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Description
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CapabilityCommand) GetTypeOutput() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.TypeOutput
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type CommandsArgs struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
// string name = 1; // название аргумента
|
||||||
|
Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` // какой тип path int string bool
|
||||||
|
Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` // описание для документации
|
||||||
|
Default string `protobuf:"bytes,4,opt,name=default,proto3" json:"default,omitempty"` // значение по умолчанию
|
||||||
|
Enum []string `protobuf:"bytes,5,rep,name=enum,proto3" json:"enum,omitempty"` // enum комманд по типу run stop restart
|
||||||
|
Validation *ArgValidation `protobuf:"bytes,6,opt,name=validation,proto3" json:"validation,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CommandsArgs) Reset() {
|
||||||
|
*x = CommandsArgs{}
|
||||||
|
mi := &file_homeops_register_proto_msgTypes[5]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CommandsArgs) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*CommandsArgs) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *CommandsArgs) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_homeops_register_proto_msgTypes[5]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use CommandsArgs.ProtoReflect.Descriptor instead.
|
||||||
|
func (*CommandsArgs) Descriptor() ([]byte, []int) {
|
||||||
|
return file_homeops_register_proto_rawDescGZIP(), []int{5}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CommandsArgs) GetType() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Type
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CommandsArgs) GetDescription() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Description
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CommandsArgs) GetDefault() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Default
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CommandsArgs) GetEnum() []string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Enum
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CommandsArgs) GetValidation() *ArgValidation {
|
||||||
|
if x != nil {
|
||||||
|
return x.Validation
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArgValidation struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
MinValue int64 `protobuf:"varint,1,opt,name=min_value,json=minValue,proto3" json:"min_value,omitempty"` // для чисел
|
||||||
|
MaxValue int64 `protobuf:"varint,2,opt,name=max_value,json=maxValue,proto3" json:"max_value,omitempty"` // для чисел
|
||||||
|
Pattern string `protobuf:"bytes,3,opt,name=pattern,proto3" json:"pattern,omitempty"` // для regex строк
|
||||||
|
AllowedExts []string `protobuf:"bytes,4,rep,name=allowed_exts,json=allowedExts,proto3" json:"allowed_exts,omitempty"` // для путей и файлов по типу .zip .rar итд
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ArgValidation) Reset() {
|
||||||
|
*x = ArgValidation{}
|
||||||
|
mi := &file_homeops_register_proto_msgTypes[6]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ArgValidation) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ArgValidation) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ArgValidation) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_homeops_register_proto_msgTypes[6]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ArgValidation.ProtoReflect.Descriptor instead.
|
||||||
|
func (*ArgValidation) Descriptor() ([]byte, []int) {
|
||||||
|
return file_homeops_register_proto_rawDescGZIP(), []int{6}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ArgValidation) GetMinValue() int64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.MinValue
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ArgValidation) GetMaxValue() int64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.MaxValue
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ArgValidation) GetPattern() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Pattern
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ArgValidation) GetAllowedExts() []string {
|
||||||
|
if x != nil {
|
||||||
|
return x.AllowedExts
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type RegisterAgentResponse struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
HeartbeatIntervalSecond int64 `protobuf:"varint,1,opt,name=heartbeat_interval_second,json=heartbeatIntervalSecond,proto3" json:"heartbeat_interval_second,omitempty"`
|
||||||
|
AgentId string `protobuf:"bytes,2,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *RegisterAgentResponse) Reset() {
|
||||||
|
*x = RegisterAgentResponse{}
|
||||||
|
mi := &file_homeops_register_proto_msgTypes[7]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *RegisterAgentResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*RegisterAgentResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *RegisterAgentResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_homeops_register_proto_msgTypes[7]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use RegisterAgentResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*RegisterAgentResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_homeops_register_proto_rawDescGZIP(), []int{7}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *RegisterAgentResponse) GetHeartbeatIntervalSecond() int64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.HeartbeatIntervalSecond
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *RegisterAgentResponse) GetAgentId() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.AgentId
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var File_homeops_register_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
const file_homeops_register_proto_rawDesc = "" +
|
||||||
|
"\n" +
|
||||||
|
"\x16homeops/register.proto\"\"\n" +
|
||||||
|
"\fPongResponse\x12\x12\n" +
|
||||||
|
"\x04pong\x18\x01 \x01(\tR\x04pong\"\x9c\x02\n" +
|
||||||
|
"\x14RegisterAgentRequest\x12\x19\n" +
|
||||||
|
"\bagent_id\x18\x01 \x01(\tR\aagentId\x12\x1d\n" +
|
||||||
|
"\n" +
|
||||||
|
"agent_name\x18\x02 \x01(\tR\tagentName\x12\x18\n" +
|
||||||
|
"\aversion\x18\x03 \x01(\tR\aversion\x12\x1d\n" +
|
||||||
|
"\x04host\x18\x04 \x01(\v2\t.HostInfoR\x04host\x12E\n" +
|
||||||
|
"\n" +
|
||||||
|
"capability\x18\x05 \x03(\v2%.RegisterAgentRequest.CapabilityEntryR\n" +
|
||||||
|
"capability\x1aJ\n" +
|
||||||
|
"\x0fCapabilityEntry\x12\x10\n" +
|
||||||
|
"\x03key\x18\x01 \x01(\tR\x03key\x12!\n" +
|
||||||
|
"\x05value\x18\x02 \x01(\v2\v.CapabilityR\x05value:\x028\x01\"R\n" +
|
||||||
|
"\bHostInfo\x12\x16\n" +
|
||||||
|
"\x06system\x18\x01 \x01(\tR\x06system\x12\x1a\n" +
|
||||||
|
"\bhostname\x18\x02 \x01(\tR\bhostname\x12\x12\n" +
|
||||||
|
"\x04arch\x18\x03 \x01(\tR\x04arch\"\xe0\x01\n" +
|
||||||
|
"\n" +
|
||||||
|
"Capability\x12\x1c\n" +
|
||||||
|
"\tavailable\x18\x01 \x01(\bR\tavailable\x12\x18\n" +
|
||||||
|
"\aversion\x18\x02 \x01(\tR\aversion\x12\x16\n" +
|
||||||
|
"\x06reason\x18\x04 \x01(\tR\x06reason\x122\n" +
|
||||||
|
"\acommand\x18\x05 \x03(\v2\x18.Capability.CommandEntryR\acommand\x1aN\n" +
|
||||||
|
"\fCommandEntry\x12\x10\n" +
|
||||||
|
"\x03key\x18\x01 \x01(\tR\x03key\x12(\n" +
|
||||||
|
"\x05value\x18\x02 \x01(\v2\x12.CapabilityCommandR\x05value:\x028\x01\"\xfe\x02\n" +
|
||||||
|
"\x11CapabilityCommand\x12:\n" +
|
||||||
|
"\bopt_args\x18\x02 \x03(\v2\x1f.CapabilityCommand.OptArgsEntryR\aoptArgs\x12:\n" +
|
||||||
|
"\breq_args\x18\x03 \x03(\v2\x1f.CapabilityCommand.ReqArgsEntryR\areqArgs\x12\x18\n" +
|
||||||
|
"\aversion\x18\x04 \x01(\tR\aversion\x12 \n" +
|
||||||
|
"\vdescription\x18\x05 \x01(\tR\vdescription\x12\x1f\n" +
|
||||||
|
"\vtype_output\x18\a \x01(\tR\n" +
|
||||||
|
"typeOutput\x1aI\n" +
|
||||||
|
"\fOptArgsEntry\x12\x10\n" +
|
||||||
|
"\x03key\x18\x01 \x01(\tR\x03key\x12#\n" +
|
||||||
|
"\x05value\x18\x02 \x01(\v2\r.CommandsArgsR\x05value:\x028\x01\x1aI\n" +
|
||||||
|
"\fReqArgsEntry\x12\x10\n" +
|
||||||
|
"\x03key\x18\x01 \x01(\tR\x03key\x12#\n" +
|
||||||
|
"\x05value\x18\x02 \x01(\v2\r.CommandsArgsR\x05value:\x028\x01\"\xa2\x01\n" +
|
||||||
|
"\fCommandsArgs\x12\x12\n" +
|
||||||
|
"\x04type\x18\x02 \x01(\tR\x04type\x12 \n" +
|
||||||
|
"\vdescription\x18\x03 \x01(\tR\vdescription\x12\x18\n" +
|
||||||
|
"\adefault\x18\x04 \x01(\tR\adefault\x12\x12\n" +
|
||||||
|
"\x04enum\x18\x05 \x03(\tR\x04enum\x12.\n" +
|
||||||
|
"\n" +
|
||||||
|
"validation\x18\x06 \x01(\v2\x0e.ArgValidationR\n" +
|
||||||
|
"validation\"\x86\x01\n" +
|
||||||
|
"\rArgValidation\x12\x1b\n" +
|
||||||
|
"\tmin_value\x18\x01 \x01(\x03R\bminValue\x12\x1b\n" +
|
||||||
|
"\tmax_value\x18\x02 \x01(\x03R\bmaxValue\x12\x18\n" +
|
||||||
|
"\apattern\x18\x03 \x01(\tR\apattern\x12!\n" +
|
||||||
|
"\fallowed_exts\x18\x04 \x03(\tR\vallowedExts\"n\n" +
|
||||||
|
"\x15RegisterAgentResponse\x12:\n" +
|
||||||
|
"\x19heartbeat_interval_second\x18\x01 \x01(\x03R\x17heartbeatIntervalSecond\x12\x19\n" +
|
||||||
|
"\bagent_id\x18\x02 \x01(\tR\aagentIdB<Z:github.com/lorsanstand/HomeOps-Hub/api/gen/homeops;homeopsb\x06proto3"
|
||||||
|
|
||||||
|
var (
|
||||||
|
file_homeops_register_proto_rawDescOnce sync.Once
|
||||||
|
file_homeops_register_proto_rawDescData []byte
|
||||||
|
)
|
||||||
|
|
||||||
|
func file_homeops_register_proto_rawDescGZIP() []byte {
|
||||||
|
file_homeops_register_proto_rawDescOnce.Do(func() {
|
||||||
|
file_homeops_register_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_homeops_register_proto_rawDesc), len(file_homeops_register_proto_rawDesc)))
|
||||||
|
})
|
||||||
|
return file_homeops_register_proto_rawDescData
|
||||||
|
}
|
||||||
|
|
||||||
|
var file_homeops_register_proto_msgTypes = make([]protoimpl.MessageInfo, 12)
|
||||||
|
var file_homeops_register_proto_goTypes = []any{
|
||||||
|
(*PongResponse)(nil), // 0: PongResponse
|
||||||
|
(*RegisterAgentRequest)(nil), // 1: RegisterAgentRequest
|
||||||
|
(*HostInfo)(nil), // 2: HostInfo
|
||||||
|
(*Capability)(nil), // 3: Capability
|
||||||
|
(*CapabilityCommand)(nil), // 4: CapabilityCommand
|
||||||
|
(*CommandsArgs)(nil), // 5: CommandsArgs
|
||||||
|
(*ArgValidation)(nil), // 6: ArgValidation
|
||||||
|
(*RegisterAgentResponse)(nil), // 7: RegisterAgentResponse
|
||||||
|
nil, // 8: RegisterAgentRequest.CapabilityEntry
|
||||||
|
nil, // 9: Capability.CommandEntry
|
||||||
|
nil, // 10: CapabilityCommand.OptArgsEntry
|
||||||
|
nil, // 11: CapabilityCommand.ReqArgsEntry
|
||||||
|
}
|
||||||
|
var file_homeops_register_proto_depIdxs = []int32{
|
||||||
|
2, // 0: RegisterAgentRequest.host:type_name -> HostInfo
|
||||||
|
8, // 1: RegisterAgentRequest.capability:type_name -> RegisterAgentRequest.CapabilityEntry
|
||||||
|
9, // 2: Capability.command:type_name -> Capability.CommandEntry
|
||||||
|
10, // 3: CapabilityCommand.opt_args:type_name -> CapabilityCommand.OptArgsEntry
|
||||||
|
11, // 4: CapabilityCommand.req_args:type_name -> CapabilityCommand.ReqArgsEntry
|
||||||
|
6, // 5: CommandsArgs.validation:type_name -> ArgValidation
|
||||||
|
3, // 6: RegisterAgentRequest.CapabilityEntry.value:type_name -> Capability
|
||||||
|
4, // 7: Capability.CommandEntry.value:type_name -> CapabilityCommand
|
||||||
|
5, // 8: CapabilityCommand.OptArgsEntry.value:type_name -> CommandsArgs
|
||||||
|
5, // 9: CapabilityCommand.ReqArgsEntry.value:type_name -> CommandsArgs
|
||||||
|
10, // [10:10] is the sub-list for method output_type
|
||||||
|
10, // [10:10] is the sub-list for method input_type
|
||||||
|
10, // [10:10] is the sub-list for extension type_name
|
||||||
|
10, // [10:10] is the sub-list for extension extendee
|
||||||
|
0, // [0:10] is the sub-list for field type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_homeops_register_proto_init() }
|
||||||
|
func file_homeops_register_proto_init() {
|
||||||
|
if File_homeops_register_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
File: protoimpl.DescBuilder{
|
||||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
|
RawDescriptor: unsafe.Slice(unsafe.StringData(file_homeops_register_proto_rawDesc), len(file_homeops_register_proto_rawDesc)),
|
||||||
|
NumEnums: 0,
|
||||||
|
NumMessages: 12,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 0,
|
||||||
|
},
|
||||||
|
GoTypes: file_homeops_register_proto_goTypes,
|
||||||
|
DependencyIndexes: file_homeops_register_proto_depIdxs,
|
||||||
|
MessageInfos: file_homeops_register_proto_msgTypes,
|
||||||
|
}.Build()
|
||||||
|
File_homeops_register_proto = out.File
|
||||||
|
file_homeops_register_proto_goTypes = nil
|
||||||
|
file_homeops_register_proto_depIdxs = nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,560 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go v1.36.11
|
||||||
|
// protoc v7.35.0
|
||||||
|
// source: homeops/stream.proto
|
||||||
|
|
||||||
|
package homeops
|
||||||
|
|
||||||
|
import (
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
reflect "reflect"
|
||||||
|
sync "sync"
|
||||||
|
unsafe "unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
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 ServerCommandRequest struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"`
|
||||||
|
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||||
|
Args map[string]string `protobuf:"bytes,3,rep,name=args,proto3" json:"args,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
|
||||||
|
TimeoutSeconds int64 `protobuf:"varint,4,opt,name=timeout_seconds,json=timeoutSeconds,proto3" json:"timeout_seconds,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ServerCommandRequest) Reset() {
|
||||||
|
*x = ServerCommandRequest{}
|
||||||
|
mi := &file_homeops_stream_proto_msgTypes[0]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ServerCommandRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ServerCommandRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ServerCommandRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_homeops_stream_proto_msgTypes[0]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ServerCommandRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*ServerCommandRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_homeops_stream_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ServerCommandRequest) GetRequestId() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.RequestId
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ServerCommandRequest) GetName() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Name
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ServerCommandRequest) GetArgs() map[string]string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Args
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ServerCommandRequest) GetTimeoutSeconds() int64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.TimeoutSeconds
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type AgentEvent struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
AgentId string `protobuf:"bytes,1,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"`
|
||||||
|
// Types that are valid to be assigned to Event:
|
||||||
|
//
|
||||||
|
// *AgentEvent_Heartbeat
|
||||||
|
// *AgentEvent_CommandResponse
|
||||||
|
// *AgentEvent_Alert
|
||||||
|
Event isAgentEvent_Event `protobuf_oneof:"event"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AgentEvent) Reset() {
|
||||||
|
*x = AgentEvent{}
|
||||||
|
mi := &file_homeops_stream_proto_msgTypes[1]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AgentEvent) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*AgentEvent) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *AgentEvent) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_homeops_stream_proto_msgTypes[1]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use AgentEvent.ProtoReflect.Descriptor instead.
|
||||||
|
func (*AgentEvent) Descriptor() ([]byte, []int) {
|
||||||
|
return file_homeops_stream_proto_rawDescGZIP(), []int{1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AgentEvent) GetAgentId() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.AgentId
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AgentEvent) GetEvent() isAgentEvent_Event {
|
||||||
|
if x != nil {
|
||||||
|
return x.Event
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AgentEvent) GetHeartbeat() *Heartbeat {
|
||||||
|
if x != nil {
|
||||||
|
if x, ok := x.Event.(*AgentEvent_Heartbeat); ok {
|
||||||
|
return x.Heartbeat
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AgentEvent) GetCommandResponse() *CommandResponse {
|
||||||
|
if x != nil {
|
||||||
|
if x, ok := x.Event.(*AgentEvent_CommandResponse); ok {
|
||||||
|
return x.CommandResponse
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *AgentEvent) GetAlert() *Alert {
|
||||||
|
if x != nil {
|
||||||
|
if x, ok := x.Event.(*AgentEvent_Alert); ok {
|
||||||
|
return x.Alert
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type isAgentEvent_Event interface {
|
||||||
|
isAgentEvent_Event()
|
||||||
|
}
|
||||||
|
|
||||||
|
type AgentEvent_Heartbeat struct {
|
||||||
|
Heartbeat *Heartbeat `protobuf:"bytes,2,opt,name=heartbeat,proto3,oneof"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AgentEvent_CommandResponse struct {
|
||||||
|
CommandResponse *CommandResponse `protobuf:"bytes,3,opt,name=command_response,json=commandResponse,proto3,oneof"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AgentEvent_Alert struct {
|
||||||
|
Alert *Alert `protobuf:"bytes,4,opt,name=alert,proto3,oneof"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*AgentEvent_Heartbeat) isAgentEvent_Event() {}
|
||||||
|
|
||||||
|
func (*AgentEvent_CommandResponse) isAgentEvent_Event() {}
|
||||||
|
|
||||||
|
func (*AgentEvent_Alert) isAgentEvent_Event() {}
|
||||||
|
|
||||||
|
type Heartbeat struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
|
||||||
|
Metrics *SystemMetrics `protobuf:"bytes,2,opt,name=metrics,proto3" json:"metrics,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Heartbeat) Reset() {
|
||||||
|
*x = Heartbeat{}
|
||||||
|
mi := &file_homeops_stream_proto_msgTypes[2]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Heartbeat) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Heartbeat) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *Heartbeat) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_homeops_stream_proto_msgTypes[2]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use Heartbeat.ProtoReflect.Descriptor instead.
|
||||||
|
func (*Heartbeat) Descriptor() ([]byte, []int) {
|
||||||
|
return file_homeops_stream_proto_rawDescGZIP(), []int{2}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Heartbeat) GetTimestamp() int64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Timestamp
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Heartbeat) GetMetrics() *SystemMetrics {
|
||||||
|
if x != nil {
|
||||||
|
return x.Metrics
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type SystemMetrics struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
CpuUsage float32 `protobuf:"fixed32,1,opt,name=cpu_usage,json=cpuUsage,proto3" json:"cpu_usage,omitempty"`
|
||||||
|
MemoryUsage float32 `protobuf:"fixed32,2,opt,name=memory_usage,json=memoryUsage,proto3" json:"memory_usage,omitempty"`
|
||||||
|
DiskUsage float32 `protobuf:"fixed32,3,opt,name=disk_usage,json=diskUsage,proto3" json:"disk_usage,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SystemMetrics) Reset() {
|
||||||
|
*x = SystemMetrics{}
|
||||||
|
mi := &file_homeops_stream_proto_msgTypes[3]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SystemMetrics) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*SystemMetrics) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *SystemMetrics) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_homeops_stream_proto_msgTypes[3]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use SystemMetrics.ProtoReflect.Descriptor instead.
|
||||||
|
func (*SystemMetrics) Descriptor() ([]byte, []int) {
|
||||||
|
return file_homeops_stream_proto_rawDescGZIP(), []int{3}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SystemMetrics) GetCpuUsage() float32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.CpuUsage
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SystemMetrics) GetMemoryUsage() float32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.MemoryUsage
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SystemMetrics) GetDiskUsage() float32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.DiskUsage
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type CommandResponse struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
RequestId string `protobuf:"bytes,1,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"`
|
||||||
|
Success bool `protobuf:"varint,2,opt,name=success,proto3" json:"success,omitempty"`
|
||||||
|
Output string `protobuf:"bytes,3,opt,name=output,proto3" json:"output,omitempty"`
|
||||||
|
Error string `protobuf:"bytes,4,opt,name=error,proto3" json:"error,omitempty"`
|
||||||
|
ExecTimeMs int64 `protobuf:"varint,5,opt,name=exec_time_ms,json=execTimeMs,proto3" json:"exec_time_ms,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CommandResponse) Reset() {
|
||||||
|
*x = CommandResponse{}
|
||||||
|
mi := &file_homeops_stream_proto_msgTypes[4]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CommandResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*CommandResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *CommandResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_homeops_stream_proto_msgTypes[4]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use CommandResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*CommandResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_homeops_stream_proto_rawDescGZIP(), []int{4}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CommandResponse) GetRequestId() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.RequestId
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CommandResponse) GetSuccess() bool {
|
||||||
|
if x != nil {
|
||||||
|
return x.Success
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CommandResponse) GetOutput() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Output
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CommandResponse) GetError() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Error
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *CommandResponse) GetExecTimeMs() int64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.ExecTimeMs
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type Alert struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
|
||||||
|
Level string `protobuf:"bytes,2,opt,name=level,proto3" json:"level,omitempty"`
|
||||||
|
Title string `protobuf:"bytes,3,opt,name=title,proto3" json:"title,omitempty"`
|
||||||
|
Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Alert) Reset() {
|
||||||
|
*x = Alert{}
|
||||||
|
mi := &file_homeops_stream_proto_msgTypes[5]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Alert) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Alert) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *Alert) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_homeops_stream_proto_msgTypes[5]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use Alert.ProtoReflect.Descriptor instead.
|
||||||
|
func (*Alert) Descriptor() ([]byte, []int) {
|
||||||
|
return file_homeops_stream_proto_rawDescGZIP(), []int{5}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Alert) GetTimestamp() int64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Timestamp
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Alert) GetLevel() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Level
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Alert) GetTitle() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Title
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Alert) GetDescription() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Description
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var File_homeops_stream_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
const file_homeops_stream_proto_rawDesc = "" +
|
||||||
|
"\n" +
|
||||||
|
"\x14homeops/stream.proto\"\xe0\x01\n" +
|
||||||
|
"\x14ServerCommandRequest\x12\x1d\n" +
|
||||||
|
"\n" +
|
||||||
|
"request_id\x18\x01 \x01(\tR\trequestId\x12\x12\n" +
|
||||||
|
"\x04name\x18\x02 \x01(\tR\x04name\x123\n" +
|
||||||
|
"\x04args\x18\x03 \x03(\v2\x1f.ServerCommandRequest.ArgsEntryR\x04args\x12'\n" +
|
||||||
|
"\x0ftimeout_seconds\x18\x04 \x01(\x03R\x0etimeoutSeconds\x1a7\n" +
|
||||||
|
"\tArgsEntry\x12\x10\n" +
|
||||||
|
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
|
||||||
|
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"\xbb\x01\n" +
|
||||||
|
"\n" +
|
||||||
|
"AgentEvent\x12\x19\n" +
|
||||||
|
"\bagent_id\x18\x01 \x01(\tR\aagentId\x12*\n" +
|
||||||
|
"\theartbeat\x18\x02 \x01(\v2\n" +
|
||||||
|
".HeartbeatH\x00R\theartbeat\x12=\n" +
|
||||||
|
"\x10command_response\x18\x03 \x01(\v2\x10.CommandResponseH\x00R\x0fcommandResponse\x12\x1e\n" +
|
||||||
|
"\x05alert\x18\x04 \x01(\v2\x06.AlertH\x00R\x05alertB\a\n" +
|
||||||
|
"\x05event\"S\n" +
|
||||||
|
"\tHeartbeat\x12\x1c\n" +
|
||||||
|
"\ttimestamp\x18\x01 \x01(\x03R\ttimestamp\x12(\n" +
|
||||||
|
"\ametrics\x18\x02 \x01(\v2\x0e.SystemMetricsR\ametrics\"n\n" +
|
||||||
|
"\rSystemMetrics\x12\x1b\n" +
|
||||||
|
"\tcpu_usage\x18\x01 \x01(\x02R\bcpuUsage\x12!\n" +
|
||||||
|
"\fmemory_usage\x18\x02 \x01(\x02R\vmemoryUsage\x12\x1d\n" +
|
||||||
|
"\n" +
|
||||||
|
"disk_usage\x18\x03 \x01(\x02R\tdiskUsage\"\x9a\x01\n" +
|
||||||
|
"\x0fCommandResponse\x12\x1d\n" +
|
||||||
|
"\n" +
|
||||||
|
"request_id\x18\x01 \x01(\tR\trequestId\x12\x18\n" +
|
||||||
|
"\asuccess\x18\x02 \x01(\bR\asuccess\x12\x16\n" +
|
||||||
|
"\x06output\x18\x03 \x01(\tR\x06output\x12\x14\n" +
|
||||||
|
"\x05error\x18\x04 \x01(\tR\x05error\x12 \n" +
|
||||||
|
"\fexec_time_ms\x18\x05 \x01(\x03R\n" +
|
||||||
|
"execTimeMs\"s\n" +
|
||||||
|
"\x05Alert\x12\x1c\n" +
|
||||||
|
"\ttimestamp\x18\x01 \x01(\x03R\ttimestamp\x12\x14\n" +
|
||||||
|
"\x05level\x18\x02 \x01(\tR\x05level\x12\x14\n" +
|
||||||
|
"\x05title\x18\x03 \x01(\tR\x05title\x12 \n" +
|
||||||
|
"\vdescription\x18\x04 \x01(\tR\vdescriptionB<Z:github.com/lorsanstand/HomeOps-Hub/api/gen/homeops;homeopsb\x06proto3"
|
||||||
|
|
||||||
|
var (
|
||||||
|
file_homeops_stream_proto_rawDescOnce sync.Once
|
||||||
|
file_homeops_stream_proto_rawDescData []byte
|
||||||
|
)
|
||||||
|
|
||||||
|
func file_homeops_stream_proto_rawDescGZIP() []byte {
|
||||||
|
file_homeops_stream_proto_rawDescOnce.Do(func() {
|
||||||
|
file_homeops_stream_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_homeops_stream_proto_rawDesc), len(file_homeops_stream_proto_rawDesc)))
|
||||||
|
})
|
||||||
|
return file_homeops_stream_proto_rawDescData
|
||||||
|
}
|
||||||
|
|
||||||
|
var file_homeops_stream_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
|
||||||
|
var file_homeops_stream_proto_goTypes = []any{
|
||||||
|
(*ServerCommandRequest)(nil), // 0: ServerCommandRequest
|
||||||
|
(*AgentEvent)(nil), // 1: AgentEvent
|
||||||
|
(*Heartbeat)(nil), // 2: Heartbeat
|
||||||
|
(*SystemMetrics)(nil), // 3: SystemMetrics
|
||||||
|
(*CommandResponse)(nil), // 4: CommandResponse
|
||||||
|
(*Alert)(nil), // 5: Alert
|
||||||
|
nil, // 6: ServerCommandRequest.ArgsEntry
|
||||||
|
}
|
||||||
|
var file_homeops_stream_proto_depIdxs = []int32{
|
||||||
|
6, // 0: ServerCommandRequest.args:type_name -> ServerCommandRequest.ArgsEntry
|
||||||
|
2, // 1: AgentEvent.heartbeat:type_name -> Heartbeat
|
||||||
|
4, // 2: AgentEvent.command_response:type_name -> CommandResponse
|
||||||
|
5, // 3: AgentEvent.alert:type_name -> Alert
|
||||||
|
3, // 4: Heartbeat.metrics:type_name -> SystemMetrics
|
||||||
|
5, // [5:5] is the sub-list for method output_type
|
||||||
|
5, // [5:5] is the sub-list for method input_type
|
||||||
|
5, // [5:5] is the sub-list for extension type_name
|
||||||
|
5, // [5:5] is the sub-list for extension extendee
|
||||||
|
0, // [0:5] is the sub-list for field type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_homeops_stream_proto_init() }
|
||||||
|
func file_homeops_stream_proto_init() {
|
||||||
|
if File_homeops_stream_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
file_homeops_stream_proto_msgTypes[1].OneofWrappers = []any{
|
||||||
|
(*AgentEvent_Heartbeat)(nil),
|
||||||
|
(*AgentEvent_CommandResponse)(nil),
|
||||||
|
(*AgentEvent_Alert)(nil),
|
||||||
|
}
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
File: protoimpl.DescBuilder{
|
||||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
|
RawDescriptor: unsafe.Slice(unsafe.StringData(file_homeops_stream_proto_rawDesc), len(file_homeops_stream_proto_rawDesc)),
|
||||||
|
NumEnums: 0,
|
||||||
|
NumMessages: 7,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 0,
|
||||||
|
},
|
||||||
|
GoTypes: file_homeops_stream_proto_goTypes,
|
||||||
|
DependencyIndexes: file_homeops_stream_proto_depIdxs,
|
||||||
|
MessageInfos: file_homeops_stream_proto_msgTypes,
|
||||||
|
}.Build()
|
||||||
|
File_homeops_stream_proto = out.File
|
||||||
|
file_homeops_stream_proto_goTypes = nil
|
||||||
|
file_homeops_stream_proto_depIdxs = nil
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
import "google/protobuf/empty.proto";
|
import "google/protobuf/empty.proto";
|
||||||
|
import "homeops/register.proto";
|
||||||
|
import "homeops/stream.proto";
|
||||||
|
|
||||||
option go_package = "github.com/lorsanstand/HomeOps-Hub/api/gen/homeops;homeops";
|
option go_package = "github.com/lorsanstand/HomeOps-Hub/api/gen/homeops;homeops";
|
||||||
|
|
||||||
@@ -9,76 +11,3 @@ service Hub {
|
|||||||
rpc RegisterAgent (RegisterAgentRequest) returns (RegisterAgentResponse) {}
|
rpc RegisterAgent (RegisterAgentRequest) returns (RegisterAgentResponse) {}
|
||||||
rpc StreamConnection (stream AgentEvent) returns (stream ServerCommandRequest) {}
|
rpc StreamConnection (stream AgentEvent) returns (stream ServerCommandRequest) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
message PongResponse {
|
|
||||||
string pong = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message RegisterAgentRequest {
|
|
||||||
string agent_id = 1;
|
|
||||||
string agent_name = 2;
|
|
||||||
string version = 3;
|
|
||||||
HostInfo host = 4;
|
|
||||||
repeated Capability capability = 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
message HostInfo {
|
|
||||||
string system = 1;
|
|
||||||
string hostname = 2;
|
|
||||||
string arch = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Capability {
|
|
||||||
bool available = 1;
|
|
||||||
string version = 2;
|
|
||||||
string name = 3;
|
|
||||||
string reason = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
message RegisterAgentResponse {
|
|
||||||
int64 heartbeat_interval_second = 1;
|
|
||||||
string agent_id = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message ServerCommandRequest {
|
|
||||||
string request_id = 1;
|
|
||||||
string name = 2;
|
|
||||||
map<string, string> args = 3;
|
|
||||||
int64 timeout_seconds = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
message AgentEvent {
|
|
||||||
string agent_id = 1;
|
|
||||||
|
|
||||||
oneof event {
|
|
||||||
Heartbeat heartbeat = 2;
|
|
||||||
CommandResponse command_response = 3;
|
|
||||||
Alert alert = 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
message Heartbeat {
|
|
||||||
int64 timestamp = 1;
|
|
||||||
SystemMetrics metrics = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message SystemMetrics {
|
|
||||||
float cpu_usage = 1;
|
|
||||||
float memory_usage = 2;
|
|
||||||
float disk_usage = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
message CommandResponse {
|
|
||||||
string request_id = 1;
|
|
||||||
bool success = 2;
|
|
||||||
string output = 3;
|
|
||||||
string error = 4;
|
|
||||||
int64 exec_time_ms = 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Alert {
|
|
||||||
int64 timestamp = 1;
|
|
||||||
string level = 2;
|
|
||||||
string title = 3;
|
|
||||||
string description = 4;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option go_package = "github.com/lorsanstand/HomeOps-Hub/api/gen/homeops;homeops";
|
||||||
|
|
||||||
|
message PongResponse {
|
||||||
|
string pong = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message RegisterAgentRequest {
|
||||||
|
string agent_id = 1;
|
||||||
|
string agent_name = 2;
|
||||||
|
string version = 3;
|
||||||
|
HostInfo host = 4;
|
||||||
|
map<string, Capability> capability = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
message HostInfo {
|
||||||
|
string system = 1;
|
||||||
|
string hostname = 2;
|
||||||
|
string arch = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Capability {
|
||||||
|
bool available = 1; // доступен ли
|
||||||
|
string version = 2; // версия раздела
|
||||||
|
// string name = 3; // название раздела по типу докер или управление пк
|
||||||
|
string reason = 4; // причина если раздел не доступент
|
||||||
|
map<string, CapabilityCommand> command = 5; // команды раздела
|
||||||
|
}
|
||||||
|
|
||||||
|
message CapabilityCommand {
|
||||||
|
// string name = 1; // название команды
|
||||||
|
map<string, CommandsArgs> opt_args = 2; // опциоанльные переменные
|
||||||
|
map<string, CommandsArgs> req_args = 3; // обязательные переменные
|
||||||
|
string version = 4; // версия команды
|
||||||
|
string description = 5; // описание команды для документации
|
||||||
|
string type_output = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CommandsArgs {
|
||||||
|
// string name = 1; // название аргумента
|
||||||
|
string type = 2; // какой тип path int string bool
|
||||||
|
string description = 3; // описание для документации
|
||||||
|
string default = 4; // значение по умолчанию
|
||||||
|
repeated string enum = 5; // enum комманд по типу run stop restart
|
||||||
|
ArgValidation validation = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
message ArgValidation {
|
||||||
|
int64 min_value = 1; // для чисел
|
||||||
|
int64 max_value = 2; // для чисел
|
||||||
|
string pattern = 3; // для regex строк
|
||||||
|
repeated string allowed_exts = 4; // для путей и файлов по типу .zip .rar итд
|
||||||
|
}
|
||||||
|
|
||||||
|
message RegisterAgentResponse {
|
||||||
|
int64 heartbeat_interval_second = 1;
|
||||||
|
string agent_id = 2;
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option go_package = "github.com/lorsanstand/HomeOps-Hub/api/gen/homeops;homeops";
|
||||||
|
|
||||||
|
message ServerCommandRequest {
|
||||||
|
string request_id = 1;
|
||||||
|
string name = 2;
|
||||||
|
map<string, string> args = 3;
|
||||||
|
int64 timeout_seconds = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
message AgentEvent {
|
||||||
|
string agent_id = 1;
|
||||||
|
|
||||||
|
oneof event {
|
||||||
|
Heartbeat heartbeat = 2;
|
||||||
|
CommandResponse command_response = 3;
|
||||||
|
Alert alert = 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message Heartbeat {
|
||||||
|
int64 timestamp = 1;
|
||||||
|
SystemMetrics metrics = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SystemMetrics {
|
||||||
|
float cpu_usage = 1;
|
||||||
|
float memory_usage = 2;
|
||||||
|
float disk_usage = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CommandResponse {
|
||||||
|
string request_id = 1;
|
||||||
|
bool success = 2;
|
||||||
|
string output = 3;
|
||||||
|
string error = 4;
|
||||||
|
int64 exec_time_ms = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Alert {
|
||||||
|
int64 timestamp = 1;
|
||||||
|
string level = 2;
|
||||||
|
string title = 3;
|
||||||
|
string description = 4;
|
||||||
|
}
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
services:
|
|
||||||
postgres-db:
|
|
||||||
image: postgres:latest
|
|
||||||
volumes:
|
|
||||||
- pgdata:/var/lib/postgresql
|
|
||||||
environment:
|
|
||||||
POSTGRES_DB: "${DB_NAME}"
|
|
||||||
POSTGRES_USER: "${DB_USER}"
|
|
||||||
POSTGRES_PASSWORD: "${DB_PASS}"
|
|
||||||
networks:
|
|
||||||
- homeops-dev
|
|
||||||
ports:
|
|
||||||
- "${DB_PORT}:5432"
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD-SHELL", "pg_isready -U ${DB_USER}"]
|
|
||||||
interval: 5s
|
|
||||||
retries: 5
|
|
||||||
restart: always
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
pgdata:
|
|
||||||
|
|
||||||
networks:
|
|
||||||
homeops-dev:
|
|
||||||
@@ -9,6 +9,7 @@ require (
|
|||||||
github.com/ilyakaznacheev/cleanenv v1.5.0
|
github.com/ilyakaznacheev/cleanenv v1.5.0
|
||||||
github.com/mattn/go-sqlite3 v1.14.44
|
github.com/mattn/go-sqlite3 v1.14.44
|
||||||
github.com/rs/zerolog v1.35.1
|
github.com/rs/zerolog v1.35.1
|
||||||
|
github.com/stretchr/testify v1.11.1
|
||||||
google.golang.org/grpc v1.81.0
|
google.golang.org/grpc v1.81.0
|
||||||
google.golang.org/protobuf v1.36.11
|
google.golang.org/protobuf v1.36.11
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
@@ -22,6 +23,7 @@ require (
|
|||||||
github.com/containerd/errdefs v1.0.0 // indirect
|
github.com/containerd/errdefs v1.0.0 // indirect
|
||||||
github.com/containerd/errdefs/pkg v0.3.0 // indirect
|
github.com/containerd/errdefs/pkg v0.3.0 // indirect
|
||||||
github.com/containerd/log v0.1.0 // indirect
|
github.com/containerd/log v0.1.0 // indirect
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
github.com/distribution/reference v0.6.0 // indirect
|
github.com/distribution/reference v0.6.0 // indirect
|
||||||
github.com/docker/go-connections v0.7.0 // indirect
|
github.com/docker/go-connections v0.7.0 // indirect
|
||||||
github.com/docker/go-units v0.5.0 // indirect
|
github.com/docker/go-units v0.5.0 // indirect
|
||||||
@@ -41,6 +43,7 @@ require (
|
|||||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
github.com/opencontainers/image-spec v1.1.1 // indirect
|
github.com/opencontainers/image-spec v1.1.1 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
|
||||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0 // indirect
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.68.0 // indirect
|
||||||
|
|||||||
+25
-14
@@ -5,12 +5,15 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
standartlog "log"
|
standartlog "log"
|
||||||
"net"
|
"net"
|
||||||
|
"os"
|
||||||
|
|
||||||
hubdir "github.com/lorsanstand/HomeOps-Hub/hub/internal"
|
hubdir "github.com/lorsanstand/HomeOps-Hub/hub/internal"
|
||||||
"github.com/lorsanstand/HomeOps-Hub/hub/internal/migrator"
|
"github.com/lorsanstand/HomeOps-Hub/hub/internal/migrator"
|
||||||
grpcserv "github.com/lorsanstand/HomeOps-Hub/hub/internal/rpc"
|
grpcserv "github.com/lorsanstand/HomeOps-Hub/hub/internal/rpc"
|
||||||
|
"github.com/lorsanstand/HomeOps-Hub/hub/internal/service/connection_manager"
|
||||||
"github.com/lorsanstand/HomeOps-Hub/hub/internal/service/hub_service"
|
"github.com/lorsanstand/HomeOps-Hub/hub/internal/service/hub_service"
|
||||||
"github.com/lorsanstand/HomeOps-Hub/hub/internal/store"
|
"github.com/lorsanstand/HomeOps-Hub/hub/internal/store"
|
||||||
|
"github.com/lorsanstand/HomeOps-Hub/hub/internal/utils/notifier"
|
||||||
"github.com/lorsanstand/HomeOps-Hub/shared/config"
|
"github.com/lorsanstand/HomeOps-Hub/shared/config"
|
||||||
"github.com/lorsanstand/HomeOps-Hub/shared/log"
|
"github.com/lorsanstand/HomeOps-Hub/shared/log"
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
@@ -39,7 +42,7 @@ func (a *App) Run() {
|
|||||||
DBConn, err := sql.Open("sqlite", "database.db")
|
DBConn, err := sql.Open("sqlite", "database.db")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.log.Error().Err(err).Msg("failed to connect to the database")
|
a.log.Error().Err(err).Msg("failed to connect to the database")
|
||||||
return
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -48,34 +51,31 @@ func (a *App) Run() {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
mgrt, err := migrator.NewMigrator(hubdir.MigrationsFS, "migrations")
|
|
||||||
if err != nil {
|
|
||||||
a.log.Error().Err(err).Msg("failed to create migrator")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
a.log.Info().Msg("applying database migrations")
|
a.log.Info().Msg("applying database migrations")
|
||||||
if err = mgrt.ApplyMigrations(DBConn); err != nil {
|
if err := applyMigrations(DBConn); err != nil {
|
||||||
a.log.Error().Err(err).Msg("migrations failed to apply")
|
a.log.Error().Err(err).Msg("")
|
||||||
return
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
a.log.Info().Msg("migrations applied successfully")
|
a.log.Info().Msg("migrations applied successfully")
|
||||||
|
|
||||||
hubStore := store.NewHubStore(DBConn)
|
hubStore := store.NewHubStore(DBConn)
|
||||||
hubService := hub_service.NewHubService(hubStore, a.log)
|
hubService := hub_service.NewHubService(hubStore, a.cfg.Heartbeat, a.log)
|
||||||
|
statusNotifier := notifier.NewStatusNotifier()
|
||||||
|
connManger := connection_manager.NewConnectionManager(hubStore, statusNotifier, a.cfg.Heartbeat*1000, a.log)
|
||||||
|
|
||||||
a.log.Info().Msg("starting hub service")
|
a.log.Info().Msg("starting hub service")
|
||||||
err = a.hubServe(hubService)
|
|
||||||
|
err = a.hubServe(hubService, connManger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.log.Error().Err(err).Msg("hub service failed to start")
|
a.log.Error().Err(err).Msg("hub service failed to start")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) hubServe(hubService *hub_service.HubService) error {
|
func (a *App) hubServe(hubService *hub_service.HubService, manager *connection_manager.ConnectionManager) error {
|
||||||
address := fmt.Sprintf("0.0.0.0:%v", a.cfg.Port)
|
address := fmt.Sprintf("0.0.0.0:%v", a.cfg.Port)
|
||||||
|
|
||||||
server := grpcserv.NewHubHandler(hubService, a.log)
|
server := grpcserv.NewHubHandler(hubService, manager, a.log)
|
||||||
|
|
||||||
lis, err := net.Listen("tcp", address)
|
lis, err := net.Listen("tcp", address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -93,3 +93,14 @@ func (a *App) hubServe(hubService *hub_service.HubService) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func applyMigrations(db *sql.DB) error {
|
||||||
|
mgrt, err := migrator.NewMigrator(hubdir.MigrationsFS, "migrations")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create migrator: %w", err)
|
||||||
|
}
|
||||||
|
if err = mgrt.ApplyMigrations(db); err != nil {
|
||||||
|
return fmt.Errorf("migrations failed to apply: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
CREATE TABLE heartbeats (
|
CREATE TABLE heartbeats (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
agent_id VARCHAR(32) UNIQUE NOT NULL,
|
agent_id VARCHAR(32) NOT NULL,
|
||||||
cpu_usage FLOAT NOT NULL ,
|
cpu_usage FLOAT NOT NULL ,
|
||||||
memory_usage FLOAT NOT NULL ,
|
memory_usage FLOAT NOT NULL ,
|
||||||
disk_usage FLOAT NOT NULL ,
|
disk_usage FLOAT NOT NULL ,
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package rpc
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
var ErrFailedRegister = fmt.Errorf("failed register agent")
|
||||||
+31
-11
@@ -2,9 +2,12 @@ package rpc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
pb "github.com/lorsanstand/HomeOps-Hub/api/gen/homeops"
|
pb "github.com/lorsanstand/HomeOps-Hub/api/gen/homeops"
|
||||||
|
"github.com/lorsanstand/HomeOps-Hub/hub/internal/service/connection_manager"
|
||||||
"github.com/lorsanstand/HomeOps-Hub/shared/domain"
|
"github.com/lorsanstand/HomeOps-Hub/shared/domain"
|
||||||
|
"github.com/lorsanstand/HomeOps-Hub/shared/mappers/rpc"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/protobuf/types/known/emptypb"
|
"google.golang.org/protobuf/types/known/emptypb"
|
||||||
@@ -14,15 +17,20 @@ type HubService interface {
|
|||||||
RegisterAgent(ctx context.Context, data domain.RegisterAgentRequest) (domain.RegisterAgentResponse, error)
|
RegisterAgent(ctx context.Context, data domain.RegisterAgentRequest) (domain.RegisterAgentResponse, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type HubHandler struct {
|
type ConnectionManager interface {
|
||||||
pb.UnimplementedHubServer
|
NewConnection(stream connection_manager.StreamConn) error
|
||||||
log zerolog.Logger
|
|
||||||
GrpcServer *grpc.Server
|
|
||||||
hub HubService
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHubHandler(HubServ HubService, logger zerolog.Logger) *HubHandler {
|
type HubHandler struct {
|
||||||
hub := &HubHandler{log: logger, hub: HubServ}
|
pb.UnimplementedHubServer
|
||||||
|
log zerolog.Logger
|
||||||
|
GrpcServer *grpc.Server
|
||||||
|
hub HubService
|
||||||
|
streamManager ConnectionManager
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHubHandler(HubServ HubService, manager ConnectionManager, logger zerolog.Logger) *HubHandler {
|
||||||
|
hub := &HubHandler{log: logger, hub: HubServ, streamManager: manager}
|
||||||
|
|
||||||
grpcServer := grpc.NewServer()
|
grpcServer := grpc.NewServer()
|
||||||
pb.RegisterHubServer(grpcServer, hub)
|
pb.RegisterHubServer(grpcServer, hub)
|
||||||
@@ -39,12 +47,24 @@ func (h *HubHandler) Ping(ctx context.Context, _ *emptypb.Empty) (*pb.PongRespon
|
|||||||
|
|
||||||
func (h *HubHandler) RegisterAgent(ctx context.Context, request *pb.RegisterAgentRequest) (*pb.RegisterAgentResponse, error) {
|
func (h *HubHandler) RegisterAgent(ctx context.Context, request *pb.RegisterAgentRequest) (*pb.RegisterAgentResponse, error) {
|
||||||
h.log.Debug().Str("agentID", request.AgentId).Str("agentName", request.AgentName).Msg("register agent request received")
|
h.log.Debug().Str("agentID", request.AgentId).Str("agentName", request.AgentName).Msg("register agent request received")
|
||||||
data := domain.ToDomainAgentRequest(request)
|
data, err := rpc.ToDomainAgentRequest(request)
|
||||||
|
if err != nil {
|
||||||
|
h.log.Error().Err(err).Msg("failed to casting request")
|
||||||
|
return &pb.RegisterAgentResponse{}, ErrFailedRegister
|
||||||
|
}
|
||||||
resp, err := h.hub.RegisterAgent(ctx, data)
|
resp, err := h.hub.RegisterAgent(ctx, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.log.Error().Err(err).Str("agentID", request.AgentId).Msg("register agent request failed")
|
h.log.Error().Err(err).Msg("failed register agent")
|
||||||
return domain.ToGRPCAgentResponse(resp), err
|
return rpc.ToGRPCAgentResponse(resp), ErrFailedRegister
|
||||||
}
|
}
|
||||||
h.log.Info().Str("agentID", resp.AgentID).Msg("register agent request completed")
|
h.log.Info().Str("agentID", resp.AgentID).Msg("register agent request completed")
|
||||||
return domain.ToGRPCAgentResponse(resp), nil
|
return rpc.ToGRPCAgentResponse(resp), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HubHandler) StreamConnection(stream grpc.BidiStreamingServer[pb.AgentEvent, pb.ServerCommandRequest]) error {
|
||||||
|
err := h.streamManager.NewConnection(stream)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("accept connection: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,15 +8,15 @@ import (
|
|||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
pb "github.com/lorsanstand/HomeOps-Hub/api/gen/homeops"
|
pb "github.com/lorsanstand/HomeOps-Hub/api/gen/homeops"
|
||||||
domainHub "github.com/lorsanstand/HomeOps-Hub/hub/internal/domain"
|
domainHub "github.com/lorsanstand/HomeOps-Hub/shared/domain"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AgentConnection struct {
|
type AgentConnection struct {
|
||||||
stream streamConn
|
stream StreamConn
|
||||||
heartbeat heartbeatStore
|
heartbeat heartbeatStore
|
||||||
log zerolog.Logger
|
log zerolog.Logger
|
||||||
status statusAgent
|
status StatusAgent
|
||||||
AgentID string
|
AgentID string
|
||||||
response *ResponseStore
|
response *ResponseStore
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
@@ -24,7 +24,7 @@ type AgentConnection struct {
|
|||||||
heartbeatTimeoutMS int
|
heartbeatTimeoutMS int
|
||||||
}
|
}
|
||||||
|
|
||||||
func newAgentConnection(agentID string, stream streamConn, heartbeat heartbeatStore, status statusAgent, heartbeatTimeoutMS int, logger zerolog.Logger) *AgentConnection {
|
func newAgentConnection(agentID string, stream StreamConn, heartbeat heartbeatStore, status StatusAgent, heartbeatTimeoutMS int, logger zerolog.Logger) *AgentConnection {
|
||||||
response := NewResponseStore()
|
response := NewResponseStore()
|
||||||
logger = logger.With().Str("agentID", agentID).Logger()
|
logger = logger.With().Str("agentID", agentID).Logger()
|
||||||
ctx, cancel := context.WithCancel(stream.Context())
|
ctx, cancel := context.WithCancel(stream.Context())
|
||||||
@@ -32,36 +32,31 @@ func newAgentConnection(agentID string, stream streamConn, heartbeat heartbeatSt
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *AgentConnection) Listen() error {
|
func (a *AgentConnection) Listen() error {
|
||||||
defer a.status.Offline()
|
heartbeatsCh := make(chan domainHub.CreateHeartbeatModel, 5)
|
||||||
|
streamRecvCh := make(chan *pb.AgentEvent, 5)
|
||||||
|
|
||||||
heartbeatsChan := make(chan domainHub.CreateHeartbeatModel, 5)
|
go a.listenHeartbeat(heartbeatsCh)
|
||||||
go a.listenHeartbeat(heartbeatsChan)
|
go a.listenStream(streamRecvCh)
|
||||||
defer close(heartbeatsChan)
|
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
err := a.Close()
|
a.status.Offline()
|
||||||
if err != nil {
|
close(heartbeatsCh)
|
||||||
a.log.Warn().Err(err).Msg("failed stream close")
|
a.Close()
|
||||||
}
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-a.ctx.Done():
|
case <-a.ctx.Done():
|
||||||
return a.ctx.Err()
|
return a.ctx.Err()
|
||||||
default:
|
case msg, ok := <-streamRecvCh:
|
||||||
agentEvent, err := a.stream.Recv()
|
if !ok {
|
||||||
if err == io.EOF {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("stream: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch x := agentEvent.Event.(type) {
|
switch x := msg.Event.(type) {
|
||||||
case *pb.AgentEvent_Heartbeat:
|
case *pb.AgentEvent_Heartbeat:
|
||||||
heartbeat := toCreateHeartbeatModel(a.AgentID, x)
|
heartbeat := toCreateHeartbeatModel(a.AgentID, x)
|
||||||
heartbeatsChan <- heartbeat
|
heartbeatsCh <- heartbeat
|
||||||
case *pb.AgentEvent_CommandResponse:
|
case *pb.AgentEvent_CommandResponse:
|
||||||
ch, ok := a.response.Read(x.CommandResponse.RequestId)
|
ch, ok := a.response.Read(x.CommandResponse.RequestId)
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -75,6 +70,22 @@ func (a *AgentConnection) Listen() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *AgentConnection) listenStream(ch chan *pb.AgentEvent) {
|
||||||
|
defer close(ch)
|
||||||
|
for {
|
||||||
|
agentEvent, err := a.stream.Recv()
|
||||||
|
if err == io.EOF {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
a.log.Warn().Err(err).Msg("close stream")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ch <- agentEvent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (a *AgentConnection) listenHeartbeat(heartbeats <-chan domainHub.CreateHeartbeatModel) {
|
func (a *AgentConnection) listenHeartbeat(heartbeats <-chan domainHub.CreateHeartbeatModel) {
|
||||||
lastHeartbeat := 0
|
lastHeartbeat := 0
|
||||||
timer := time.NewTicker(time.Duration(a.heartbeatTimeoutMS) * time.Millisecond)
|
timer := time.NewTicker(time.Duration(a.heartbeatTimeoutMS) * time.Millisecond)
|
||||||
@@ -92,9 +103,12 @@ func (a *AgentConnection) listenHeartbeat(heartbeats <-chan domainHub.CreateHear
|
|||||||
a.log.Warn().Msg("agent not send heartbeat")
|
a.log.Warn().Msg("agent not send heartbeat")
|
||||||
a.Close()
|
a.Close()
|
||||||
return
|
return
|
||||||
case heartbeat := <-heartbeats:
|
case heartbeat, ok := <-heartbeats:
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
a.log.Debug().
|
a.log.Debug().
|
||||||
Float64("cpu usage", heartbeat.Metrics.CpuUsage).
|
Float64("cpu usage", heartbeat.Metrics.CPUUsage).
|
||||||
Float64("disk usage", heartbeat.Metrics.DiskUsage).
|
Float64("disk usage", heartbeat.Metrics.DiskUsage).
|
||||||
Float64("memory usage", heartbeat.Metrics.MemoryUsage).Msg("")
|
Float64("memory usage", heartbeat.Metrics.MemoryUsage).Msg("")
|
||||||
|
|
||||||
@@ -137,7 +151,6 @@ func (a *AgentConnection) Execute(ctx context.Context, request domainHub.AgentRe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AgentConnection) Close() error {
|
func (a *AgentConnection) Close() {
|
||||||
a.cancel()
|
a.cancel()
|
||||||
return a.stream.Close()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,119 +3,16 @@ package connection_manager
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
pb "github.com/lorsanstand/HomeOps-Hub/api/gen/homeops"
|
pb "github.com/lorsanstand/HomeOps-Hub/api/gen/homeops"
|
||||||
domainHub "github.com/lorsanstand/HomeOps-Hub/hub/internal/domain"
|
domainHub "github.com/lorsanstand/HomeOps-Hub/shared/domain"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
type streamMock struct {
|
|
||||||
recvCh chan *pb.AgentEvent
|
|
||||||
sendCh chan *pb.ServerCommandRequest
|
|
||||||
closeCh chan struct{}
|
|
||||||
ctx context.Context
|
|
||||||
mu sync.Mutex
|
|
||||||
sendErr error
|
|
||||||
recvErr error
|
|
||||||
closeOnce sync.Once
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *streamMock) Context() context.Context {
|
|
||||||
return f.ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *streamMock) Send(request *pb.ServerCommandRequest) error {
|
|
||||||
f.mu.Lock()
|
|
||||||
err := f.sendErr
|
|
||||||
f.mu.Unlock()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
f.sendCh <- request
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *streamMock) Recv() (*pb.AgentEvent, error) {
|
|
||||||
f.mu.Lock()
|
|
||||||
recvErr := f.recvErr
|
|
||||||
f.mu.Unlock()
|
|
||||||
if recvErr != nil {
|
|
||||||
return nil, recvErr
|
|
||||||
}
|
|
||||||
select {
|
|
||||||
case msg, ok := <-f.recvCh:
|
|
||||||
if !ok {
|
|
||||||
return nil, io.EOF
|
|
||||||
}
|
|
||||||
return msg, nil
|
|
||||||
case <-f.ctx.Done():
|
|
||||||
return nil, f.ctx.Err()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *streamMock) Close() error {
|
|
||||||
select {
|
|
||||||
case f.closeCh <- struct{}{}:
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
f.closeOnce.Do(func() {
|
|
||||||
close(f.recvCh)
|
|
||||||
})
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type heartBeatMock struct {
|
|
||||||
mu sync.Mutex
|
|
||||||
countUse int
|
|
||||||
doneCh chan struct{}
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *heartBeatMock) CreateHeartbeat(ctx context.Context, heartbeat domainHub.CreateHeartbeatModel) error {
|
|
||||||
h.mu.Lock()
|
|
||||||
h.countUse += 1
|
|
||||||
err := h.err
|
|
||||||
h.mu.Unlock()
|
|
||||||
select {
|
|
||||||
case h.doneCh <- struct{}{}:
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
type statusMock struct {
|
|
||||||
mu sync.Mutex
|
|
||||||
online bool
|
|
||||||
doneCh chan struct{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *statusMock) Offline() {
|
|
||||||
s.mu.Lock()
|
|
||||||
s.online = false
|
|
||||||
s.mu.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *statusMock) Online() {
|
|
||||||
s.mu.Lock()
|
|
||||||
s.online = true
|
|
||||||
s.mu.Unlock()
|
|
||||||
select {
|
|
||||||
case s.doneCh <- struct{}{}:
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *statusMock) IsOnline() bool {
|
|
||||||
s.mu.Lock()
|
|
||||||
defer s.mu.Unlock()
|
|
||||||
return s.online
|
|
||||||
}
|
|
||||||
|
|
||||||
type agentTestHarness struct {
|
type agentTestHarness struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
@@ -133,7 +30,7 @@ func newAgentTestHarness(t *testing.T, heartbeatTimeoutMS int) *agentTestHarness
|
|||||||
recvStream := make(chan *pb.AgentEvent, 4)
|
recvStream := make(chan *pb.AgentEvent, 4)
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
stream := &streamMock{recvCh: recvStream, sendCh: sendStream, ctx: ctx, closeCh: make(chan struct{}, 1)}
|
stream := &streamMock{recvCh: recvStream, sendCh: sendStream, ctx: ctx}
|
||||||
heartbeat := &heartBeatMock{doneCh: make(chan struct{}, 2)}
|
heartbeat := &heartBeatMock{doneCh: make(chan struct{}, 2)}
|
||||||
status := &statusMock{doneCh: make(chan struct{}, 2)}
|
status := &statusMock{doneCh: make(chan struct{}, 2)}
|
||||||
|
|
||||||
@@ -158,15 +55,6 @@ func waitFor(t *testing.T, ch <-chan struct{}, timeout time.Duration, message st
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func waitForClose(t *testing.T, closeCh <-chan struct{}, timeout time.Duration) {
|
|
||||||
t.Helper()
|
|
||||||
select {
|
|
||||||
case <-closeCh:
|
|
||||||
case <-time.After(timeout):
|
|
||||||
t.Fatal("timeout waiting for close")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func commandResponseEvent(requestID, output string) *pb.AgentEvent {
|
func commandResponseEvent(requestID, output string) *pb.AgentEvent {
|
||||||
return &pb.AgentEvent{
|
return &pb.AgentEvent{
|
||||||
AgentId: "agent-1",
|
AgentId: "agent-1",
|
||||||
@@ -182,7 +70,11 @@ func commandResponseEvent(requestID, output string) *pb.AgentEvent {
|
|||||||
|
|
||||||
func TestAgentConnection_Heartbeat(t *testing.T) {
|
func TestAgentConnection_Heartbeat(t *testing.T) {
|
||||||
h := newAgentTestHarness(t, 5000)
|
h := newAgentTestHarness(t, 5000)
|
||||||
go h.agent.Listen()
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
_ = h.agent.Listen()
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
h.recvCh <- &pb.AgentEvent{AgentId: "agent-1", Event: &pb.AgentEvent_Heartbeat{
|
h.recvCh <- &pb.AgentEvent{AgentId: "agent-1", Event: &pb.AgentEvent_Heartbeat{
|
||||||
Heartbeat: &pb.Heartbeat{
|
Heartbeat: &pb.Heartbeat{
|
||||||
@@ -201,13 +93,15 @@ func TestAgentConnection_Heartbeat(t *testing.T) {
|
|||||||
assert.Equal(t, h.status.IsOnline(), true)
|
assert.Equal(t, h.status.IsOnline(), true)
|
||||||
|
|
||||||
h.cancel()
|
h.cancel()
|
||||||
waitForClose(t, h.stream.closeCh, 500*time.Millisecond)
|
waitFor(t, done, 500*time.Millisecond, "timeout waiting for listen stop")
|
||||||
assert.Equal(t, h.status.IsOnline(), false)
|
assert.Equal(t, h.status.IsOnline(), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAgentConnection_Execute(t *testing.T) {
|
func TestAgentConnection_Execute(t *testing.T) {
|
||||||
h := newAgentTestHarness(t, 5000)
|
h := newAgentTestHarness(t, 5000)
|
||||||
go h.agent.Listen()
|
go func() {
|
||||||
|
_ = h.agent.Listen()
|
||||||
|
}()
|
||||||
|
|
||||||
// Данные для проверки
|
// Данные для проверки
|
||||||
requestID := make(chan domainHub.AgentResponse)
|
requestID := make(chan domainHub.AgentResponse)
|
||||||
@@ -245,13 +139,11 @@ func TestAgentConnection_Execute(t *testing.T) {
|
|||||||
|
|
||||||
func TestAgentConnection_HeartbeatTimeout(t *testing.T) {
|
func TestAgentConnection_HeartbeatTimeout(t *testing.T) {
|
||||||
h := newAgentTestHarness(t, 200)
|
h := newAgentTestHarness(t, 200)
|
||||||
var wg sync.WaitGroup
|
listenDone := make(chan error, 1)
|
||||||
|
execDone := make(chan error, 1)
|
||||||
|
|
||||||
wg.Add(2)
|
|
||||||
go func() {
|
go func() {
|
||||||
err := h.agent.Listen()
|
listenDone <- h.agent.Listen()
|
||||||
assert.NilError(t, err)
|
|
||||||
wg.Done()
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
@@ -260,13 +152,25 @@ func TestAgentConnection_HeartbeatTimeout(t *testing.T) {
|
|||||||
Args: nil,
|
Args: nil,
|
||||||
TimeOut: 0,
|
TimeOut: 0,
|
||||||
})
|
})
|
||||||
assert.ErrorIs(t, err, ErrConnectionClose)
|
execDone <- err
|
||||||
wg.Done()
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
wg.Wait()
|
timeout := time.After(2 * time.Second)
|
||||||
|
gotListen := false
|
||||||
waitForClose(t, h.stream.closeCh, 500*time.Millisecond)
|
gotExec := false
|
||||||
|
for !gotListen && !gotExec {
|
||||||
|
select {
|
||||||
|
case err := <-listenDone:
|
||||||
|
assert.ErrorIs(t, err, context.Canceled)
|
||||||
|
gotListen = true
|
||||||
|
case err := <-execDone:
|
||||||
|
assert.ErrorIs(t, err, ErrConnectionClose)
|
||||||
|
gotExec = true
|
||||||
|
case <-timeout:
|
||||||
|
h.cancel()
|
||||||
|
t.Fatal("timeout waiting for heartbeat timeout")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAgentConnection_ConnectionClose(t *testing.T) {
|
func TestAgentConnection_ConnectionClose(t *testing.T) {
|
||||||
@@ -293,8 +197,6 @@ func TestAgentConnection_ConnectionClose(t *testing.T) {
|
|||||||
h.cancel()
|
h.cancel()
|
||||||
|
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
||||||
waitForClose(t, h.stream.closeCh, 500*time.Millisecond)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAgentConnection_ExecuteClose(t *testing.T) {
|
func TestAgentConnection_ExecuteClose(t *testing.T) {
|
||||||
@@ -303,7 +205,9 @@ func TestAgentConnection_ExecuteClose(t *testing.T) {
|
|||||||
t.Cleanup(cancelExecute)
|
t.Cleanup(cancelExecute)
|
||||||
|
|
||||||
executeCh := make(chan struct{})
|
executeCh := make(chan struct{})
|
||||||
go h.agent.Listen()
|
go func() {
|
||||||
|
_ = h.agent.Listen()
|
||||||
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
_, err := h.agent.Execute(ctxExecute, domainHub.AgentRequest{
|
_, err := h.agent.Execute(ctxExecute, domainHub.AgentRequest{
|
||||||
@@ -322,23 +226,10 @@ func TestAgentConnection_ExecuteClose(t *testing.T) {
|
|||||||
|
|
||||||
func TestAgentConnection_ListenEOF(t *testing.T) {
|
func TestAgentConnection_ListenEOF(t *testing.T) {
|
||||||
h := newAgentTestHarness(t, 5000)
|
h := newAgentTestHarness(t, 5000)
|
||||||
h.stream.Close()
|
h.stream.CloseRecv()
|
||||||
|
|
||||||
err := h.agent.Listen()
|
err := h.agent.Listen()
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
waitForClose(t, h.stream.closeCh, 500*time.Millisecond)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAgentConnection_ListenRecvError(t *testing.T) {
|
|
||||||
h := newAgentTestHarness(t, 5000)
|
|
||||||
|
|
||||||
recvErr := errors.New("recv failure")
|
|
||||||
h.stream.mu.Lock()
|
|
||||||
h.stream.recvErr = recvErr
|
|
||||||
h.stream.mu.Unlock()
|
|
||||||
|
|
||||||
err := h.agent.Listen()
|
|
||||||
assert.ErrorIs(t, err, recvErr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAgentConnection_ExecuteSendError(t *testing.T) {
|
func TestAgentConnection_ExecuteSendError(t *testing.T) {
|
||||||
@@ -370,7 +261,11 @@ func TestAgentConnection_ExecuteConnectionCanceled(t *testing.T) {
|
|||||||
|
|
||||||
func TestAgentConnection_UnknownResponseID(t *testing.T) {
|
func TestAgentConnection_UnknownResponseID(t *testing.T) {
|
||||||
h := newAgentTestHarness(t, 5000)
|
h := newAgentTestHarness(t, 5000)
|
||||||
go h.agent.Listen()
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
_ = h.agent.Listen()
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
h.recvCh <- &pb.AgentEvent{AgentId: "agent-1", Event: &pb.AgentEvent_CommandResponse{
|
h.recvCh <- &pb.AgentEvent{AgentId: "agent-1", Event: &pb.AgentEvent_CommandResponse{
|
||||||
CommandResponse: &pb.CommandResponse{
|
CommandResponse: &pb.CommandResponse{
|
||||||
@@ -380,7 +275,7 @@ func TestAgentConnection_UnknownResponseID(t *testing.T) {
|
|||||||
}}}
|
}}}
|
||||||
|
|
||||||
h.cancel()
|
h.cancel()
|
||||||
waitForClose(t, h.stream.closeCh, 500*time.Millisecond)
|
waitFor(t, done, 500*time.Millisecond, "timeout waiting for listen stop")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAgentConnection_HeartbeatErrorDoesNotStop(t *testing.T) {
|
func TestAgentConnection_HeartbeatErrorDoesNotStop(t *testing.T) {
|
||||||
@@ -389,7 +284,9 @@ func TestAgentConnection_HeartbeatErrorDoesNotStop(t *testing.T) {
|
|||||||
h.heartbeat.err = errors.New("db error")
|
h.heartbeat.err = errors.New("db error")
|
||||||
h.heartbeat.mu.Unlock()
|
h.heartbeat.mu.Unlock()
|
||||||
|
|
||||||
go h.agent.Listen()
|
go func() {
|
||||||
|
_ = h.agent.Listen()
|
||||||
|
}()
|
||||||
h.recvCh <- &pb.AgentEvent{AgentId: "agent-1", Event: &pb.AgentEvent_Heartbeat{
|
h.recvCh <- &pb.AgentEvent{AgentId: "agent-1", Event: &pb.AgentEvent_Heartbeat{
|
||||||
Heartbeat: &pb.Heartbeat{
|
Heartbeat: &pb.Heartbeat{
|
||||||
Timestamp: time.Now().Unix(),
|
Timestamp: time.Now().Unix(),
|
||||||
@@ -402,7 +299,9 @@ func TestAgentConnection_HeartbeatErrorDoesNotStop(t *testing.T) {
|
|||||||
|
|
||||||
func TestAgentConnection_ConcurrentExecute(t *testing.T) {
|
func TestAgentConnection_ConcurrentExecute(t *testing.T) {
|
||||||
h := newAgentTestHarness(t, 5000)
|
h := newAgentTestHarness(t, 5000)
|
||||||
go h.agent.Listen()
|
go func() {
|
||||||
|
_ = h.agent.Listen()
|
||||||
|
}()
|
||||||
|
|
||||||
responses := make(chan domainHub.AgentResponse, 2)
|
responses := make(chan domainHub.AgentResponse, 2)
|
||||||
|
|
||||||
|
|||||||
@@ -4,25 +4,24 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
pb "github.com/lorsanstand/HomeOps-Hub/api/gen/homeops"
|
pb "github.com/lorsanstand/HomeOps-Hub/api/gen/homeops"
|
||||||
domainHub "github.com/lorsanstand/HomeOps-Hub/hub/internal/domain"
|
domainHub "github.com/lorsanstand/HomeOps-Hub/shared/domain"
|
||||||
)
|
)
|
||||||
|
|
||||||
type streamConn interface {
|
type StreamConn interface {
|
||||||
Send(request *pb.ServerCommandRequest) error
|
Send(request *pb.ServerCommandRequest) error
|
||||||
Recv() (*pb.AgentEvent, error)
|
Recv() (*pb.AgentEvent, error)
|
||||||
Context() context.Context
|
Context() context.Context
|
||||||
Close() error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type heartbeatStore interface {
|
type heartbeatStore interface {
|
||||||
CreateHeartbeat(ctx context.Context, heartbeat domainHub.CreateHeartbeatModel) error
|
CreateHeartbeat(ctx context.Context, heartbeat domainHub.CreateHeartbeatModel) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type statusAgent interface {
|
type StatusAgent interface {
|
||||||
Offline()
|
Offline()
|
||||||
Online()
|
Online()
|
||||||
}
|
}
|
||||||
|
|
||||||
type statusNotifier interface {
|
type statusNotifier interface {
|
||||||
New(AgentID string) statusAgent
|
New(agentID string) StatusAgent
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,39 +8,36 @@ import (
|
|||||||
"google.golang.org/grpc/metadata"
|
"google.golang.org/grpc/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
const heartbeatTimeoutMS = 6000
|
|
||||||
|
|
||||||
type ConnectionManager struct {
|
type ConnectionManager struct {
|
||||||
heartbeat heartbeatStore
|
heartbeat heartbeatStore
|
||||||
log zerolog.Logger
|
log zerolog.Logger
|
||||||
status statusNotifier
|
status statusNotifier
|
||||||
agentConnStore *AgentConnStore
|
agentConnStore *AgentConnStore
|
||||||
|
heartbeatTimeout int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConnectionManager(heartbeat heartbeatStore, status statusNotifier, logger zerolog.Logger) *ConnectionManager {
|
func NewConnectionManager(heartbeat heartbeatStore, status statusNotifier, heartbeatTimeoutMS int, logger zerolog.Logger) *ConnectionManager {
|
||||||
return &ConnectionManager{heartbeat: heartbeat, log: logger, status: status, agentConnStore: NewAgentConnStore()}
|
return &ConnectionManager{heartbeat: heartbeat, log: logger, status: status, agentConnStore: NewAgentConnStore(), heartbeatTimeout: heartbeatTimeoutMS + 600}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConnectionManager) NewConnection(stream streamConn) {
|
func (c *ConnectionManager) NewConnection(stream StreamConn) error {
|
||||||
AgentID, err := agentIDFromMetadata(stream.Context())
|
AgentID, err := agentIDFromMetadata(stream.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.log.Error().Err(err).Msg("missing agent id in metadata")
|
c.log.Error().Err(err).Msg("missing agent id in metadata")
|
||||||
return
|
return fmt.Errorf("get agent id: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.log.Info().Str("agentID", AgentID).Msg("connection accepted")
|
c.log.Info().Str("agentID", AgentID).Msg("connection accepted")
|
||||||
|
|
||||||
status := c.status.New(AgentID)
|
status := c.status.New(AgentID)
|
||||||
|
|
||||||
agent := newAgentConnection(AgentID, stream, c.heartbeat, status, heartbeatTimeoutMS, c.log)
|
agent := newAgentConnection(AgentID, stream, c.heartbeat, status, c.heartbeatTimeout, c.log)
|
||||||
c.agentConnStore.Add(AgentID, agent)
|
c.agentConnStore.Add(AgentID, agent)
|
||||||
go func() {
|
defer c.agentConnStore.Delete(AgentID)
|
||||||
c.log.Debug().Str("agentID", AgentID).Msg("start listening")
|
|
||||||
err := agent.Listen()
|
c.log.Debug().Str("agentID", AgentID).Msg("start listening")
|
||||||
if err != nil {
|
|
||||||
c.log.Error().Err(err).Msg("listening agent stopped")
|
return agent.Listen()
|
||||||
}
|
|
||||||
c.agentConnStore.Delete(AgentID)
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConnectionManager) GetConnection(AgentID string) (*AgentConnection, error) {
|
func (c *ConnectionManager) GetConnection(AgentID string) (*AgentConnection, error) {
|
||||||
|
|||||||
@@ -0,0 +1,116 @@
|
|||||||
|
package connection_manager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
pb "github.com/lorsanstand/HomeOps-Hub/api/gen/homeops"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"google.golang.org/grpc/metadata"
|
||||||
|
"gotest.tools/v3/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
type connectionManagerTestHarness struct {
|
||||||
|
heartbeat *heartBeatMock
|
||||||
|
status *statusNotifierMock
|
||||||
|
manager *ConnectionManager
|
||||||
|
}
|
||||||
|
|
||||||
|
func newConnectionManagerTestHarness(t *testing.T) *connectionManagerTestHarness {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
heartbeat := &heartBeatMock{doneCh: make(chan struct{}, 2)}
|
||||||
|
status := &statusNotifierMock{agentIDCh: make(chan string, 1)}
|
||||||
|
|
||||||
|
manager := NewConnectionManager(heartbeat, status, 10000, zerolog.New(nil))
|
||||||
|
|
||||||
|
return &connectionManagerTestHarness{manager: manager, status: status, heartbeat: heartbeat}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMetadataAgentID(t *testing.T, agentID string) metadata.MD {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
return metadata.New(map[string]string{"agent-id": agentID})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewConnectionManager_NewConnection(t *testing.T) {
|
||||||
|
h := newConnectionManagerTestHarness(t)
|
||||||
|
agentID := "123"
|
||||||
|
|
||||||
|
ctx := metadata.NewIncomingContext(context.Background(), newMetadataAgentID(t, agentID))
|
||||||
|
|
||||||
|
stream := streamMock{ctx: ctx,
|
||||||
|
recvCh: make(chan *pb.AgentEvent, 1),
|
||||||
|
sendCh: make(chan *pb.ServerCommandRequest, 1),
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
_ = h.manager.NewConnection(&stream)
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case ID := <-h.status.agentIDCh:
|
||||||
|
require.Equal(t, agentID, ID)
|
||||||
|
case <-time.After(200 * time.Millisecond):
|
||||||
|
t.Fatalf("get agent id for notifier")
|
||||||
|
}
|
||||||
|
|
||||||
|
agentIDs := h.manager.GetAllAgentID()
|
||||||
|
assert.Equal(t, agentID, agentIDs[0])
|
||||||
|
|
||||||
|
agent, err := h.manager.GetConnection(agentID)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
require.NotNil(t, agent)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewConnectionManager_NewConnectionNotAgentID(t *testing.T) {
|
||||||
|
h := newConnectionManagerTestHarness(t)
|
||||||
|
|
||||||
|
stream := streamMock{ctx: context.Background(),
|
||||||
|
recvCh: make(chan *pb.AgentEvent, 1),
|
||||||
|
sendCh: make(chan *pb.ServerCommandRequest, 1),
|
||||||
|
}
|
||||||
|
|
||||||
|
wait := make(chan struct{})
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
err := h.manager.NewConnection(&stream)
|
||||||
|
assert.ErrorContains(t, err, "get agent id")
|
||||||
|
wait <- struct{}{}
|
||||||
|
}()
|
||||||
|
|
||||||
|
waitFor(t, wait, 5000, "timeout new connection")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewConnectionManager_AgentNotFound(t *testing.T) {
|
||||||
|
h := newConnectionManagerTestHarness(t)
|
||||||
|
_, err := h.manager.GetConnection("123")
|
||||||
|
assert.ErrorIs(t, ErrNotFoundConn, err)
|
||||||
|
|
||||||
|
agentIDs := h.manager.GetAllAgentID()
|
||||||
|
assert.Equal(t, len(agentIDs), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_agentIDFromMetadata(t *testing.T) {
|
||||||
|
agentID := "123"
|
||||||
|
|
||||||
|
ctx := metadata.NewIncomingContext(context.Background(), newMetadataAgentID(t, agentID))
|
||||||
|
id, err := agentIDFromMetadata(ctx)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Equal(t, id, agentID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_agentIDFromMetadata_MetadataNotFound(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
_, err := agentIDFromMetadata(ctx)
|
||||||
|
assert.ErrorContains(t, err, "metadata not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_agentIDFromMetadata_AgentIDNotFound(t *testing.T) {
|
||||||
|
ctx := metadata.NewIncomingContext(context.Background(), newMetadataAgentID(t, ""))
|
||||||
|
_, err := agentIDFromMetadata(ctx)
|
||||||
|
assert.ErrorContains(t, err, "agent-id not found")
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
pb "github.com/lorsanstand/HomeOps-Hub/api/gen/homeops"
|
pb "github.com/lorsanstand/HomeOps-Hub/api/gen/homeops"
|
||||||
domainHub "github.com/lorsanstand/HomeOps-Hub/hub/internal/domain"
|
domainHub "github.com/lorsanstand/HomeOps-Hub/shared/domain"
|
||||||
)
|
)
|
||||||
|
|
||||||
func toCreateHeartbeatModel(agentID string, heartbeat *pb.AgentEvent_Heartbeat) domainHub.CreateHeartbeatModel {
|
func toCreateHeartbeatModel(agentID string, heartbeat *pb.AgentEvent_Heartbeat) domainHub.CreateHeartbeatModel {
|
||||||
@@ -15,7 +15,7 @@ func toCreateHeartbeatModel(agentID string, heartbeat *pb.AgentEvent_Heartbeat)
|
|||||||
Timestamp: timestamp,
|
Timestamp: timestamp,
|
||||||
Metrics: domainHub.SystemMetrics{
|
Metrics: domainHub.SystemMetrics{
|
||||||
MemoryUsage: float64(heartbeat.Heartbeat.Metrics.MemoryUsage),
|
MemoryUsage: float64(heartbeat.Heartbeat.Metrics.MemoryUsage),
|
||||||
CpuUsage: float64(heartbeat.Heartbeat.Metrics.CpuUsage),
|
CPUUsage: float64(heartbeat.Heartbeat.Metrics.CpuUsage),
|
||||||
DiskUsage: float64(heartbeat.Heartbeat.Metrics.DiskUsage),
|
DiskUsage: float64(heartbeat.Heartbeat.Metrics.DiskUsage),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,119 @@
|
|||||||
|
package connection_manager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
pb "github.com/lorsanstand/HomeOps-Hub/api/gen/homeops"
|
||||||
|
domainHub "github.com/lorsanstand/HomeOps-Hub/shared/domain"
|
||||||
|
)
|
||||||
|
|
||||||
|
type streamMock struct {
|
||||||
|
recvCh chan *pb.AgentEvent
|
||||||
|
sendCh chan *pb.ServerCommandRequest
|
||||||
|
ctx context.Context
|
||||||
|
mu sync.Mutex
|
||||||
|
sendErr error
|
||||||
|
recvErr error
|
||||||
|
closeOnce sync.Once
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *streamMock) Context() context.Context {
|
||||||
|
return f.ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *streamMock) Send(request *pb.ServerCommandRequest) error {
|
||||||
|
f.mu.Lock()
|
||||||
|
err := f.sendErr
|
||||||
|
f.mu.Unlock()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f.sendCh <- request
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *streamMock) Recv() (*pb.AgentEvent, error) {
|
||||||
|
f.mu.Lock()
|
||||||
|
recvErr := f.recvErr
|
||||||
|
f.mu.Unlock()
|
||||||
|
if recvErr != nil {
|
||||||
|
return nil, recvErr
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case msg, ok := <-f.recvCh:
|
||||||
|
if !ok {
|
||||||
|
return nil, io.EOF
|
||||||
|
}
|
||||||
|
return msg, nil
|
||||||
|
case <-f.ctx.Done():
|
||||||
|
return nil, f.ctx.Err()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *streamMock) CloseRecv() {
|
||||||
|
f.closeOnce.Do(func() {
|
||||||
|
close(f.recvCh)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type heartBeatMock struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
countUse int
|
||||||
|
doneCh chan struct{}
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *heartBeatMock) CreateHeartbeat(ctx context.Context, heartbeat domainHub.CreateHeartbeatModel) error {
|
||||||
|
h.mu.Lock()
|
||||||
|
h.countUse += 1
|
||||||
|
err := h.err
|
||||||
|
h.mu.Unlock()
|
||||||
|
select {
|
||||||
|
case h.doneCh <- struct{}{}:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
type statusMock struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
online bool
|
||||||
|
doneCh chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *statusMock) Offline() {
|
||||||
|
s.mu.Lock()
|
||||||
|
s.online = false
|
||||||
|
s.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *statusMock) Online() {
|
||||||
|
s.mu.Lock()
|
||||||
|
s.online = true
|
||||||
|
s.mu.Unlock()
|
||||||
|
select {
|
||||||
|
case s.doneCh <- struct{}{}:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *statusMock) IsOnline() bool {
|
||||||
|
s.mu.Lock()
|
||||||
|
defer s.mu.Unlock()
|
||||||
|
return s.online
|
||||||
|
}
|
||||||
|
|
||||||
|
type statusNotifierMock struct {
|
||||||
|
agentIDCh chan string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *statusNotifierMock) New(AgentID string) StatusAgent {
|
||||||
|
select {
|
||||||
|
case s.agentIDCh <- AgentID:
|
||||||
|
default:
|
||||||
|
|
||||||
|
}
|
||||||
|
return &statusMock{doneCh: make(chan struct{}, 2)}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ package connection_manager
|
|||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
domainHub "github.com/lorsanstand/HomeOps-Hub/hub/internal/domain"
|
domainHub "github.com/lorsanstand/HomeOps-Hub/shared/domain"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AgentConnStore struct {
|
type AgentConnStore struct {
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ import (
|
|||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
)
|
)
|
||||||
|
|
||||||
const HEARTBEAT = 5
|
|
||||||
|
|
||||||
type Store interface {
|
type Store interface {
|
||||||
NewAgent(ctx context.Context, agent domainHub.CreateAgentModel) error
|
NewAgent(ctx context.Context, agent domainHub.CreateAgentModel) error
|
||||||
GetAgentByAgentID(ctx context.Context, AgentID string) (domainHub.AgentModel, error)
|
GetAgentByAgentID(ctx context.Context, AgentID string) (domainHub.AgentModel, error)
|
||||||
@@ -21,12 +19,13 @@ type Store interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type HubService struct {
|
type HubService struct {
|
||||||
store Store
|
store Store
|
||||||
log zerolog.Logger
|
log zerolog.Logger
|
||||||
|
heartbeatTimeout int
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHubService(store Store, logger zerolog.Logger) *HubService {
|
func NewHubService(store Store, heartbeatTimeout int, logger zerolog.Logger) *HubService {
|
||||||
return &HubService{log: logger, store: store}
|
return &HubService{log: logger, store: store, heartbeatTimeout: heartbeatTimeout}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HubService) RegisterAgent(ctx context.Context, data domain.RegisterAgentRequest) (domain.RegisterAgentResponse, error) {
|
func (h *HubService) RegisterAgent(ctx context.Context, data domain.RegisterAgentRequest) (domain.RegisterAgentResponse, error) {
|
||||||
@@ -47,7 +46,7 @@ func (h *HubService) RegisterAgent(ctx context.Context, data domain.RegisterAgen
|
|||||||
return domain.RegisterAgentResponse{}, fmt.Errorf("update agent in db: %w", err)
|
return domain.RegisterAgentResponse{}, fmt.Errorf("update agent in db: %w", err)
|
||||||
}
|
}
|
||||||
h.log.Debug().Str("agentId", agent.AgentID).Msg("agent updated successfully")
|
h.log.Debug().Str("agentId", agent.AgentID).Msg("agent updated successfully")
|
||||||
return domain.RegisterAgentResponse{AgentID: agent.AgentID, Heartbeat: HEARTBEAT}, nil
|
return domain.RegisterAgentResponse{AgentID: agent.AgentID, Heartbeat: h.heartbeatTimeout}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
AgentID, err := hasher.MakeID(data.Host, data.AgentName)
|
AgentID, err := hasher.MakeID(data.Host, data.AgentName)
|
||||||
@@ -62,5 +61,5 @@ func (h *HubService) RegisterAgent(ctx context.Context, data domain.RegisterAgen
|
|||||||
if err := h.store.NewAgent(ctx, agentStore); err != nil {
|
if err := h.store.NewAgent(ctx, agentStore); err != nil {
|
||||||
return domain.RegisterAgentResponse{}, fmt.Errorf("insert new agent: %w", err)
|
return domain.RegisterAgentResponse{}, fmt.Errorf("insert new agent: %w", err)
|
||||||
}
|
}
|
||||||
return domain.RegisterAgentResponse{AgentID: AgentID, Heartbeat: HEARTBEAT}, nil
|
return domain.RegisterAgentResponse{AgentID: AgentID, Heartbeat: h.heartbeatTimeout}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,24 +77,24 @@ func toDomainCapabilities(caps []byte) []domain.Capability {
|
|||||||
return capabilities
|
return capabilities
|
||||||
}
|
}
|
||||||
|
|
||||||
func toDBHeartbeat(heartbeat domainHub.CreateHeartbeatModel) gen2.InsertHeartbeatParams {
|
func toDBHeartbeat(heartbeat domain.CreateHeartbeatModel) gen2.InsertHeartbeatParams {
|
||||||
|
|
||||||
return gen2.InsertHeartbeatParams{
|
return gen2.InsertHeartbeatParams{
|
||||||
AgentID: heartbeat.AgentID,
|
AgentID: heartbeat.AgentID,
|
||||||
HeartbeatTimestamp: heartbeat.Timestamp,
|
HeartbeatTimestamp: heartbeat.Timestamp,
|
||||||
CpuUsage: heartbeat.Metrics.CpuUsage,
|
CpuUsage: heartbeat.Metrics.CPUUsage,
|
||||||
DiskUsage: heartbeat.Metrics.DiskUsage,
|
DiskUsage: heartbeat.Metrics.DiskUsage,
|
||||||
MemoryUsage: heartbeat.Metrics.MemoryUsage,
|
MemoryUsage: heartbeat.Metrics.MemoryUsage,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func toHeartBeatModel(heartbeat gen2.Heartbeat) domainHub.HeartbeatModel {
|
func toHeartBeatModel(heartbeat gen2.Heartbeat) domain.HeartbeatModel {
|
||||||
return domainHub.HeartbeatModel{
|
return domain.HeartbeatModel{
|
||||||
Timestamp: heartbeat.HeartbeatTimestamp,
|
Timestamp: heartbeat.HeartbeatTimestamp,
|
||||||
AgentID: heartbeat.AgentID,
|
AgentID: heartbeat.AgentID,
|
||||||
ID: int(heartbeat.ID),
|
ID: int(heartbeat.ID),
|
||||||
Metrics: domainHub.SystemMetrics{
|
Metrics: domain.SystemMetrics{
|
||||||
CpuUsage: heartbeat.CpuUsage,
|
CPUUsage: heartbeat.CpuUsage,
|
||||||
DiskUsage: heartbeat.DiskUsage,
|
DiskUsage: heartbeat.DiskUsage,
|
||||||
MemoryUsage: heartbeat.MemoryUsage,
|
MemoryUsage: heartbeat.MemoryUsage,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
|
|
||||||
domainHub "github.com/lorsanstand/HomeOps-Hub/hub/internal/domain"
|
domainHub "github.com/lorsanstand/HomeOps-Hub/hub/internal/domain"
|
||||||
"github.com/lorsanstand/HomeOps-Hub/hub/internal/store/sqlc/gen"
|
"github.com/lorsanstand/HomeOps-Hub/hub/internal/store/sqlc/gen"
|
||||||
|
"github.com/lorsanstand/HomeOps-Hub/shared/domain"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HubStore struct {
|
type HubStore struct {
|
||||||
@@ -36,19 +37,19 @@ func (h *HubStore) UpdateAgentByID(ctx context.Context, ID int, updateAgent doma
|
|||||||
return h.queries.UpdateAgentByID(ctx, data)
|
return h.queries.UpdateAgentByID(ctx, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HubStore) CreateHeartbeat(ctx context.Context, heartbeat domainHub.CreateHeartbeatModel) error {
|
func (h *HubStore) CreateHeartbeat(ctx context.Context, heartbeat domain.CreateHeartbeatModel) error {
|
||||||
data := toDBHeartbeat(heartbeat)
|
data := toDBHeartbeat(heartbeat)
|
||||||
return h.queries.InsertHeartbeat(ctx, data)
|
return h.queries.InsertHeartbeat(ctx, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HubStore) GetHeartbeatsByIDAfter(ctx context.Context, agentID string, timestamp time.Time) ([]domainHub.HeartbeatModel, error) {
|
func (h *HubStore) GetHeartbeatsByIDAfter(ctx context.Context, agentID string, timestamp time.Time) ([]domain.HeartbeatModel, error) {
|
||||||
data := gen.SelectHeartbeatsAfterParams{AgentID: agentID, Timestamp: timestamp}
|
data := gen.SelectHeartbeatsAfterParams{AgentID: agentID, Timestamp: timestamp}
|
||||||
heartbeats, err := h.queries.SelectHeartbeatsAfter(ctx, data)
|
heartbeats, err := h.queries.SelectHeartbeatsAfter(ctx, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []domainHub.HeartbeatModel{}, err
|
return []domain.HeartbeatModel{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
heartbeatsModel := make([]domainHub.HeartbeatModel, len(heartbeats))
|
heartbeatsModel := make([]domain.HeartbeatModel, len(heartbeats))
|
||||||
|
|
||||||
for i, heartbeat := range heartbeats {
|
for i, heartbeat := range heartbeats {
|
||||||
heartbeatsModel[i] = toHeartBeatModel(heartbeat)
|
heartbeatsModel[i] = toHeartBeatModel(heartbeat)
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package notifier
|
||||||
|
|
||||||
|
import "github.com/lorsanstand/HomeOps-Hub/hub/internal/service/connection_manager"
|
||||||
|
|
||||||
|
// Временная заглушка
|
||||||
|
type StatusNotifier struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
type Status struct {
|
||||||
|
agentID string
|
||||||
|
online bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStatusNotifier() *StatusNotifier {
|
||||||
|
return &StatusNotifier{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StatusNotifier) New(agentID string) connection_manager.StatusAgent {
|
||||||
|
return &Status{agentID: agentID}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Status) Online() {
|
||||||
|
s.online = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Status) Offline() {
|
||||||
|
s.online = false
|
||||||
|
}
|
||||||
+4
-18
@@ -9,14 +9,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
DBHost string `env:"DB_HOST"`
|
LogLevel string `env:"LOG_LEVEL" env-default:"INFO"`
|
||||||
DBPort int `env:"DB_PORT"`
|
Mode string `env:"MODE" env-default:"DEV"`
|
||||||
DBPassword string `env:"DB_PASS"`
|
Port int `env:"PORT" env-default:"9000"`
|
||||||
DBUser string `env:"DB_USER"`
|
Heartbeat int `env:"HEARTBEAT" env-default:"5"`
|
||||||
DBName string `env:"DB_NAME"`
|
|
||||||
LogLevel string `env:"LOG_LEVEL" env-default:"INFO"`
|
|
||||||
Mode string `env:"MODE" env-default:"DEV"`
|
|
||||||
Port int `env:"PORT" env-default:"9000"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewConfig() (*Config, error) {
|
func NewConfig() (*Config, error) {
|
||||||
@@ -33,16 +29,6 @@ func NewConfig() (*Config, error) {
|
|||||||
return &cfg, nil
|
return &cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) GetURLPostgres() string {
|
|
||||||
return fmt.Sprintf(
|
|
||||||
"postgres://%v:%v@%v:%v/%v?sslmode=disable",
|
|
||||||
c.DBUser,
|
|
||||||
c.DBPassword,
|
|
||||||
c.DBHost,
|
|
||||||
c.DBPort,
|
|
||||||
c.DBName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) GetLogLevel() zerolog.Level {
|
func (c *Config) GetLogLevel() zerolog.Level {
|
||||||
level, err := zerolog.ParseLevel(c.LogLevel)
|
level, err := zerolog.ParseLevel(c.LogLevel)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -39,38 +39,3 @@ func TestConfig_GetLogLevel(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConfig_GetURLPostgres(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
cfg Config
|
|
||||||
wantURLPostgres string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "success",
|
|
||||||
cfg: Config{
|
|
||||||
DBHost: "TestHost",
|
|
||||||
DBName: "TestName",
|
|
||||||
DBPassword: "TestPassword",
|
|
||||||
DBPort: 1234,
|
|
||||||
DBUser: "TestUser",
|
|
||||||
},
|
|
||||||
wantURLPostgres: "postgres://TestUser:TestPassword@TestHost:1234/TestName?sslmode=disable",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
tt := tt
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
url := tt.cfg.GetURLPostgres()
|
|
||||||
|
|
||||||
if url != tt.wantURLPostgres {
|
|
||||||
t.Fatalf("expected %v, got: %v", tt.wantURLPostgres, url)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
package domain
|
|
||||||
|
|
||||||
type RegisterAgentRequest struct {
|
|
||||||
AgentID string
|
|
||||||
AgentName string
|
|
||||||
AgentVersion string
|
|
||||||
Host HostInfo
|
|
||||||
Capabilities []Capability
|
|
||||||
}
|
|
||||||
|
|
||||||
type HostInfo struct {
|
|
||||||
System string
|
|
||||||
Hostname string
|
|
||||||
Arch string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Capability struct {
|
|
||||||
Available bool
|
|
||||||
Version string
|
|
||||||
Name string
|
|
||||||
Reason string
|
|
||||||
}
|
|
||||||
|
|
||||||
type RegisterAgentResponse struct {
|
|
||||||
Heartbeat int
|
|
||||||
AgentID string
|
|
||||||
}
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
package domain
|
|
||||||
|
|
||||||
import (
|
|
||||||
pb "github.com/lorsanstand/HomeOps-Hub/api/gen/homeops"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ToDomainAgentRequest(request *pb.RegisterAgentRequest) RegisterAgentRequest {
|
|
||||||
if request == nil {
|
|
||||||
return RegisterAgentRequest{}
|
|
||||||
}
|
|
||||||
|
|
||||||
return RegisterAgentRequest{
|
|
||||||
AgentID: request.AgentId,
|
|
||||||
AgentName: request.AgentName,
|
|
||||||
Host: HostInfo{
|
|
||||||
System: request.Host.System,
|
|
||||||
Hostname: request.Host.Hostname,
|
|
||||||
Arch: request.Host.Arch,
|
|
||||||
},
|
|
||||||
Capabilities: ToDomainCapabilities(request.Capability),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ToDomainAgentResponse(response *pb.RegisterAgentResponse) RegisterAgentResponse {
|
|
||||||
if response == nil {
|
|
||||||
return RegisterAgentResponse{}
|
|
||||||
}
|
|
||||||
|
|
||||||
return RegisterAgentResponse{
|
|
||||||
AgentID: response.AgentId,
|
|
||||||
Heartbeat: int(response.HeartbeatIntervalSecond),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ToDomainCapabilities(capability []*pb.Capability) []Capability {
|
|
||||||
var caps []Capability
|
|
||||||
|
|
||||||
for _, capa := range capability {
|
|
||||||
if capa == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
caps = append(caps, Capability{
|
|
||||||
Name: capa.Name,
|
|
||||||
Version: capa.Version,
|
|
||||||
Reason: capa.Reason,
|
|
||||||
Available: capa.Available,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return caps
|
|
||||||
}
|
|
||||||
|
|
||||||
func ToGRPCAgentRequest(request RegisterAgentRequest) pb.RegisterAgentRequest {
|
|
||||||
return pb.RegisterAgentRequest{
|
|
||||||
AgentId: request.AgentID,
|
|
||||||
AgentName: request.AgentName,
|
|
||||||
Host: &pb.HostInfo{
|
|
||||||
Hostname: request.Host.Hostname,
|
|
||||||
Arch: request.Host.Arch,
|
|
||||||
System: request.Host.System,
|
|
||||||
},
|
|
||||||
Version: request.AgentVersion,
|
|
||||||
Capability: ToGRPCCapability(request.Capabilities),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ToGRPCAgentResponse(response RegisterAgentResponse) *pb.RegisterAgentResponse {
|
|
||||||
return &pb.RegisterAgentResponse{AgentId: response.AgentID, HeartbeatIntervalSecond: int64(response.Heartbeat)}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ToGRPCCapability(caps []Capability) []*pb.Capability {
|
|
||||||
var capability []*pb.Capability
|
|
||||||
for _, capi := range caps {
|
|
||||||
capability = append(capability, &pb.Capability{
|
|
||||||
Name: capi.Name,
|
|
||||||
Available: capi.Available,
|
|
||||||
Version: capi.Version,
|
|
||||||
Reason: capi.Reason,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return capability
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package domain
|
||||||
|
|
||||||
|
type RegisterAgentRequest struct {
|
||||||
|
AgentID string
|
||||||
|
AgentName string
|
||||||
|
AgentVersion string
|
||||||
|
Host HostInfo
|
||||||
|
Capabilities map[string]Capability
|
||||||
|
}
|
||||||
|
|
||||||
|
type HostInfo struct {
|
||||||
|
System string
|
||||||
|
Hostname string
|
||||||
|
Arch string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Capability struct {
|
||||||
|
Available bool
|
||||||
|
Version string
|
||||||
|
Reason string
|
||||||
|
Command map[string]CapabilityCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
type CapabilityCommand struct {
|
||||||
|
OptionalArgs map[string]CommandArgs
|
||||||
|
RequiredArgs map[string]CommandArgs
|
||||||
|
Version string
|
||||||
|
Description string
|
||||||
|
TypeOutput string
|
||||||
|
}
|
||||||
|
|
||||||
|
type CommandArgs struct {
|
||||||
|
Type string
|
||||||
|
Description string
|
||||||
|
Default string
|
||||||
|
Enum []string
|
||||||
|
Validation ArgValidation
|
||||||
|
}
|
||||||
|
|
||||||
|
type ArgValidation struct {
|
||||||
|
MinValue int
|
||||||
|
MaxValue int
|
||||||
|
Pattern string
|
||||||
|
AllowedExts []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type RegisterAgentResponse struct {
|
||||||
|
Heartbeat int
|
||||||
|
AgentID string
|
||||||
|
}
|
||||||
@@ -23,7 +23,7 @@ type AgentAlert struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SystemMetrics struct {
|
type SystemMetrics struct {
|
||||||
CpuUsage float64
|
CPUUsage float64
|
||||||
MemoryUsage float64
|
MemoryUsage float64
|
||||||
DiskUsage float64
|
DiskUsage float64
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
package rpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
pb "github.com/lorsanstand/HomeOps-Hub/api/gen/homeops"
|
||||||
|
"github.com/lorsanstand/HomeOps-Hub/shared/domain"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ToDomainAgentRequest(request *pb.RegisterAgentRequest) (domain.RegisterAgentRequest, error) {
|
||||||
|
if request == nil {
|
||||||
|
return domain.RegisterAgentRequest{}, fmt.Errorf("request is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
return domain.RegisterAgentRequest{
|
||||||
|
AgentVersion: request.Version,
|
||||||
|
AgentID: request.AgentId,
|
||||||
|
AgentName: request.AgentName,
|
||||||
|
Host: domain.HostInfo{
|
||||||
|
System: request.Host.System,
|
||||||
|
Hostname: request.Host.Hostname,
|
||||||
|
Arch: request.Host.Arch,
|
||||||
|
},
|
||||||
|
Capabilities: ToDomainCapabilities(request.Capability),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToDomainAgentResponse(response *pb.RegisterAgentResponse) (domain.RegisterAgentResponse, error) {
|
||||||
|
if response == nil {
|
||||||
|
return domain.RegisterAgentResponse{}, fmt.Errorf("request is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
return domain.RegisterAgentResponse{
|
||||||
|
AgentID: response.AgentId,
|
||||||
|
Heartbeat: int(response.HeartbeatIntervalSecond),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToDomainCapabilities(capabilities map[string]*pb.Capability) map[string]domain.Capability {
|
||||||
|
domainCaps := make(map[string]domain.Capability, len(capabilities))
|
||||||
|
|
||||||
|
for name, capability := range capabilities {
|
||||||
|
if capability == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
domainCaps[name] = domain.Capability{
|
||||||
|
Version: capability.Version,
|
||||||
|
Reason: capability.Reason,
|
||||||
|
Available: capability.Available,
|
||||||
|
Command: ToDomainCapabilityCommands(capability.Command),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return domainCaps
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToDomainCapabilityCommands(commands map[string]*pb.CapabilityCommand) map[string]domain.CapabilityCommand {
|
||||||
|
domainCommand := make(map[string]domain.CapabilityCommand, len(commands))
|
||||||
|
|
||||||
|
for name, command := range commands {
|
||||||
|
if command == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
domainCommand[name] = domain.CapabilityCommand{
|
||||||
|
OptionalArgs: ToDomainCommandArgs(command.OptArgs),
|
||||||
|
RequiredArgs: ToDomainCommandArgs(command.ReqArgs),
|
||||||
|
Version: command.Version,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return domainCommand
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToDomainCommandArgs(args map[string]*pb.CommandsArgs) map[string]domain.CommandArgs {
|
||||||
|
DomainArgs := make(map[string]domain.CommandArgs, len(args))
|
||||||
|
|
||||||
|
for name, arg := range args {
|
||||||
|
DomainArgs[name] = domain.CommandArgs{
|
||||||
|
Type: arg.Type,
|
||||||
|
Default: arg.Default,
|
||||||
|
Description: arg.Description,
|
||||||
|
Enum: arg.Enum,
|
||||||
|
Validation: domain.ArgValidation{
|
||||||
|
AllowedExts: arg.Validation.AllowedExts,
|
||||||
|
MaxValue: int(arg.Validation.MaxValue),
|
||||||
|
MinValue: int(arg.Validation.MinValue),
|
||||||
|
Pattern: arg.Validation.Pattern,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return DomainArgs
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToGRPCAgentRequest(request domain.RegisterAgentRequest) *pb.RegisterAgentRequest {
|
||||||
|
return &pb.RegisterAgentRequest{
|
||||||
|
AgentId: request.AgentID,
|
||||||
|
AgentName: request.AgentName,
|
||||||
|
Host: &pb.HostInfo{
|
||||||
|
Hostname: request.Host.Hostname,
|
||||||
|
Arch: request.Host.Arch,
|
||||||
|
System: request.Host.System,
|
||||||
|
},
|
||||||
|
Version: request.AgentVersion,
|
||||||
|
Capability: ToGRPCCapability(request.Capabilities),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToGRPCAgentResponse(response domain.RegisterAgentResponse) *pb.RegisterAgentResponse {
|
||||||
|
return &pb.RegisterAgentResponse{AgentId: response.AgentID, HeartbeatIntervalSecond: int64(response.Heartbeat)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToGRPCCapability(capabilities map[string]domain.Capability) map[string]*pb.Capability {
|
||||||
|
GRPCCapabilities := make(map[string]*pb.Capability, len(capabilities))
|
||||||
|
|
||||||
|
for name, capability := range capabilities {
|
||||||
|
GRPCCapabilities[name] = &pb.Capability{
|
||||||
|
Available: capability.Available,
|
||||||
|
Version: capability.Version,
|
||||||
|
Reason: capability.Reason,
|
||||||
|
Command: ToGRPCCapabilityCommands(capability.Command),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return GRPCCapabilities
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToGRPCCapabilityCommands(commands map[string]domain.CapabilityCommand) map[string]*pb.CapabilityCommand {
|
||||||
|
GRPCCommands := make(map[string]*pb.CapabilityCommand, len(commands))
|
||||||
|
|
||||||
|
for name, command := range commands {
|
||||||
|
GRPCCommands[name] = &pb.CapabilityCommand{
|
||||||
|
Version: command.Version,
|
||||||
|
OptArgs: ToGRPCCommandArgs(command.OptionalArgs),
|
||||||
|
ReqArgs: ToGRPCCommandArgs(command.RequiredArgs),
|
||||||
|
TypeOutput: command.TypeOutput,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return GRPCCommands
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToGRPCCommandArgs(args map[string]domain.CommandArgs) map[string]*pb.CommandsArgs {
|
||||||
|
GRPCArgs := make(map[string]*pb.CommandsArgs, len(args))
|
||||||
|
|
||||||
|
for name, arg := range args {
|
||||||
|
GRPCArgs[name] = &pb.CommandsArgs{
|
||||||
|
Type: arg.Type,
|
||||||
|
Default: arg.Default,
|
||||||
|
Description: arg.Description,
|
||||||
|
Enum: arg.Enum,
|
||||||
|
Validation: &pb.ArgValidation{
|
||||||
|
AllowedExts: arg.Validation.AllowedExts,
|
||||||
|
MaxValue: int64(arg.Validation.MaxValue),
|
||||||
|
MinValue: int64(arg.Validation.MinValue),
|
||||||
|
Pattern: arg.Validation.Pattern,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return GRPCArgs
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user