feat: Add core models and protocol definitions for NxMesh

This commit is contained in:
GW_MC
2026-03-03 04:14:36 +00:00
parent 43b2e44d95
commit 2e9ad4fc21
13 changed files with 1018 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
[package]
name = "nxmesh-core"
version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true
repository.workspace = true
rust-version.workspace = true
[dependencies]
serde.workspace = true
serde_json.workspace = true
thiserror.workspace = true
chrono.workspace = true
uuid.workspace = true
[dev-dependencies]
tokio-test.workspace = true

View File

@@ -0,0 +1,43 @@
//! Core error types
use thiserror::Error;
/// Result type alias for core operations
pub type Result<T> = std::result::Result<T, CoreError>;
/// Core error types used across NxMesh
#[derive(Error, Debug, Clone)]
pub enum CoreError {
#[error("Validation error: {0}")]
Validation(String),
#[error("Invalid configuration: {0}")]
InvalidConfig(String),
#[error("Serialization error: {0}")]
Serialization(String),
#[error("Crypto error: {0}")]
Crypto(String),
#[error("Not found: {0}")]
NotFound(String),
#[error("Permission denied: {0}")]
PermissionDenied(String),
#[error("Internal error: {0}")]
Internal(String),
}
impl CoreError {
/// Create a validation error
pub fn validation<S: Into<String>>(msg: S) -> Self {
Self::Validation(msg.into())
}
/// Create a not found error
pub fn not_found<S: Into<String>>(resource: S) -> Self {
Self::NotFound(resource.into())
}
}

View File

@@ -0,0 +1,9 @@
//! NxMesh Core Library
//!
//! This crate contains shared types, models, and utilities used by both
//! the master and agent components of NxMesh.
pub mod error;
pub mod models;
pub use error::{CoreError, Result};

View File

