345 lines
8.8 KiB
Rust
345 lines
8.8 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
|
|
#[derive(Debug, Clone, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct SshConnectRequest {
|
|
pub host: String,
|
|
#[serde(default = "default_ssh_port")]
|
|
pub port: u16,
|
|
pub username: String,
|
|
pub password: Option<String>,
|
|
pub private_key: Option<String>,
|
|
pub passphrase: Option<String>,
|
|
pub proxy: Option<serde_json::Value>,
|
|
pub jump_host: Option<serde_json::Value>,
|
|
pub jump_hosts: Option<Vec<serde_json::Value>>,
|
|
pub timeout_seconds: Option<u64>,
|
|
pub keep_alive: Option<bool>,
|
|
}
|
|
|
|
fn default_ssh_port() -> u16 {
|
|
22
|
|
}
|
|
|
|
#[derive(Debug, Serialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct OperationResponse {
|
|
pub success: bool,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub error: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub error_code: Option<String>,
|
|
}
|
|
|
|
impl OperationResponse {
|
|
pub fn ok() -> Self {
|
|
Self {
|
|
success: true,
|
|
error: None,
|
|
error_code: None,
|
|
}
|
|
}
|
|
|
|
pub fn error(error: impl Into<String>) -> Self {
|
|
Self {
|
|
success: false,
|
|
error: Some(error.into()),
|
|
error_code: None,
|
|
}
|
|
}
|
|
|
|
pub fn coded(code: &'static str, error: impl Into<String>) -> Self {
|
|
Self {
|
|
success: false,
|
|
error: Some(error.into()),
|
|
error_code: Some(code.to_string()),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Serialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct IdResponse {
|
|
pub success: bool,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub connection_id: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub shell_id: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub sftp_id: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub error: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub error_code: Option<String>,
|
|
}
|
|
|
|
impl IdResponse {
|
|
pub fn connection(id: String) -> Self {
|
|
Self {
|
|
success: true,
|
|
connection_id: Some(id),
|
|
shell_id: None,
|
|
sftp_id: None,
|
|
error: None,
|
|
error_code: None,
|
|
}
|
|
}
|
|
|
|
pub fn shell(id: String) -> Self {
|
|
Self {
|
|
success: true,
|
|
connection_id: None,
|
|
shell_id: Some(id),
|
|
sftp_id: None,
|
|
error: None,
|
|
error_code: None,
|
|
}
|
|
}
|
|
|
|
pub fn sftp(id: String) -> Self {
|
|
Self {
|
|
success: true,
|
|
connection_id: None,
|
|
shell_id: None,
|
|
sftp_id: Some(id),
|
|
error: None,
|
|
error_code: None,
|
|
}
|
|
}
|
|
|
|
pub fn error(error: impl Into<String>) -> Self {
|
|
Self {
|
|
success: false,
|
|
connection_id: None,
|
|
shell_id: None,
|
|
sftp_id: None,
|
|
error: Some(error.into()),
|
|
error_code: None,
|
|
}
|
|
}
|
|
|
|
pub fn coded(code: &'static str, error: impl Into<String>) -> Self {
|
|
Self {
|
|
success: false,
|
|
connection_id: None,
|
|
shell_id: None,
|
|
sftp_id: None,
|
|
error: Some(error.into()),
|
|
error_code: Some(code.to_string()),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Serialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct ShellOutputResponse {
|
|
pub success: bool,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub data: Option<Vec<u8>>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub error: Option<String>,
|
|
}
|
|
|
|
impl ShellOutputResponse {
|
|
pub fn ok(data: Vec<u8>) -> Self {
|
|
Self {
|
|
success: true,
|
|
data: Some(data),
|
|
error: None,
|
|
}
|
|
}
|
|
|
|
pub fn error(error: impl Into<String>) -> Self {
|
|
Self {
|
|
success: false,
|
|
data: None,
|
|
error: Some(error.into()),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Serialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct ExecResponse {
|
|
pub success: bool,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub result: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub exit_code: Option<i32>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub error: Option<String>,
|
|
}
|
|
|
|
#[derive(Debug, Serialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct ForwardResponse {
|
|
pub success: bool,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub forward_id: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub bound_port: Option<u16>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub error: Option<String>,
|
|
}
|
|
|
|
impl ForwardResponse {
|
|
pub fn ok(forward_id: String, port: u16) -> Self {
|
|
Self {
|
|
success: true,
|
|
forward_id: Some(forward_id),
|
|
bound_port: Some(port),
|
|
error: None,
|
|
}
|
|
}
|
|
|
|
pub fn error(error: impl Into<String>) -> Self {
|
|
Self {
|
|
success: false,
|
|
forward_id: None,
|
|
bound_port: None,
|
|
error: Some(error.into()),
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Runtime state for a single forwarding listener. Persisted rules live in the
|
|
/// renderer settings; this structure deliberately represents process-local
|
|
/// state only.
|
|
#[derive(Debug, Clone, Serialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct ForwardStatus {
|
|
pub forward_id: String,
|
|
pub connection_id: String,
|
|
pub kind: String,
|
|
pub bind_host: String,
|
|
pub bound_port: u16,
|
|
pub target_host: Option<String>,
|
|
pub target_port: Option<u16>,
|
|
pub started_at: u64,
|
|
pub running: bool,
|
|
pub active_connections: u64,
|
|
pub bytes_up: u64,
|
|
pub bytes_down: u64,
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Clone)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct ShellDataEvent {
|
|
pub connection_id: String,
|
|
pub shell_id: String,
|
|
pub data: Vec<u8>,
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Clone)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct ShellClosedEvent {
|
|
pub connection_id: String,
|
|
pub shell_id: String,
|
|
pub reason: String,
|
|
pub idle_timeout: bool,
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Clone)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct ConnectionClosedEvent {
|
|
pub connection_id: String,
|
|
pub reason: String,
|
|
}
|
|
|
|
#[derive(Debug, Serialize)]
|
|
pub struct SftpFileAttrs {
|
|
pub mode: u32,
|
|
pub size: u64,
|
|
pub mtime: u64,
|
|
pub atime: u64,
|
|
}
|
|
|
|
#[derive(Debug, Serialize)]
|
|
pub struct SftpDirEntry {
|
|
pub filename: String,
|
|
pub longname: String,
|
|
pub attrs: SftpFileAttrs,
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Clone)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct SftpProgressEvent {
|
|
pub sftp_id: String,
|
|
pub transferred: u64,
|
|
pub total: u64,
|
|
pub percentage: u8,
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Clone)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct HostDiskMetric {
|
|
pub mount: String,
|
|
pub percent: u8,
|
|
pub used_kb: u64,
|
|
pub total_kb: u64,
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Clone)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct HostMetrics {
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub os_pretty_name: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub timezone: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub timezone_offset: Option<String>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub uptime_sec: Option<u64>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub cpu_percent: Option<f32>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub mem_used_kb: Option<u64>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub mem_total_kb: Option<u64>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub mem_percent: Option<u8>,
|
|
pub disks: Vec<HostDiskMetric>,
|
|
}
|
|
|
|
#[derive(Debug, Serialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct HostMetricsResponse {
|
|
pub success: bool,
|
|
/// True when another ssh_exec (e.g. Agent) holds the connection — caller should keep stale UI.
|
|
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
|
pub skipped: bool,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub metrics: Option<HostMetrics>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
pub error: Option<String>,
|
|
}
|
|
|
|
impl HostMetricsResponse {
|
|
pub fn ok(metrics: HostMetrics) -> Self {
|
|
Self {
|
|
success: true,
|
|
skipped: false,
|
|
metrics: Some(metrics),
|
|
error: None,
|
|
}
|
|
}
|
|
|
|
pub fn skipped() -> Self {
|
|
Self {
|
|
success: true,
|
|
skipped: true,
|
|
metrics: None,
|
|
error: None,
|
|
}
|
|
}
|
|
|
|
pub fn error(error: impl Into<String>) -> Self {
|
|
Self {
|
|
success: false,
|
|
skipped: false,
|
|
metrics: None,
|
|
error: Some(error.into()),
|
|
}
|
|
}
|
|
}
|