From 2568bfde5e94bac25e3e8353daeb6943bdc4bca9 Mon Sep 17 00:00:00 2001 From: Aiden McClelland Date: Fri, 31 May 2024 13:46:58 -0600 Subject: [PATCH] create skeleton --- Makefile | 2 +- core/build-analyticsd.sh | 42 ++++++ core/{build-reg.sh => build-registrybox.sh} | 0 core/{build-prod.sh => build-startos-bins.sh} | 0 core/startos/Cargo.toml | 7 +- core/startos/src/analytics/context.rs | 121 ++++++++++++++++++ core/startos/src/analytics/mod.rs | 78 +++++++++++ core/startos/src/bins/analyticsd.rs | 86 +++++++++++++ core/startos/src/bins/mod.rs | 4 + core/startos/src/context/config.rs | 3 + core/startos/src/context/rpc.rs | 5 + core/startos/src/lib.rs | 9 +- core/startos/src/lxc/dev.rs | 112 ++++++++++++++++ core/startos/src/lxc/mod.rs | 117 +---------------- core/startos/src/os_install/mod.rs | 4 + core/startos/src/registry/context.rs | 21 ++- sdk/lib/osBindings/AddAssetParams.ts | 1 - sdk/lib/osBindings/AddPackageParams.ts | 9 ++ sdk/lib/osBindings/GetPackageResponse.ts | 1 + sdk/lib/osBindings/GetPackageResponseFull.ts | 1 + sdk/lib/osBindings/HardwareRequirements.ts | 2 +- sdk/lib/osBindings/OsVersionInfo.ts | 2 +- sdk/lib/osBindings/PackageInfo.ts | 3 +- sdk/lib/osBindings/PackageVersionInfo.ts | 1 - sdk/lib/osBindings/index.ts | 1 + 25 files changed, 508 insertions(+), 124 deletions(-) create mode 100755 core/build-analyticsd.sh rename core/{build-reg.sh => build-registrybox.sh} (100%) rename core/{build-prod.sh => build-startos-bins.sh} (100%) create mode 100644 core/startos/src/analytics/context.rs create mode 100644 core/startos/src/analytics/mod.rs create mode 100644 core/startos/src/bins/analyticsd.rs create mode 100644 core/startos/src/lxc/dev.rs create mode 100644 sdk/lib/osBindings/AddPackageParams.ts diff --git a/Makefile b/Makefile index ff5b9c4ad..7b488d2d2 100644 --- a/Makefile +++ b/Makefile @@ -225,7 +225,7 @@ system-images/binfmt/docker-images/$(ARCH).tar: $(BINFMT_SRC) cd system-images/binfmt && make docker-images/$(ARCH).tar && touch docker-images/$(ARCH).tar $(BINS): $(CORE_SRC) $(ENVIRONMENT_FILE) - cd core && ARCH=$(ARCH) ./build-prod.sh + cd core && ARCH=$(ARCH) ./build-startos-bins.sh touch $(BINS) web/node_modules/.package-lock.json: web/package.json sdk/dist diff --git a/core/build-analyticsd.sh b/core/build-analyticsd.sh new file mode 100755 index 000000000..4f8578da1 --- /dev/null +++ b/core/build-analyticsd.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +cd "$(dirname "${BASH_SOURCE[0]}")" + +set -e +shopt -s expand_aliases + +if [ -z "$ARCH" ]; then + ARCH=$(uname -m) +fi + +USE_TTY= +if tty -s; then + USE_TTY="-it" +fi + +cd .. +FEATURES="$(echo $ENVIRONMENT | sed 's/-/,/g')" +RUSTFLAGS="" + +if [[ "${ENVIRONMENT}" =~ (^|-)unstable($|-) ]]; then + RUSTFLAGS="--cfg tokio_unstable" +fi + +alias 'rust-musl-builder'='docker run $USE_TTY --rm -e "RUSTFLAGS=$RUSTFLAGS" -v "$HOME/.cargo/registry":/root/.cargo/registry -v "$HOME/.cargo/git":/root/.cargo/git -v "$(pwd)":/home/rust/src -w /home/rust/src -P messense/rust-musl-cross:$ARCH-musl' + +set +e +fail= +echo "FEATURES=\"$FEATURES\"" +echo "RUSTFLAGS=\"$RUSTFLAGS\"" +if ! rust-musl-builder sh -c "(cd core && cargo build --release --no-default-features --features analyticsd,$FEATURES --locked --bin analyticsd --target=$ARCH-unknown-linux-musl)"; then + fail=true +fi +set -e +cd core + +sudo chown -R $USER target +sudo chown -R $USER ~/.cargo + +if [ -n "$fail" ]; then + exit 1 +fi diff --git a/core/build-reg.sh b/core/build-registrybox.sh similarity index 100% rename from core/build-reg.sh rename to core/build-registrybox.sh diff --git a/core/build-prod.sh b/core/build-startos-bins.sh similarity index 100% rename from core/build-prod.sh rename to core/build-startos-bins.sh diff --git a/core/startos/Cargo.toml b/core/startos/Cargo.toml index bd064a167..fa2bac69d 100644 --- a/core/startos/Cargo.toml +++ b/core/startos/Cargo.toml @@ -37,12 +37,17 @@ path = "src/main.rs" name = "registrybox" path = "src/main.rs" +[[bin]] +name = "analyticsd" +path = "src/main.rs" + [features] cli = [] container-runtime = [] daemon = [] registry = [] -default = ["cli", "daemon", "registry"] +analyticsd = [] +default = ["cli", "daemon"] dev = [] unstable = ["console-subscriber", "tokio/tracing"] docker = [] diff --git a/core/startos/src/analytics/context.rs b/core/startos/src/analytics/context.rs new file mode 100644 index 000000000..8ece8479b --- /dev/null +++ b/core/startos/src/analytics/context.rs @@ -0,0 +1,121 @@ +use std::net::{Ipv4Addr, SocketAddr}; +use std::ops::Deref; +use std::path::PathBuf; +use std::sync::Arc; + +use clap::Parser; +use reqwest::{Client, Proxy}; +use rpc_toolkit::yajrc::RpcError; +use rpc_toolkit::{call_remote_http, CallRemote, Context, Empty}; +use serde::{Deserialize, Serialize}; +use sqlx::PgPool; +use tokio::sync::broadcast::Sender; +use tracing::instrument; +use url::Url; + +use crate::context::config::{ContextConfig, CONFIG_PATH}; +use crate::context::RpcContext; +use crate::prelude::*; +use crate::rpc_continuations::RpcContinuations; + +#[derive(Debug, Clone, Default, Deserialize, Serialize, Parser)] +#[serde(rename_all = "kebab-case")] +#[command(rename_all = "kebab-case")] +pub struct AnalyticsConfig { + #[arg(short = 'c', long = "config")] + pub config: Option, + #[arg(short = 'l', long = "listen")] + pub listen: Option, + #[arg(short = 'p', long = "proxy")] + pub tor_proxy: Option, + #[arg(short = 'd', long = "dbconnect")] + pub dbconnect: Option, +} +impl ContextConfig for AnalyticsConfig { + fn next(&mut self) -> Option { + self.config.take() + } + fn merge_with(&mut self, other: Self) { + self.listen = self.listen.take().or(other.listen); + self.tor_proxy = self.tor_proxy.take().or(other.tor_proxy); + self.dbconnect = self.dbconnect.take().or(other.dbconnect); + } +} + +impl AnalyticsConfig { + pub fn load(mut self) -> Result { + let path = self.next(); + self.load_path_rec(path)?; + self.load_path_rec(Some(CONFIG_PATH))?; + Ok(self) + } +} + +pub struct AnalyticsContextSeed { + pub listen: SocketAddr, + pub db: PgPool, + pub rpc_continuations: RpcContinuations, + pub client: Client, + pub shutdown: Sender<()>, +} + +#[derive(Clone)] +pub struct AnalyticsContext(Arc); +impl AnalyticsContext { + #[instrument(skip_all)] + pub async fn init(config: &AnalyticsConfig) -> Result { + let (shutdown, _) = tokio::sync::broadcast::channel(1); + let dbconnect = config + .dbconnect + .clone() + .unwrap_or_else(|| "postgres://localhost/analytics".parse().unwrap()) + .to_owned(); + let db = PgPool::connect(dbconnect.as_str()).await?; + let tor_proxy_url = config + .tor_proxy + .clone() + .map(Ok) + .unwrap_or_else(|| "socks5h://localhost:9050".parse())?; + Ok(Self(Arc::new(AnalyticsContextSeed { + listen: config + .listen + .unwrap_or(SocketAddr::new(Ipv4Addr::LOCALHOST.into(), 5959)), + db, + rpc_continuations: RpcContinuations::new(), + client: Client::builder() + .proxy(Proxy::custom(move |url| { + if url.host_str().map_or(false, |h| h.ends_with(".onion")) { + Some(tor_proxy_url.clone()) + } else { + None + } + })) + .build() + .with_kind(crate::ErrorKind::ParseUrl)?, + shutdown, + }))) + } +} +impl AsRef for AnalyticsContext { + fn as_ref(&self) -> &RpcContinuations { + &self.rpc_continuations + } +} + +impl Context for AnalyticsContext {} +impl Deref for AnalyticsContext { + type Target = AnalyticsContextSeed; + fn deref(&self) -> &Self::Target { + &*self.0 + } +} + +impl CallRemote for RpcContext { + async fn call_remote(&self, method: &str, params: Value, _: Empty) -> Result { + if let Some(analytics_url) = self.analytics_url.clone() { + call_remote_http(&self.client, analytics_url, method, params).await + } else { + Ok(Value::Null) + } + } +} diff --git a/core/startos/src/analytics/mod.rs b/core/startos/src/analytics/mod.rs new file mode 100644 index 000000000..52ca37948 --- /dev/null +++ b/core/startos/src/analytics/mod.rs @@ -0,0 +1,78 @@ +use std::net::SocketAddr; + +use axum::Router; +use futures::future::ready; +use rpc_toolkit::{Context, ParentHandler, Server}; + +use crate::analytics::context::AnalyticsContext; +use crate::middleware::cors::Cors; +use crate::net::static_server::{bad_request, not_found, server_error}; +use crate::net::web_server::WebServer; +use crate::rpc_continuations::Guid; + +pub mod context; + +pub fn analytics_api() -> ParentHandler { + ParentHandler::new() // TODO: FullMetal +} + +pub fn analytics_server_router(ctx: AnalyticsContext) -> Router { + use axum::extract as x; + use axum::routing::{any, get, post}; + Router::new() + .route("/rpc/*path", { + let ctx = ctx.clone(); + post( + Server::new(move || ready(Ok(ctx.clone())), analytics_api()) + .middleware(Cors::new()) + ) + }) + .route( + "/ws/rpc/*path", + get({ + let ctx = ctx.clone(); + move |x::Path(path): x::Path, + ws: axum::extract::ws::WebSocketUpgrade| async move { + match Guid::from(&path) { + None => { + tracing::debug!("No Guid Path"); + bad_request() + } + Some(guid) => match ctx.rpc_continuations.get_ws_handler(&guid).await { + Some(cont) => ws.on_upgrade(cont), + _ => not_found(), + }, + } + } + }), + ) + .route( + "/rest/rpc/*path", + any({ + let ctx = ctx.clone(); + move |request: x::Request| async move { + let path = request + .uri() + .path() + .strip_prefix("/rest/rpc/") + .unwrap_or_default(); + match Guid::from(&path) { + None => { + tracing::debug!("No Guid Path"); + bad_request() + } + Some(guid) => match ctx.rpc_continuations.get_rest_handler(&guid).await { + None => not_found(), + Some(cont) => cont(request).await.unwrap_or_else(server_error), + }, + } + } + }), + ) +} + +impl WebServer { + pub fn analytics(bind: SocketAddr, ctx: AnalyticsContext) -> Self { + Self::new(bind, analytics_server_router(ctx)) + } +} diff --git a/core/startos/src/bins/analyticsd.rs b/core/startos/src/bins/analyticsd.rs new file mode 100644 index 000000000..e37a7dae1 --- /dev/null +++ b/core/startos/src/bins/analyticsd.rs @@ -0,0 +1,86 @@ +use std::ffi::OsString; + +use clap::Parser; +use futures::FutureExt; +use tokio::signal::unix::signal; +use tracing::instrument; + +use crate::analytics::context::{AnalyticsConfig, AnalyticsContext}; +use crate::net::web_server::WebServer; +use crate::prelude::*; +use crate::util::logger::EmbassyLogger; + +#[instrument(skip_all)] +async fn inner_main(config: &AnalyticsConfig) -> Result<(), Error> { + let server = async { + let ctx = AnalyticsContext::init(config).await?; + let server = WebServer::analytics(ctx.listen, ctx.clone()); + + let mut shutdown_recv = ctx.shutdown.subscribe(); + + let sig_handler_ctx = ctx; + let sig_handler = tokio::spawn(async move { + use tokio::signal::unix::SignalKind; + futures::future::select_all( + [ + SignalKind::interrupt(), + SignalKind::quit(), + SignalKind::terminate(), + ] + .iter() + .map(|s| { + async move { + signal(*s) + .unwrap_or_else(|_| panic!("register {:?} handler", s)) + .recv() + .await + } + .boxed() + }), + ) + .await; + sig_handler_ctx + .shutdown + .send(()) + .map_err(|_| ()) + .expect("send shutdown signal"); + }); + + shutdown_recv + .recv() + .await + .with_kind(crate::ErrorKind::Unknown)?; + + sig_handler.abort(); + + Ok::<_, Error>(server) + } + .await?; + server.shutdown().await; + + Ok(()) +} + +pub fn main(args: impl IntoIterator) { + EmbassyLogger::init(); + + let config = AnalyticsConfig::parse_from(args).load().unwrap(); + + let res = { + let rt = tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .expect("failed to initialize runtime"); + rt.block_on(inner_main(&config)) + }; + + match res { + Ok(()) => (), + Err(e) => { + eprintln!("{}", e.source); + tracing::debug!("{:?}", e.source); + drop(e.source); + std::process::exit(e.kind as i32) + } + } +} diff --git a/core/startos/src/bins/mod.rs b/core/startos/src/bins/mod.rs index 4a4670a5b..70f87aa99 100644 --- a/core/startos/src/bins/mod.rs +++ b/core/startos/src/bins/mod.rs @@ -2,6 +2,8 @@ use std::collections::VecDeque; use std::ffi::OsString; use std::path::Path; +#[cfg(feature = "analytics")] +pub mod analytics; #[cfg(feature = "container-runtime")] pub mod container_cli; pub mod deprecated; @@ -24,6 +26,8 @@ fn select_executable(name: &str) -> Option)> { "startd" => Some(startd::main), #[cfg(feature = "registry")] "registry" => Some(registry::main), + #[cfg(feature = "analyticsd")] + "analyticsd" => Some(analyticsd::main), "embassy-cli" => Some(|_| deprecated::renamed("embassy-cli", "start-cli")), "embassy-sdk" => Some(|_| deprecated::renamed("embassy-sdk", "start-sdk")), "embassyd" => Some(|_| deprecated::renamed("embassyd", "startd")), diff --git a/core/startos/src/context/config.rs b/core/startos/src/context/config.rs index bc2da00e2..886361777 100644 --- a/core/startos/src/context/config.rs +++ b/core/startos/src/context/config.rs @@ -113,6 +113,8 @@ pub struct ServerConfig { pub datadir: Option, #[arg(long = "disable-encryption")] pub disable_encryption: Option, + #[arg(short = 'a', long = "analytics-url")] + pub analytics_url: Option, } impl ContextConfig for ServerConfig { fn next(&mut self) -> Option { @@ -131,6 +133,7 @@ impl ContextConfig for ServerConfig { .or(other.revision_cache_size); self.datadir = self.datadir.take().or(other.datadir); self.disable_encryption = self.disable_encryption.take().or(other.disable_encryption); + self.analytics_url = self.analytics_url.take().or(other.analytics_url); } } diff --git a/core/startos/src/context/rpc.rs b/core/startos/src/context/rpc.rs index cf2d28085..1042def74 100644 --- a/core/startos/src/context/rpc.rs +++ b/core/startos/src/context/rpc.rs @@ -13,6 +13,7 @@ use rpc_toolkit::{CallRemote, Context, Empty}; use tokio::sync::{broadcast, oneshot, Mutex, RwLock}; use tokio::time::Instant; use tracing::instrument; +use url::Url; use super::setup::CURRENT_SECRET; use crate::account::AccountInfo; @@ -55,7 +56,9 @@ pub struct RpcContextSeed { pub client: Client, pub hardware: Hardware, pub start_time: Instant, + #[cfg(feature = "dev")] pub dev: Dev, + pub analytics_url: Option, } pub struct Dev { @@ -184,9 +187,11 @@ impl RpcContext { .with_kind(crate::ErrorKind::ParseUrl)?, hardware: Hardware { devices, ram }, start_time: Instant::now(), + #[cfg(feature = "dev")] dev: Dev { lxc: Mutex::new(BTreeMap::new()), }, + analytics_url: config.analytics_url.clone(), }); let res = Self(seed.clone()); diff --git a/core/startos/src/lib.rs b/core/startos/src/lib.rs index d60a2db24..96210114f 100644 --- a/core/startos/src/lib.rs +++ b/core/startos/src/lib.rs @@ -24,6 +24,7 @@ lazy_static::lazy_static! { pub mod account; pub mod action; +pub mod analytics; pub mod auth; pub mod backup; pub mod bins; @@ -95,7 +96,7 @@ pub fn echo(_: C, EchoParams { message }: EchoParams) -> Result() -> ParentHandler { - ParentHandler::new() + let api = ParentHandler::new() .subcommand::("git-info", from_fn(version::git_info)) .subcommand( "echo", @@ -120,9 +121,11 @@ pub fn main_api() -> ParentHandler { ) .no_cli(), ) - .subcommand("lxc", lxc::lxc::()) .subcommand("s9pk", s9pk::rpc::s9pk()) - .subcommand("util", util::rpc::util::()) + .subcommand("util", util::rpc::util::()); + #[cfg(feature = "dev")] + let api = api.subcommand("lxc", lxc::dev::lxc::()); + api } pub fn server() -> ParentHandler { diff --git a/core/startos/src/lxc/dev.rs b/core/startos/src/lxc/dev.rs new file mode 100644 index 000000000..61dd8e598 --- /dev/null +++ b/core/startos/src/lxc/dev.rs @@ -0,0 +1,112 @@ +use std::ops::Deref; + +use clap::Parser; +use rpc_toolkit::{ + from_fn_async, CallRemoteHandler, Context, Empty, HandlerArgs, HandlerExt, HandlerFor, + ParentHandler, +}; +use serde::{Deserialize, Serialize}; +use ts_rs::TS; + +use crate::context::{CliContext, RpcContext}; +use crate::lxc::{ContainerId, LxcConfig}; +use crate::prelude::*; +use crate::rpc_continuations::Guid; + +pub fn lxc() -> ParentHandler { + ParentHandler::new() + .subcommand( + "create", + from_fn_async(create).with_call_remote::(), + ) + .subcommand( + "list", + from_fn_async(list) + .with_custom_display_fn(|_, res| { + use prettytable::*; + let mut table = table!([bc => "GUID"]); + for guid in res { + table.add_row(row![&*guid]); + } + table.printstd(); + Ok(()) + }) + .with_call_remote::(), + ) + .subcommand( + "remove", + from_fn_async(remove) + .no_display() + .with_call_remote::(), + ) + .subcommand("connect", from_fn_async(connect_rpc).no_cli()) + .subcommand("connect", from_fn_async(connect_rpc_cli).no_display()) +} + +pub async fn create(ctx: RpcContext) -> Result { + let container = ctx.lxc_manager.create(None, LxcConfig::default()).await?; + let guid = container.guid.deref().clone(); + ctx.dev.lxc.lock().await.insert(guid.clone(), container); + Ok(guid) +} + +pub async fn list(ctx: RpcContext) -> Result, Error> { + Ok(ctx.dev.lxc.lock().await.keys().cloned().collect()) +} + +#[derive(Deserialize, Serialize, Parser, TS)] +pub struct RemoveParams { + #[ts(type = "string")] + pub guid: ContainerId, +} + +pub async fn remove(ctx: RpcContext, RemoveParams { guid }: RemoveParams) -> Result<(), Error> { + if let Some(container) = ctx.dev.lxc.lock().await.remove(&guid) { + container.exit().await?; + } + Ok(()) +} + +#[derive(Deserialize, Serialize, Parser, TS)] +pub struct ConnectParams { + #[ts(type = "string")] + pub guid: ContainerId, +} + +pub async fn connect_rpc( + ctx: RpcContext, + ConnectParams { guid }: ConnectParams, +) -> Result { + super::connect( + &ctx, + ctx.dev.lxc.lock().await.get(&guid).ok_or_else(|| { + Error::new(eyre!("No container with guid: {guid}"), ErrorKind::NotFound) + })?, + ) + .await +} + +pub async fn connect_rpc_cli( + HandlerArgs { + context, + parent_method, + method, + params, + inherited_params, + raw_params, + }: HandlerArgs, +) -> Result<(), Error> { + let ctx = context.clone(); + let guid = CallRemoteHandler::::new(from_fn_async(connect_rpc)) + .handle_async(HandlerArgs { + context, + parent_method, + method, + params: rpc_toolkit::util::Flat(params, Empty {}), + inherited_params, + raw_params, + }) + .await?; + + super::connect_cli(&ctx, guid).await +} diff --git a/core/startos/src/lxc/mod.rs b/core/startos/src/lxc/mod.rs index f64ecebe7..997c17c8a 100644 --- a/core/startos/src/lxc/mod.rs +++ b/core/startos/src/lxc/mod.rs @@ -1,20 +1,15 @@ use std::collections::BTreeSet; use std::net::Ipv4Addr; -use std::ops::Deref; use std::path::Path; use std::sync::{Arc, Weak}; use std::time::Duration; use clap::builder::ValueParserFactory; -use clap::Parser; use futures::{AsyncWriteExt, FutureExt, StreamExt}; use imbl_value::{InOMap, InternedString}; use models::InvalidId; -use rpc_toolkit::yajrc::{RpcError, RpcResponse}; -use rpc_toolkit::{ - from_fn_async, CallRemoteHandler, Context, Empty, GenericRpcMethod, HandlerArgs, HandlerExt, - HandlerFor, ParentHandler, RpcRequest, -}; +use rpc_toolkit::yajrc::RpcError; +use rpc_toolkit::{GenericRpcMethod, RpcRequest, RpcResponse}; use rustyline_async::{ReadlineEvent, SharedWriter}; use serde::{Deserialize, Serialize}; use tokio::fs::File; @@ -38,6 +33,9 @@ use crate::util::clap::FromStrParser; use crate::util::rpc_client::UnixRpcClient; use crate::util::{new_guid, Invoke}; +#[cfg(feature = "dev")] +pub mod dev; + const LXC_CONTAINER_DIR: &str = "/var/lib/lxc"; const RPC_DIR: &str = "media/startos/rpc"; // must not be absolute path pub const CONTAINER_RPC_SERVER_SOCKET: &str = "service.sock"; // must not be absolute path @@ -369,80 +367,6 @@ impl Drop for LxcContainer { #[derive(Default, Serialize)] pub struct LxcConfig {} - -pub fn lxc() -> ParentHandler { - ParentHandler::new() - .subcommand( - "create", - from_fn_async(create).with_call_remote::(), - ) - .subcommand( - "list", - from_fn_async(list) - .with_custom_display_fn(|_, res| { - use prettytable::*; - let mut table = table!([bc => "GUID"]); - for guid in res { - table.add_row(row![&*guid]); - } - table.printstd(); - Ok(()) - }) - .with_call_remote::(), - ) - .subcommand( - "remove", - from_fn_async(remove) - .no_display() - .with_call_remote::(), - ) - .subcommand("connect", from_fn_async(connect_rpc).no_cli()) - .subcommand("connect", from_fn_async(connect_rpc_cli).no_display()) -} - -pub async fn create(ctx: RpcContext) -> Result { - let container = ctx.lxc_manager.create(None, LxcConfig::default()).await?; - let guid = container.guid.deref().clone(); - ctx.dev.lxc.lock().await.insert(guid.clone(), container); - Ok(guid) -} - -pub async fn list(ctx: RpcContext) -> Result, Error> { - Ok(ctx.dev.lxc.lock().await.keys().cloned().collect()) -} - -#[derive(Deserialize, Serialize, Parser, TS)] -pub struct RemoveParams { - #[ts(type = "string")] - pub guid: ContainerId, -} - -pub async fn remove(ctx: RpcContext, RemoveParams { guid }: RemoveParams) -> Result<(), Error> { - if let Some(container) = ctx.dev.lxc.lock().await.remove(&guid) { - container.exit().await?; - } - Ok(()) -} - -#[derive(Deserialize, Serialize, Parser, TS)] -pub struct ConnectParams { - #[ts(type = "string")] - pub guid: ContainerId, -} - -pub async fn connect_rpc( - ctx: RpcContext, - ConnectParams { guid }: ConnectParams, -) -> Result { - connect( - &ctx, - ctx.dev.lxc.lock().await.get(&guid).ok_or_else(|| { - Error::new(eyre!("No container with guid: {guid}"), ErrorKind::NotFound) - })?, - ) - .await -} - pub async fn connect(ctx: &RpcContext, container: &LxcContainer) -> Result { use axum::extract::ws::Message; @@ -473,10 +397,8 @@ pub async fn connect(ctx: &RpcContext, container: &LxcContainer) -> Result { id, result }, - ) - .with_kind(ErrorKind::Serialization)?, + serde_json::to_string(&RpcResponse { id, result }) + .with_kind(ErrorKind::Serialization)?, )) .await .with_kind(ErrorKind::Network)?; @@ -612,28 +534,3 @@ pub async fn connect_cli(ctx: &CliContext, guid: Guid) -> Result<(), Error> { Ok(()) } - -pub async fn connect_rpc_cli( - HandlerArgs { - context, - parent_method, - method, - params, - inherited_params, - raw_params, - }: HandlerArgs, -) -> Result<(), Error> { - let ctx = context.clone(); - let guid = CallRemoteHandler::::new(from_fn_async(connect_rpc)) - .handle_async(HandlerArgs { - context, - parent_method, - method, - params: rpc_toolkit::util::Flat(params, Empty {}), - inherited_params, - raw_params, - }) - .await?; - - connect_cli(&ctx, guid).await -} diff --git a/core/startos/src/os_install/mod.rs b/core/startos/src/os_install/mod.rs index c3931b236..b1d9ef1c4 100644 --- a/core/startos/src/os_install/mod.rs +++ b/core/startos/src/os_install/mod.rs @@ -281,6 +281,10 @@ pub async fn execute( IoFormat::Yaml.to_vec(&ServerConfig { os_partitions: Some(part_info.clone()), ethernet_interface: Some(eth_iface), + #[cfg(feature = "dev")] + analytics_url: None, + #[cfg(not(feature = "dev"))] + analytics_url: Some("https://analytics.start9.com".parse()?), // TODO: FullMetal ..Default::default() })?, ) diff --git a/core/startos/src/registry/context.rs b/core/startos/src/registry/context.rs index 99d60307b..0461aa924 100644 --- a/core/startos/src/registry/context.rs +++ b/core/startos/src/registry/context.rs @@ -32,8 +32,8 @@ pub struct RegistryConfig { #[arg(short = 'l', long = "listen")] pub listen: Option, #[arg(short = 'h', long = "hostname")] - pub hostname: InternedString, - #[arg(short = 'p', long = "proxy")] + pub hostname: Option, + #[arg(short = 'p', long = "tor-proxy")] pub tor_proxy: Option, #[arg(short = 'd', long = "datadir")] pub datadir: Option, @@ -43,6 +43,9 @@ impl ContextConfig for RegistryConfig { self.config.take() } fn merge_with(&mut self, other: Self) { + self.listen = self.listen.take().or(other.listen); + self.hostname = self.hostname.take().or(other.hostname); + self.tor_proxy = self.tor_proxy.take().or(other.tor_proxy); self.datadir = self.datadir.take().or(other.datadir); } } @@ -92,7 +95,16 @@ impl RegistryContext { .map(Ok) .unwrap_or_else(|| "socks5h://localhost:9050".parse())?; Ok(Self(Arc::new(RegistryContextSeed { - hostname: config.hostname.clone(), + hostname: config + .hostname + .as_ref() + .ok_or_else(|| { + Error::new( + eyre!("missing required configuration: hostname"), + ErrorKind::NotFound, + ) + })? + .clone(), listen: config .listen .unwrap_or(SocketAddr::new(Ipv4Addr::LOCALHOST.into(), 5959)), @@ -169,7 +181,8 @@ impl CallRemote for CliContext { &AnySigningKey::Ed25519(self.developer_key()?.clone()), &body, &host, - )?.to_header(), + )? + .to_header(), ) .body(body) .send() diff --git a/sdk/lib/osBindings/AddAssetParams.ts b/sdk/lib/osBindings/AddAssetParams.ts index ce6128cf7..ffd7db675 100644 --- a/sdk/lib/osBindings/AddAssetParams.ts +++ b/sdk/lib/osBindings/AddAssetParams.ts @@ -6,7 +6,6 @@ import type { Version } from "./Version" export type AddAssetParams = { version: Version platform: string - upload: boolean url: string signature: AnySignature commitment: Blake3Commitment diff --git a/sdk/lib/osBindings/AddPackageParams.ts b/sdk/lib/osBindings/AddPackageParams.ts new file mode 100644 index 000000000..4395b9b8a --- /dev/null +++ b/sdk/lib/osBindings/AddPackageParams.ts @@ -0,0 +1,9 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { AnySignature } from "./AnySignature" +import type { MerkleArchiveCommitment } from "./MerkleArchiveCommitment" + +export type AddPackageParams = { + url: string + commitment: MerkleArchiveCommitment + signature: AnySignature +} diff --git a/sdk/lib/osBindings/GetPackageResponse.ts b/sdk/lib/osBindings/GetPackageResponse.ts index 5bf24bfc0..3e1dd4e9d 100644 --- a/sdk/lib/osBindings/GetPackageResponse.ts +++ b/sdk/lib/osBindings/GetPackageResponse.ts @@ -4,6 +4,7 @@ import type { PackageVersionInfo } from "./PackageVersionInfo" import type { Version } from "./Version" export type GetPackageResponse = { + categories: string[] best: { [key: Version]: PackageVersionInfo } otherVersions?: { [key: Version]: PackageInfoShort } } diff --git a/sdk/lib/osBindings/GetPackageResponseFull.ts b/sdk/lib/osBindings/GetPackageResponseFull.ts index 579924291..e375dd489 100644 --- a/sdk/lib/osBindings/GetPackageResponseFull.ts +++ b/sdk/lib/osBindings/GetPackageResponseFull.ts @@ -3,6 +3,7 @@ import type { PackageVersionInfo } from "./PackageVersionInfo" import type { Version } from "./Version" export type GetPackageResponseFull = { + categories: string[] best: { [key: Version]: PackageVersionInfo } otherVersions: { [key: Version]: PackageVersionInfo } } diff --git a/sdk/lib/osBindings/HardwareRequirements.ts b/sdk/lib/osBindings/HardwareRequirements.ts index 4964bc66f..0e1da1f36 100644 --- a/sdk/lib/osBindings/HardwareRequirements.ts +++ b/sdk/lib/osBindings/HardwareRequirements.ts @@ -3,5 +3,5 @@ export type HardwareRequirements = { device: { [key: string]: string } ram: number | null - arch: Array | null + arch: string[] | null } diff --git a/sdk/lib/osBindings/OsVersionInfo.ts b/sdk/lib/osBindings/OsVersionInfo.ts index 7cd0fde9e..a88115350 100644 --- a/sdk/lib/osBindings/OsVersionInfo.ts +++ b/sdk/lib/osBindings/OsVersionInfo.ts @@ -7,7 +7,7 @@ export type OsVersionInfo = { headline: string releaseNotes: string sourceVersion: string - signers: Array + authorized: Array iso: { [key: string]: RegistryAsset } squashfs: { [key: string]: RegistryAsset } img: { [key: string]: RegistryAsset } diff --git a/sdk/lib/osBindings/PackageInfo.ts b/sdk/lib/osBindings/PackageInfo.ts index af340424f..6d07cd43e 100644 --- a/sdk/lib/osBindings/PackageInfo.ts +++ b/sdk/lib/osBindings/PackageInfo.ts @@ -4,6 +4,7 @@ import type { PackageVersionInfo } from "./PackageVersionInfo" import type { Version } from "./Version" export type PackageInfo = { - signers: Array + authorized: Array versions: { [key: Version]: PackageVersionInfo } + categories: string[] } diff --git a/sdk/lib/osBindings/PackageVersionInfo.ts b/sdk/lib/osBindings/PackageVersionInfo.ts index da82540cd..bdded46bd 100644 --- a/sdk/lib/osBindings/PackageVersionInfo.ts +++ b/sdk/lib/osBindings/PackageVersionInfo.ts @@ -17,7 +17,6 @@ export type PackageVersionInfo = { upstreamRepo: string supportSite: string marketingSite: string - categories: string[] osVersion: Version hardwareRequirements: HardwareRequirements sourceVersion: string | null diff --git a/sdk/lib/osBindings/index.ts b/sdk/lib/osBindings/index.ts index 16fc56a74..3059c6087 100644 --- a/sdk/lib/osBindings/index.ts +++ b/sdk/lib/osBindings/index.ts @@ -3,6 +3,7 @@ export { ActionId } from "./ActionId" export { ActionMetadata } from "./ActionMetadata" export { AddAdminParams } from "./AddAdminParams" export { AddAssetParams } from "./AddAssetParams" +export { AddPackageParams } from "./AddPackageParams" export { AddressInfo } from "./AddressInfo" export { AddSslOptions } from "./AddSslOptions" export { AddVersionParams } from "./AddVersionParams"