@@ -0,0 +1,152 @@
//! Agent model
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use uuid::Uuid;
/// Agent entity - represents a running nxmesh-agent instance
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Agent {
pub id: Uuid,
pub workspace_id: Uuid,
pub name: String,
pub hostname: String,
pub ip_address: String,
pub version: String,
pub state: AgentState,
pub deployment_mode: DeploymentMode,
pub last_seen_at: DateTime<Utc>,
pub capabilities: Vec<String>,
pub labels: HashMap<String, String>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
/// Agent connection state
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum AgentState {
/// Registered but never connected
Pending,
/// Connected and healthy
Online,
/// Disconnected
Offline,
/// Connected but health checks failing
Degraded,
/// Manually placed in maintenance mode
Maintenance,
}
/// Deployment mode for the agent
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum DeploymentMode {
/// Docker sidecar (shares PID namespace with nginx)
DockerSidecar,
/// Kubernetes sidecar
KubernetesSidecar,
/// Standalone mode (VM or bare metal)
Standalone,
}
/// Health report from agent
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HealthReport {
pub agent_id: Uuid,
pub timestamp: DateTime<Utc>,
pub nginx_status: NginxStatus,
pub system_metrics: SystemMetrics,
pub config_checksum: String,
pub alerts: Vec<Alert>,
}
/// Nginx process status
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NginxStatus {
pub is_running: bool,
pub pid: Option<u32>,
pub uptime_seconds: u64,
pub active_connections: u32,
pub requests_per_second: f64,
}
/// System-level metrics
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SystemMetrics {
pub cpu_percent: f64,
pub memory_used_mb: u64,
pub memory_total_mb: u64,
pub disk_used_gb: u64,
pub disk_total_gb: u64,
}
/// Alert from agent
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Alert {
pub id: String,
pub severity: AlertSeverity,
pub message: String,
pub timestamp: DateTime<Utc>,
}
/// Alert severity levels
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum AlertSeverity {
Info,
Warning,
Error,
Critical,
}
impl Agent {
/// Create a new agent registration
pub fn new(
workspace_id: Uuid,
name: impl Into<String>,
hostname: impl Into<String>,
ip_address: impl Into<String>,
version: impl Into<String>,
deployment_mode: DeploymentMode,
) -> Self {
let now = Utc::now();
Self {
id: Uuid::new_v4(),
workspace_id,
name: name.into(),
hostname: hostname.into(),
ip_address: ip_address.into(),
version: version.into(),
state: AgentState::Pending,
deployment_mode,
last_seen_at: now,
capabilities: Vec::new(),
labels: HashMap::new(),
created_at: now,
updated_at: now,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_agent_creation() {
let ws_id = Uuid::new_v4();
let agent = Agent::new(
ws_id,
"web-server-01",
"web-01.internal",
"10.0.1.10",
"0.1.0",
DeploymentMode::DockerSidecar,
);
assert_eq!(agent.name, "web-server-01");
assert_eq!(agent.state, AgentState::Pending);
assert!(agent.capabilities.is_empty());
}
}

View File

@@ -0,0 +1,146 @@
//! Certificate model
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
/// SSL/TLS Certificate entity
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Certificate {
pub id: Uuid,
pub workspace_id: Uuid,
pub domain: String,
pub is_wildcard: bool,
pub provider: CertificateProvider,
pub status: CertificateStatus,
pub issued_at: Option<DateTime<Utc>>,
pub expires_at: Option<DateTime<Utc>>,
pub auto_renew: bool,
pub certificate_pem: Option<String>,
pub private_key_pem: Option<String>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
/// Certificate provider
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum CertificateProvider {
LetsEncrypt,
Custom,
}
/// Certificate status
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum CertificateStatus {
Pending,
Active,
Expired,
Error,
}
/// ACME challenge info
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AcmeChallenge {
pub certificate_id: Uuid,
pub challenge_type: ChallengeType,
pub token: String,
pub key_authorization: String,
pub status: ChallengeStatus,
pub completed_at: Option<DateTime<Utc>>,
}
/// ACME challenge type
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ChallengeType {
Http01,
Dns01,
}
/// ACME challenge status
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ChallengeStatus {
Pending,
Processing,
Valid,
Invalid,
}
impl Certificate {
/// Create a new certificate request
pub fn new(
workspace_id: Uuid,
domain: impl Into<String>,
provider: CertificateProvider,
auto_renew: bool,
) -> Self {
let now = Utc::now();
Self {
id: Uuid::new_v4(),
workspace_id,
domain: domain.into(),
is_wildcard: false,
provider,
status: CertificateStatus::Pending,
issued_at: None,
expires_at: None,
auto_renew,
certificate_pem: None,
private_key_pem: None,
created_at: now,
updated_at: now,
}
}
/// Check if certificate is expired or expiring soon
pub fn is_expiring_soon(&self, days: i64) -> bool {
match self.expires_at {
Some(expires) => {
let threshold = Utc::now() + chrono::Duration::days(days);
expires <= threshold
}
None => false,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_certificate_creation() {
let ws_id = Uuid::new_v4();
let cert = Certificate::new(
ws_id,
"example.com",
CertificateProvider::LetsEncrypt,
true,
);
assert_eq!(cert.domain, "example.com");
assert_eq!(cert.status, CertificateStatus::Pending);
assert!(cert.auto_renew);
}
#[test]
fn test_certificate_expiring_soon() {
let ws_id = Uuid::new_v4();
let mut cert = Certificate::new(
ws_id,
"example.com",
CertificateProvider::LetsEncrypt,
true,
);
// Not expiring
cert.expires_at = Some(Utc::now() + chrono::Duration::days(60));
assert!(!cert.is_expiring_soon(30));
// Expiring soon
cert.expires_at = Some(Utc::now() + chrono::Duration::days(20));
assert!(cert.is_expiring_soon(30));
}
}

View File

@@ -0,0 +1,195 @@
//! Configuration models
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use uuid::Uuid;
/// Virtual Host (server block) configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VirtualHost {
pub id: Uuid,
pub workspace_id: Uuid,
pub name: String,
pub server_name: String,
pub listen_port: u16,
pub ssl_enabled: bool,
pub ssl_certificate_id: Option<Uuid>,
pub locations: Vec<Location>,
pub http2_enabled: bool,
pub http3_enabled: bool,
pub gzip_enabled: bool,
pub rate_limiting: Option<RateLimitConfig>,
pub target_agents: AgentSelector,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
/// Location block configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Location {
pub path: String,
pub proxy_pass: Option<String>,
pub upstream_id: Option<Uuid>,
pub root: Option<String>,
pub index: Option<String>,
pub custom_headers: Vec<Header>,
pub rewrite_rules: Vec<RewriteRule>,
}
/// HTTP header
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Header {
pub name: String,
pub value: String,
pub always: bool,
}
/// Rewrite rule
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RewriteRule {
pub pattern: String,
pub replacement: String,
pub flag: String,
}
/// Rate limiting configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RateLimitConfig {
pub zone: String,
pub burst: u32,
pub per_minute: Option<u32>,
pub per_second: Option<u32>,
}
/// Upstream (backend pool) configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Upstream {
pub id: Uuid,
pub workspace_id: Uuid,
pub name: String,
pub algorithm: LoadBalanceAlgorithm,
pub servers: Vec<UpstreamServer>,
pub health_check: Option<HealthCheckConfig>,
pub keepalive_connections: Option<u32>,
pub keepalive_timeout: Option<u32>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
/// Upstream server definition
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpstreamServer {
pub address: String,
pub weight: u32,
pub backup: bool,
pub down: bool,
pub max_fails: u32,
pub fail_timeout: u32,
}
/// Load balancing algorithm
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum LoadBalanceAlgorithm {
RoundRobin,
LeastConnections,
IpHash,
WeightedRoundRobin,
}
/// Health check configuration for upstreams
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HealthCheckConfig {
pub enabled: bool,
pub path: String,
pub interval: u32,
pub timeout: u32,
pub healthy_threshold: u32,
pub unhealthy_threshold: u32,
}
/// Selector for targeting agents
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum AgentSelector {
/// All agents in the workspace
All,
/// Agents matching label selector
Selector { label_selector: String },
/// Specific agent
Agent { agent_id: Uuid },
}
/// Configuration scope for distribution
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ConfigScope {
/// All agents
Global,
/// All agents in workspace
Workspace,
/// Agents with specific label selector
AgentGroup(String),
/// Single agent
Agent(Uuid),
}
/// Configuration version for tracking changes
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConfigVersion {
pub id: Uuid,
pub resource_type: String,
pub resource_id: Uuid,
pub version_number: u64,
pub data: serde_json::Value,
pub checksum: String,
pub created_by: Uuid,
pub created_at: DateTime<Utc>,
pub change_summary: String,
}
/// Configuration update message sent to agents
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConfigUpdate {
pub config_id: String,
pub version: u64,
pub virtual_hosts: Vec<VirtualHost>,
pub upstreams: Vec<Upstream>,
pub ssl_certificates: HashMap<String, Certificate>,
}
/// Certificate data in config update
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Certificate {
pub id: String,
pub domain: String,
pub certificate_pem: String,
pub private_key_pem: String,
pub expires_at: DateTime<Utc>,
}
/// Configuration apply status
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ConfigApplyStatus {
Pending,
Validating,
Applying,
Success,
Failed,
RolledBack,
}
impl Default for UpstreamServer {
fn default() -> Self {
Self {
address: String::new(),
weight: 1,
backup: false,
down: false,
max_fails: 1,
fail_timeout: 10,
}
}
}

View File

@@ -0,0 +1,13 @@
//! Shared data models
pub mod agent;
pub mod certificate;
pub mod config;
pub mod organization;
pub mod workspace;
pub use agent::{Agent, AgentState, DeploymentMode};
pub use certificate::{Certificate, CertificateProvider, CertificateStatus};
pub use config::{AgentSelector, ConfigScope, Location, Upstream, UpstreamServer, VirtualHost};
pub use organization::Organization;
pub use workspace::Workspace;

View File

@@ -0,0 +1,62 @@
//! Organization model
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
/// Organization entity
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Organization {
pub id: Uuid,
pub name: String,
pub slug: String,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub settings: OrganizationSettings,
}
/// Organization-specific settings
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OrganizationSettings {
pub allow_public_agents: bool,
pub max_workspaces: Option<u32>,
pub max_agents_per_workspace: Option<u32>,
}
impl Default for OrganizationSettings {
fn default() -> Self {
Self {
allow_public_agents: false,
max_workspaces: None,
max_agents_per_workspace: None,
}
}
}
impl Organization {
/// Create a new organization
pub fn new(name: impl Into<String>, slug: impl Into<String>) -> Self {
let now = Utc::now();
Self {
id: Uuid::new_v4(),
name: name.into(),
slug: slug.into(),
created_at: now,
updated_at: now,
settings: OrganizationSettings::default(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_organization_creation() {
let org = Organization::new("Acme Corp", "acme-corp");
assert_eq!(org.name, "Acme Corp");
assert_eq!(org.slug, "acme-corp");
assert!(!org.settings.allow_public_agents);
}
}

View File

@@ -0,0 +1,49 @@
//! Workspace model
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
/// Workspace entity - isolated resource container within an organization
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Workspace {
pub id: Uuid,
pub organization_id: Uuid,
pub name: String,
pub slug: String,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
impl Workspace {
/// Create a new workspace
pub fn new(
organization_id: Uuid,
name: impl Into<String>,
slug: impl Into<String>,
) -> Self {
let now = Utc::now();
Self {
id: Uuid::new_v4(),
organization_id,
name: name.into(),
slug: slug.into(),
created_at: now,
updated_at: now,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_workspace_creation() {
let org_id = Uuid::new_v4();
let ws = Workspace::new(org_id, "Production", "production");
assert_eq!(ws.name, "Production");
assert_eq!(ws.slug, "production");
assert_eq!(ws.organization_id, org_id);
}
}

View File

@@ -0,0 +1,15 @@
[package]
name = "nxmesh-proto"
version.workspace = true
edition.workspace = true
authors.workspace = true
license.workspace = true
repository.workspace = true
rust-version.workspace = true
[dependencies]
tonic.workspace = true
prost.workspace = true
[build-dependencies]
tonic-build = "0.11"

View File

@@ -0,0 +1,9 @@
use std::io::Result;
fn main() -> Result<()> {
tonic_build::configure()
.build_server(true)
.build_client(true)
.compile(&["proto/agent.proto"], &["proto"])?;
Ok(())
}

View File

@@ -0,0 +1,298 @@
syntax = "proto3";
package nxmesh.agent.v1;
option go_package = "github.com/nxmesh/api/agent/v1";
// AgentService defines the bidirectional communication between master and agents
service AgentService {
// Stream establishes a persistent connection for real-time communication
rpc Stream(stream AgentMessage) returns (stream MasterMessage);
// ReportHealth sends a health report to the master
rpc ReportHealth(HealthReport) returns (Ack);
// ReportMetrics sends metrics batch to the master
rpc ReportMetrics(MetricsBatch) returns (Ack);
}
// Messages sent from agent to master
message AgentMessage {
string agent_id = 1;
int64 timestamp = 2;
oneof payload {
RegistrationRequest registration = 3;
HealthReport health = 4;
ConfigStatus config_status = 5;
MetricsBatch metrics = 6;
LogBatch logs = 7;
Event event = 8;
}
}
// Messages sent from master to agent
message MasterMessage {
int64 timestamp = 1;
oneof payload {
RegistrationResponse registration_response = 2;
ConfigUpdate config_update = 3;
Command command = 4;
Ack ack = 5;
Error error = 6;
}
}
// Registration
message RegistrationRequest {
string token = 1;
string hostname = 2;
string ip_address = 3;
string version = 4;
repeated string capabilities = 5;
map<string, string> labels = 6;
DeploymentMode deployment_mode = 7;
}
message RegistrationResponse {
string agent_id = 1;
bool success = 2;
string error_message = 3;
int64 heartbeat_interval_seconds = 4;
}
enum DeploymentMode {
DEPLOYMENT_MODE_UNSPECIFIED = 0;
DOCKER_SIDECAR = 1;
KUBERNETES_SIDECAR = 2;
STANDALONE = 3;
}
// Health Reporting
message HealthReport {
NginxStatus nginx = 1;
SystemMetrics system = 2;
string config_checksum = 3;
int64 config_version = 4;
repeated Alert alerts = 5;
}
message NginxStatus {
bool is_running = 1;
uint32 pid = 2;
uint64 uptime_seconds = 3;
uint32 active_connections = 4;
uint64 total_requests = 5;
float requests_per_second = 6;
}
message SystemMetrics {
float cpu_percent = 1;
uint64 memory_used_bytes = 2;
uint64 memory_total_bytes = 3;
uint64 disk_used_bytes = 4;
uint64 disk_total_bytes = 5;
float load_average_1m = 6;
}
message Alert {
string id = 1;
string severity = 2; // info, warning, error, critical
string message = 3;
int64 timestamp = 4;
}
// Configuration
message ConfigUpdate {
string config_id = 1;
int64 version = 2;
repeated VirtualHost virtual_hosts = 3;
repeated Upstream upstreams = 4;
map<string, Certificate> certificates = 5;
GlobalSettings global_settings = 6;
}
message VirtualHost {
string id = 1;
string name = 2;
string server_name = 3;
uint32 listen_port = 4;
bool ssl_enabled = 5;
string ssl_certificate_id = 6;
bool http2_enabled = 7;
bool http3_enabled = 8;
repeated Location locations = 9;
map<string, string> custom_directives = 10;
}
message Location {
string path = 1;
string proxy_pass = 2;
string upstream_id = 3;
string root = 4;
string index = 5;
repeated Header custom_headers = 6;
repeated RewriteRule rewrite_rules = 7;
map<string, string> custom_directives = 8;
}
message Header {
string name = 1;
string value = 2;
bool always = 3;
}
message RewriteRule {
string pattern = 1;
string replacement = 2;
string flag = 3;
}
message Upstream {
string id = 1;
string name = 2;
LoadBalanceAlgorithm algorithm = 3;
repeated UpstreamServer servers = 4;
HealthCheckConfig health_check = 5;
uint32 keepalive_connections = 6;
}
enum LoadBalanceAlgorithm {
LOAD_BALANCE_ALGORITHM_UNSPECIFIED = 0;
ROUND_ROBIN = 1;
LEAST_CONNECTIONS = 2;
IP_HASH = 3;
WEIGHTED_ROUND_ROBIN = 4;
}
message UpstreamServer {
string address = 1;
uint32 weight = 2;
bool backup = 3;
bool down = 4;
uint32 max_fails = 5;
uint32 fail_timeout_seconds = 6;
}
message HealthCheckConfig {
bool enabled = 1;
string path = 2;
uint32 interval_seconds = 3;
uint32 timeout_seconds = 4;
uint32 healthy_threshold = 5;
uint32 unhealthy_threshold = 6;
}
message Certificate {
string id = 1;
string domain = 2;
string certificate_pem = 3;
string private_key_pem = 4;
int64 expires_at = 5;
}
message GlobalSettings {
map<string, string> nginx_directives = 1;
map<string, string> env_vars = 2;
}
message ConfigStatus {
string config_id = 1;
int64 version = 2;
ConfigApplyStatus status = 3;
string error_message = 4;
int64 applied_at = 5;
}
enum ConfigApplyStatus {
CONFIG_APPLY_STATUS_UNSPECIFIED = 0;
PENDING = 1;
VALIDATING = 2;
APPLYING = 3;
SUCCESS = 4;
FAILED = 5;
ROLLED_BACK = 6;
}
// Metrics
message MetricsBatch {
int64 timestamp = 1;
repeated Metric metrics = 2;
}
message Metric {
string name = 1;
double value = 2;
int64 timestamp = 3;
map<string, string> labels = 4;
MetricType type = 5;
}
enum MetricType {
METRIC_TYPE_UNSPECIFIED = 0;
GAUGE = 1;
COUNTER = 2;
HISTOGRAM = 3;
}
// Logs
message LogBatch {
repeated LogEntry entries = 1;
}
message LogEntry {
int64 timestamp = 1;
string level = 2;
string message = 3;
map<string, string> fields = 4;
}
// Commands
message Command {
string command_id = 1;
oneof command {
ReloadCommand reload = 2;
RestartCommand restart = 3;
StopCommand stop = 4;
GetStatusCommand get_status = 5;
ValidateConfigCommand validate_config = 6;
}
}
message ReloadCommand {
bool graceful = 1;
}
message RestartCommand {
bool force = 1;
}
message StopCommand {
bool graceful = 1;
uint32 timeout_seconds = 2;
}
message GetStatusCommand {}
message ValidateConfigCommand {
string config_content = 1;
}
// Events
message Event {
string event_id = 1;
string event_type = 2;
int64 timestamp = 3;
map<string, string> data = 4;
}
// Common messages
message Ack {
string message_id = 1;
bool success = 2;
string error_message = 3;
}
message Error {
string code = 1;
string message = 2;
map<string, string> details = 3;
}

View File

@@ -0,0 +1,9 @@
//! NxMesh Protocol Buffers
//!
//! This crate contains the gRPC protocol definitions for master-agent communication.
pub mod agent {
tonic::include_proto!("nxmesh.agent.v1");
}
pub use agent::*;