use std::io::{BufRead, BufReader, Write};
use std::path::{Path, PathBuf};
use serde_json::Value;
pub const NODE_BIN_ENV: &str = "SUPERCODE_NODE_BIN";
pub const SOCKET_FILE: &str = "orchestrator.sock";
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Door {
Live,
Cold,
}
impl Door {
pub const fn as_str(self) -> &'static str {
match self {
Self::Live => "live",
Self::Cold => "cold",
}
}
}
#[derive(Debug, Clone)]
pub struct DoorAnswer {
pub ran: String,
pub door: Door,
pub result: Value,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DoorError {
Refused(String),
Failed(String),
}
impl std::fmt::Display for DoorError {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Refused(message) | Self::Failed(message) => formatter.write_str(message),
}
}
}
impl std::error::Error for DoorError {}
type Result<T> = std::result::Result<T, DoorError>;
pub fn socket_path(root: &Path) -> PathBuf {
root.join(SOCKET_FILE)
}
pub fn daemon_is_live(root: &Path) -> bool {
crate::orchestrator::live_lease(root).is_some() && socket_path(root).exists()
}
pub fn call(root: &Path, op: &str, args: &Value, profile: &str) -> Result<DoorAnswer> {
if daemon_is_live(root) {
match call_live(root, op, args, profile) {
Ok(answer) => return Ok(answer),
Err(DoorError::Refused(message)) => return Err(DoorError::Refused(message)),
Err(DoorError::Failed(_)) => {}
}
}
call_cold(root, op, args, profile)
}
fn narrate_live(root: &Path, op: &str, args: &Value, profile: &str) -> String {
format!(
"{} {op} --profile {profile} --json {}",
socket_path(root).display(),
shell_quote(&args.to_string())
)
}
#[cfg(unix)]
fn call_live(root: &Path, op: &str, args: &Value, profile: &str) -> Result<DoorAnswer> {
use std::os::unix::net::UnixStream;
let ran = narrate_live(root, op, args, profile);
let path = socket_path(root);
let mut stream = UnixStream::connect(&path).map_err(|error| {
DoorError::Failed(format!(
"the orchestrator daemon is leased for `{}` but its socket `{}` did not accept a \
connection: {error}",
root.display(),
path.display()
))
})?;
let line = serde_json::json!({"op": op, "args": args, "profile": profile});
stream
.write_all(format!("{line}\n").as_bytes())
.and_then(|()| stream.flush())
.map_err(|error| DoorError::Failed(format!("`{ran}` could not be sent: {error}")))?;
let mut reader = BufReader::new(stream);
let mut answer = String::new();
reader
.read_line(&mut answer)
.map_err(|error| DoorError::Failed(format!("`{ran}` was not answered: {error}")))?;
if answer.trim().is_empty() {
return Err(DoorError::Failed(format!(
"`{ran}`: the orchestrator closed the connection without answering"
)));
}
interpret(&ran, Door::Live, answer.trim())
}
#[cfg(not(unix))]
fn call_live(root: &Path, op: &str, args: &Value, profile: &str) -> Result<DoorAnswer> {
Err(DoorError::Failed(format!(
"`{}`: the daemon's door is a Unix socket, which this platform has no client for; the \
cold path answers instead",
narrate_live(root, op, args, profile)
)))
}
fn call_cold(root: &Path, op: &str, args: &Value, profile: &str) -> Result<DoorAnswer> {
let entry = crate::orchestrator::daemon_entry().map_err(|error| {
DoorError::Failed(format!(
"the orchestrator's write door is its own package, and it could not be located: \
{error}"
))
})?;
let node = std::env::var_os(NODE_BIN_ENV)
.map(|value| value.to_string_lossy().trim().to_string())
.filter(|value| !value.is_empty())
.unwrap_or_else(|| "node".to_string());
let payload = args.to_string();
let arguments = vec![
entry.to_string_lossy().into_owned(),
op.to_string(),
"--root".to_string(),
root.to_string_lossy().into_owned(),
"--profile".to_string(),
profile.to_string(),
"--json".to_string(),
payload,
];
let ran = std::iter::once(node.clone())
.chain(arguments.iter().cloned())
.map(|part| shell_quote(&part))
.collect::<Vec<_>>()
.join(" ");
let output = std::process::Command::new(&node)
.args(&arguments)
.stdin(std::process::Stdio::null())
.output()
.map_err(|error| DoorError::Failed(format!("`{ran}` could not be executed: {error}")))?;
let stdout = String::from_utf8_lossy(&output.stdout).into_owned();
let last = stdout.lines().rev().find(|line| !line.trim().is_empty());
let Some(last) = last else {
let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
return Err(DoorError::Failed(format!(
"`{ran}` printed nothing ({}){}",
output.status,
if stderr.is_empty() {
String::new()
} else {
format!(": {stderr}")
}
)));
};
interpret(&ran, Door::Cold, last.trim())
}
fn interpret(ran: &str, door: Door, line: &str) -> Result<DoorAnswer> {
let value: Value = serde_json::from_str(line).map_err(|error| {
DoorError::Failed(format!(
"`{ran}` answered something that is not JSON: {error}"
))
})?;
if value.get("ok").and_then(Value::as_bool) == Some(true) {
return Ok(DoorAnswer {
ran: ran.to_string(),
door,
result: value.get("result").cloned().unwrap_or(Value::Null),
});
}
Err(DoorError::Refused(
value
.get("error")
.and_then(Value::as_str)
.map(str::to_string)
.unwrap_or_else(|| format!("`{ran}` answered `{line}`")),
))
}
fn shell_quote(value: &str) -> String {
if !value.is_empty()
&& value
.chars()
.all(|c| c.is_ascii_alphanumeric() || "-_./:@=+,".contains(c))
{
return value.to_string();
}
format!("'{}'", value.replace('\'', "'\\''"))
}
#[cfg(test)]
mod tests {
use super::*;
fn scratch(label: &str) -> PathBuf {
let root = std::env::temp_dir().join(format!(
"supercode-orc13-{label}-{}-{}",
std::process::id(),
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos()
));
std::fs::create_dir_all(&root).unwrap();
root
}
#[test]
fn a_home_without_a_live_lease_is_not_live() {
let root = scratch("live");
assert!(!daemon_is_live(&root));
crate::orchestrator::write_lease(
&root,
&crate::orchestrator::Lease {
pid: std::process::id(),
started_at: "2026-09-04T00:00:00Z".into(),
root: root.clone(),
},
)
.unwrap();
assert!(!daemon_is_live(&root), "a lease without a socket is not up");
std::fs::write(socket_path(&root), b"").unwrap();
assert!(daemon_is_live(&root));
std::fs::remove_dir_all(&root).ok();
}
#[test]
fn a_refusal_carries_the_packages_own_sentence() {
let error = interpret(
"node entry jobs.delete",
Door::Cold,
r#"{"ok":false,"error":"jobs_delete: no job job_x"}"#,
)
.unwrap_err();
assert_eq!(
error,
DoorError::Refused("jobs_delete: no job job_x".into())
);
}
#[test]
fn an_ok_line_yields_the_packages_result() {
let answer = interpret(
"node entry jobs.create",
Door::Cold,
r#"{"ok":true,"result":{"ran":"created cron job a","job_id":"a"}}"#,
)
.unwrap();
assert_eq!(answer.door, Door::Cold);
assert_eq!(
answer.result.pointer("/job_id").and_then(Value::as_str),
Some("a")
);
}
#[test]
fn the_cold_path_runs_the_packages_cli_and_refuses_a_home_that_does_not_load() {
let root = scratch("cold").join("not-a-home");
let error = call(
&root,
"jobs.delete",
&serde_json::json!({"id": "x"}),
"default",
)
.unwrap_err();
let message = error.to_string();
assert!(
message.contains("not a directory") || message.contains("could not be executed"),
"{message}"
);
std::fs::remove_dir_all(root.parent().unwrap()).ok();
}
}