#![forbid(unsafe_code)]
use crate::ssh::ExecutionOutput;
use serde::{Deserialize, Serialize};
use super::exec_target::{ExecTarget, TargetEcho, TargetSource};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct ExecutionJson {
#[serde(flatten)]
pub target: TargetEcho,
#[serde(default)]
pub active_fallback: bool,
pub stdout: String,
pub stderr: String,
pub exit_code: Option<i32>,
pub truncated_stdout: bool,
pub truncated_stderr: bool,
pub duration_ms: u64,
}
impl ExecutionJson {
#[must_use]
pub fn with_target(o: &ExecutionOutput, target: &ExecTarget) -> Self {
Self {
target: TargetEcho::new(target),
active_fallback: target.source.is_ambient(),
stdout: o.stdout.clone(),
stderr: o.stderr.clone(),
exit_code: o.exit_code,
truncated_stdout: o.truncated_stdout,
truncated_stderr: o.truncated_stderr,
duration_ms: o.duration_ms,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct HealthCheckJson {
pub name: String,
#[serde(flatten)]
pub target: TargetEcho,
pub status: String,
pub latency_ms: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct HealthHostJson {
pub name: String,
pub status: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub latency_ms: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct HealthBatchJson {
pub event: String,
pub batch_run_id: String,
pub max_concurrency: u32,
pub results: Vec<HealthHostJson>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct ExecHostJson {
pub name: String,
pub ok: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub exit_code: Option<i32>,
pub stdout: String,
pub stderr: String,
pub duration_ms: u64,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct ExecBatchJson {
pub event: String,
pub batch_run_id: String,
pub max_concurrency: u32,
pub results: Vec<ExecHostJson>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct ScpHostJson {
pub name: String,
pub ok: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub bytes: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub duration_ms: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub local: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct ScpBatchJson {
pub event: String,
#[serde(default)]
pub target_source: TargetSource,
#[serde(default)]
pub host_source: TargetSource,
pub batch_run_id: String,
pub direction: String,
pub max_concurrency: u32,
pub results: Vec<ScpHostJson>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct ScpTransferJson {
pub ok: bool,
pub event: String,
#[serde(flatten)]
pub target: TargetEcho,
pub direction: String,
pub vps: String,
pub local: String,
pub remote: String,
pub bytes: u64,
pub duration_ms: u64,
#[serde(default = "default_true")]
pub mtime_preserved: bool,
#[serde(default = "default_true")]
pub durable: bool,
}
fn default_true() -> bool {
true
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct SftpTransferJson {
pub ok: bool,
pub event: String,
#[serde(flatten)]
pub target: TargetEcho,
pub direction: String,
pub vps: String,
pub local: String,
pub remote: String,
pub bytes: u64,
pub duration_ms: u64,
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
pub recursive: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct SftpListEntryJson {
pub name: String,
pub path: String,
pub kind: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub size: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mode: Option<u32>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct SftpListJson {
pub ok: bool,
pub event: String,
pub vps: String,
pub path: String,
pub entries: Vec<SftpListEntryJson>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct SftpFsOpJson {
pub ok: bool,
pub event: String,
pub op: String,
pub vps: String,
pub path: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub to: Option<String>,
pub duration_ms: u64,
#[serde(skip_serializing_if = "Option::is_none")]
pub kind: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub size: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mode: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mtime: Option<u32>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct SftpBatchJson {
pub event: String,
#[serde(default)]
pub target_source: TargetSource,
#[serde(default)]
pub host_source: TargetSource,
pub batch_run_id: String,
pub direction: String,
pub max_concurrency: u32,
pub results: Vec<ScpHostJson>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct TunnelListeningJson {
pub ok: bool,
pub event: String,
pub vps: String,
pub local_port: u16,
pub remote_host: String,
pub remote_port: u16,
pub timeout_ms: u64,
pub bind: String,
#[serde(default = "default_tunnel_mode")]
pub mode: String,
}
fn default_tunnel_mode() -> String {
"local".to_string()
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum TunnelCloseReason {
Deadline,
Signal,
AcceptError,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct TunnelClosedJson {
pub ok: bool,
pub event: String,
pub vps: String,
pub reason: TunnelCloseReason,
pub bind: String,
pub local_port: u16,
pub forwards_served: u64,
pub capacity_waits: u64,
pub duration_ms: u64,
#[serde(default = "default_tunnel_mode")]
pub mode: String,
}
#[cfg(test)]
#[path = "execution_tests.rs"]
mod tests;