mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-15 17:01:02 +00:00
143 lines
4.4 KiB
Rust
143 lines
4.4 KiB
Rust
use std::collections::HashMap;
|
|
use std::path::PathBuf;
|
|
|
|
use serde::Deserialize;
|
|
use serde_json::Value;
|
|
use thiserror::Error;
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct LaunchSpec {
|
|
pub program: PathBuf,
|
|
pub args: Vec<String>,
|
|
pub env: HashMap<String, String>,
|
|
}
|
|
|
|
#[derive(Debug, Error)]
|
|
pub enum RegistryError {
|
|
#[error("invalid registry json: {0}")]
|
|
InvalidJson(#[from] serde_json::Error),
|
|
#[error("unable to resolve registry entry from blob")]
|
|
UnsupportedBlob,
|
|
#[error("registry blob has agents[] but no --registry-agent-id was provided")]
|
|
MissingAgentId,
|
|
#[error("agent '{0}' was not found in registry blob")]
|
|
AgentNotFound(String),
|
|
#[error("registry entry has no supported launch target")]
|
|
MissingLaunchTarget,
|
|
#[error("platform '{0}' is not present in distribution.binary")]
|
|
UnsupportedPlatform(String),
|
|
}
|
|
|
|
impl LaunchSpec {
|
|
pub fn from_registry_blob(blob: &str, agent_id: Option<&str>) -> Result<Self, RegistryError> {
|
|
let value: Value = serde_json::from_str(blob)?;
|
|
Self::from_registry_value(value, agent_id)
|
|
}
|
|
|
|
fn from_registry_value(value: Value, agent_id: Option<&str>) -> Result<Self, RegistryError> {
|
|
if value.get("agents").is_some() {
|
|
let doc: RegistryDocument = serde_json::from_value(value)?;
|
|
let wanted = agent_id.ok_or(RegistryError::MissingAgentId)?;
|
|
let agent = doc
|
|
.agents
|
|
.into_iter()
|
|
.find(|a| a.id == wanted)
|
|
.ok_or_else(|| RegistryError::AgentNotFound(wanted.to_string()))?;
|
|
return Self::from_distribution(agent.distribution);
|
|
}
|
|
|
|
if value.get("distribution").is_some() {
|
|
let entry: RegistryAgent = serde_json::from_value(value)?;
|
|
return Self::from_distribution(entry.distribution);
|
|
}
|
|
|
|
if value.get("npx").is_some() || value.get("binary").is_some() {
|
|
let distribution: RegistryDistribution = serde_json::from_value(value)?;
|
|
return Self::from_distribution(distribution);
|
|
}
|
|
|
|
Err(RegistryError::UnsupportedBlob)
|
|
}
|
|
|
|
fn from_distribution(distribution: RegistryDistribution) -> Result<Self, RegistryError> {
|
|
if let Some(npx) = distribution.npx {
|
|
let mut args = vec!["-y".to_string(), npx.package];
|
|
args.extend(npx.args);
|
|
return Ok(Self {
|
|
program: PathBuf::from("npx"),
|
|
args,
|
|
env: npx.env,
|
|
});
|
|
}
|
|
|
|
if let Some(binary) = distribution.binary {
|
|
let platform = platform_key().ok_or(RegistryError::UnsupportedPlatform(format!(
|
|
"{}/{}",
|
|
std::env::consts::OS,
|
|
std::env::consts::ARCH
|
|
)))?;
|
|
let target = binary
|
|
.get(platform)
|
|
.ok_or_else(|| RegistryError::UnsupportedPlatform(platform.to_string()))?;
|
|
return Ok(Self {
|
|
program: PathBuf::from(&target.cmd),
|
|
args: target.args.clone(),
|
|
env: target.env.clone(),
|
|
});
|
|
}
|
|
|
|
Err(RegistryError::MissingLaunchTarget)
|
|
}
|
|
}
|
|
|
|
fn platform_key() -> Option<&'static str> {
|
|
match (std::env::consts::OS, std::env::consts::ARCH) {
|
|
("linux", "x86_64") => Some("linux-x86_64"),
|
|
("linux", "aarch64") => Some("linux-aarch64"),
|
|
("macos", "x86_64") => Some("darwin-x86_64"),
|
|
("macos", "aarch64") => Some("darwin-aarch64"),
|
|
("windows", "x86_64") => Some("windows-x86_64"),
|
|
("windows", "aarch64") => Some("windows-aarch64"),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct RegistryDocument {
|
|
agents: Vec<RegistryAgent>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct RegistryAgent {
|
|
#[allow(dead_code)]
|
|
id: String,
|
|
distribution: RegistryDistribution,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct RegistryDistribution {
|
|
#[serde(default)]
|
|
npx: Option<RegistryNpx>,
|
|
#[serde(default)]
|
|
binary: Option<HashMap<String, RegistryBinaryTarget>>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct RegistryNpx {
|
|
package: String,
|
|
#[serde(default)]
|
|
args: Vec<String>,
|
|
#[serde(default)]
|
|
env: HashMap<String, String>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct RegistryBinaryTarget {
|
|
#[allow(dead_code)]
|
|
archive: Option<String>,
|
|
cmd: String,
|
|
#[serde(default)]
|
|
args: Vec<String>,
|
|
#[serde(default)]
|
|
env: HashMap<String, String>,
|
|
}
|