Files
IdeA/crates/domain/src/remote.rs
Blomios 307ae71857 feat: add main features
Agents for developpement added + frontend add + backend added. Git viewer created + agent and template creator + layout and project creator
2026-06-06 01:27:01 +02:00

129 lines
3.8 KiB
Rust

//! Remote-location value objects: the strategy that locates where a project's
//! filesystem and processes actually live (local, SSH, or WSL).
use serde::{Deserialize, Serialize};
use crate::error::DomainError;
/// SSH authentication strategy.
///
/// The domain only models *which* strategy is selected; resolving keys,
/// agents or known-hosts is an infrastructure concern.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", tag = "type")]
pub enum SshAuth {
/// Use the running SSH agent.
Agent,
/// Use a private-key file at the given (remote-machine-agnostic) path.
Key {
/// Path to the private key on the local machine.
path: String,
},
/// Interactive / stored password authentication.
Password,
}
/// Strategy describing where a project is physically located and executed.
///
/// Invariants:
/// - `Ssh.port` ∈ `1..=65535`,
/// - `Ssh.host` / `Ssh.user` / `Ssh.remote_root` non-empty,
/// - `Wsl.distro` non-empty.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", tag = "kind")]
pub enum RemoteRef {
/// The local machine.
Local,
/// A remote host reached over SSH.
#[serde(rename_all = "camelCase")]
Ssh {
/// Hostname or IP.
host: String,
/// TCP port (`1..=65535`).
port: u16,
/// Remote user.
user: String,
/// Authentication strategy.
auth: SshAuth,
/// Absolute root path on the remote machine.
remote_root: String,
},
/// A Windows Subsystem for Linux distribution.
Wsl {
/// Distribution name (e.g. `Ubuntu-22.04`).
distro: String,
},
}
impl RemoteRef {
/// Convenience constructor for the local machine.
#[must_use]
pub const fn local() -> Self {
Self::Local
}
/// Validated constructor for an SSH remote.
///
/// # Errors
/// Returns [`DomainError`] if the port is `0`, or if `host`, `user` or
/// `remote_root` is empty.
pub fn ssh(
host: impl Into<String>,
port: u16,
user: impl Into<String>,
auth: SshAuth,
remote_root: impl Into<String>,
) -> Result<Self, DomainError> {
let host = host.into();
let user = user.into();
let remote_root = remote_root.into();
crate::validation::non_empty(&host, "ssh.host")?;
crate::validation::non_empty(&user, "ssh.user")?;
crate::validation::non_empty(&remote_root, "ssh.remote_root")?;
// u16 already bounds the upper end; only port 0 is invalid.
if port == 0 {
return Err(DomainError::InvalidPort { port: 0 });
}
Ok(Self::Ssh {
host,
port,
user,
auth,
remote_root,
})
}
/// Validated constructor for a WSL remote.
///
/// # Errors
/// Returns [`DomainError`] if `distro` is empty.
pub fn wsl(distro: impl Into<String>) -> Result<Self, DomainError> {
let distro = distro.into();
crate::validation::non_empty(&distro, "wsl.distro")?;
Ok(Self::Wsl { distro })
}
/// Returns the coarse kind of this remote, for adapter selection.
#[must_use]
pub fn kind(&self) -> RemoteKind {
match self {
Self::Local => RemoteKind::Local,
Self::Ssh { .. } => RemoteKind::Ssh,
Self::Wsl { .. } => RemoteKind::Wsl,
}
}
}
/// Coarse discriminant used by the [`crate::ports::RemoteHost`] port to advertise
/// its kind without exposing connection details.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum RemoteKind {
/// Local execution.
Local,
/// SSH remote.
Ssh,
/// WSL distribution.
Wsl,
}