mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-27 02:41:53 +00:00
overhaul context
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
use anyhow::anyhow;
|
||||
use basic_cookies::Cookie;
|
||||
use chrono::{DateTime, NaiveDateTime, Utc};
|
||||
use chrono::{DateTime, Utc};
|
||||
use clap::ArgMatches;
|
||||
use http::header::COOKIE;
|
||||
use http::HeaderValue;
|
||||
@@ -11,14 +11,14 @@ use rpc_toolkit::yajrc::RpcError;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::context::EitherContext;
|
||||
use crate::context::{CliContext, RpcContext};
|
||||
use crate::middleware::auth::{get_id, hash_token};
|
||||
use crate::util::{display_none, display_serializable, IoFormat};
|
||||
use crate::{ensure_code, Error, ResultExt};
|
||||
|
||||
#[command(subcommands(login, logout, session))]
|
||||
pub fn auth(#[context] ctx: EitherContext) -> Result<EitherContext, Error> {
|
||||
Ok(ctx)
|
||||
pub fn auth() -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn parse_metadata(_: &str, _: &ArgMatches<'_>) -> Result<Value, Error> {
|
||||
@@ -40,12 +40,20 @@ fn gen_pwd() {
|
||||
)
|
||||
}
|
||||
|
||||
#[command(display(display_none), metadata(authenticated = false))]
|
||||
// fn cli_login(ctx: CliContext, password: Option<String>, metadata: Value) -> Result<(), Error> {
|
||||
// todo!()
|
||||
// }
|
||||
|
||||
#[command(
|
||||
// custom_cli(cli_login),
|
||||
display(display_none),
|
||||
metadata(authenticated = false)
|
||||
)]
|
||||
pub async fn login(
|
||||
#[context] ctx: EitherContext,
|
||||
#[context] ctx: RpcContext,
|
||||
#[request] req: &RequestParts,
|
||||
#[response] res: &mut ResponseParts,
|
||||
#[arg] password: String,
|
||||
#[arg] password: Option<String>,
|
||||
#[arg(
|
||||
parse(parse_metadata),
|
||||
default = "",
|
||||
@@ -53,8 +61,8 @@ pub async fn login(
|
||||
)]
|
||||
metadata: Value,
|
||||
) -> Result<(), Error> {
|
||||
let rpc_ctx = ctx.as_rpc().unwrap();
|
||||
let mut handle = rpc_ctx.secret_store.acquire().await?;
|
||||
let password = password.unwrap_or_default();
|
||||
let mut handle = ctx.secret_store.acquire().await?;
|
||||
let pw_hash = sqlx::query!("SELECT password FROM account")
|
||||
.fetch_one(&mut handle)
|
||||
.await?
|
||||
@@ -99,7 +107,7 @@ pub async fn login(
|
||||
|
||||
#[command(display(display_none), metadata(authenticated = false))]
|
||||
pub async fn logout(
|
||||
#[context] ctx: EitherContext,
|
||||
#[context] ctx: RpcContext,
|
||||
#[request] req: &RequestParts,
|
||||
) -> Result<(), Error> {
|
||||
if let Some(cookie_header) = req.headers.get(COOKIE) {
|
||||
@@ -135,8 +143,8 @@ pub struct SessionList {
|
||||
}
|
||||
|
||||
#[command(subcommands(list, kill))]
|
||||
pub async fn session(#[context] ctx: EitherContext) -> Result<EitherContext, Error> {
|
||||
Ok(ctx)
|
||||
pub async fn session() -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn display_sessions(arg: SessionList, matches: &ArgMatches<'_>) {
|
||||
@@ -174,7 +182,7 @@ fn display_sessions(arg: SessionList, matches: &ArgMatches<'_>) {
|
||||
|
||||
#[command(display(display_sessions))]
|
||||
pub async fn list(
|
||||
#[context] ctx: EitherContext,
|
||||
#[context] ctx: RpcContext,
|
||||
#[request] req: &RequestParts,
|
||||
#[allow(unused_variables)]
|
||||
#[arg(long = "format")]
|
||||
@@ -185,7 +193,7 @@ pub async fn list(
|
||||
sessions: sqlx::query!(
|
||||
"SELECT * FROM session WHERE logged_out IS NULL OR logged_out > CURRENT_TIMESTAMP"
|
||||
)
|
||||
.fetch_all(&mut ctx.as_rpc().unwrap().secret_store.acquire().await?)
|
||||
.fetch_all(&mut ctx.secret_store.acquire().await?)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|row| {
|
||||
@@ -210,15 +218,14 @@ fn parse_comma_separated(arg: &str, _: &ArgMatches<'_>) -> Result<Vec<String>, R
|
||||
|
||||
#[command(display(display_none))]
|
||||
pub async fn kill(
|
||||
#[context] ctx: EitherContext,
|
||||
#[context] ctx: RpcContext,
|
||||
#[arg(parse(parse_comma_separated))] ids: Vec<String>,
|
||||
) -> Result<(), Error> {
|
||||
let rpc_ctx = ctx.as_rpc().unwrap();
|
||||
sqlx::query(&format!(
|
||||
"UPDATE session SET logged_out = CURRENT_TIMESTAMP WHERE id IN ('{}')",
|
||||
ids.join("','")
|
||||
))
|
||||
.execute(&mut rpc_ctx.secret_store.acquire().await?)
|
||||
.execute(&mut ctx.secret_store.acquire().await?)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use clap::Arg;
|
||||
use embassy::context::{CliContext, EitherContext};
|
||||
use embassy::context::CliContext;
|
||||
use embassy::Error;
|
||||
use rpc_toolkit::run_cli;
|
||||
use rpc_toolkit::yajrc::RpcError;
|
||||
@@ -35,6 +35,7 @@ fn inner_main() -> Result<(), Error> {
|
||||
});
|
||||
EitherContext::Cli(CliContext::init(matches)?)
|
||||
},
|
||||
(),
|
||||
|e: RpcError| {
|
||||
match e.data {
|
||||
Some(Value::String(s)) => eprintln!("{}: {}", e.message, s),
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::path::Path;
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use embassy::context::{EitherContext, RpcContext};
|
||||
use embassy::context::RpcContext;
|
||||
use embassy::db::model::Database;
|
||||
use embassy::db::subscribe;
|
||||
use embassy::hostname::{get_hostname, get_id};
|
||||
@@ -46,7 +46,7 @@ async fn inner_main(cfg_path: Option<&str>) -> Result<(), Error> {
|
||||
.await?;
|
||||
}
|
||||
let auth = auth(rpc_ctx.clone());
|
||||
let ctx = EitherContext::Rpc(rpc_ctx.clone());
|
||||
let ctx = rpc_ctx.clone();
|
||||
let server = rpc_server!({
|
||||
command: embassy::main_api,
|
||||
context: ctx,
|
||||
|
||||
@@ -14,7 +14,7 @@ use serde_json::Value;
|
||||
|
||||
use crate::action::docker::DockerAction;
|
||||
use crate::config::spec::PackagePointerSpecVariant;
|
||||
use crate::context::{EitherContext, ExtendedContext};
|
||||
use crate::context::RpcContext;
|
||||
use crate::db::model::{CurrentDependencyInfo, InstalledPackageDataEntryModel};
|
||||
use crate::db::util::WithRevision;
|
||||
use crate::dependencies::{
|
||||
@@ -137,24 +137,22 @@ pub enum MatchError {
|
||||
}
|
||||
|
||||
#[command(subcommands(get, set))]
|
||||
pub fn config(
|
||||
#[context] ctx: EitherContext,
|
||||
#[arg] id: PackageId,
|
||||
) -> Result<ExtendedContext<EitherContext, PackageId>, Error> {
|
||||
Ok(ExtendedContext::from(ctx).map(|_| id))
|
||||
pub fn config(#[arg] id: PackageId) -> Result<PackageId, Error> {
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
#[command(display(display_serializable))]
|
||||
pub async fn get(
|
||||
#[context] ctx: ExtendedContext<EitherContext, PackageId>,
|
||||
#[context] ctx: RpcContext,
|
||||
#[parent_data] id: PackageId,
|
||||
#[allow(unused_variables)]
|
||||
#[arg(long = "format")]
|
||||
format: Option<IoFormat>,
|
||||
) -> Result<ConfigRes, Error> {
|
||||
let mut db = ctx.base().as_rpc().unwrap().db.handle();
|
||||
let mut db = ctx.db.handle();
|
||||
let pkg_model = crate::db::DatabaseModel::new()
|
||||
.package_data()
|
||||
.idx_model(ctx.extension())
|
||||
.idx_model(&id)
|
||||
.and_then(|m| m.installed())
|
||||
.expect(&mut db)
|
||||
.await
|
||||
@@ -166,12 +164,7 @@ pub async fn get(
|
||||
.get(&mut db, true)
|
||||
.await?
|
||||
.to_owned()
|
||||
.ok_or_else(|| {
|
||||
Error::new(
|
||||
anyhow!("{} has no config", ctx.extension()),
|
||||
crate::ErrorKind::NotFound,
|
||||
)
|
||||
})?;
|
||||
.ok_or_else(|| Error::new(anyhow!("{} has no config", id), crate::ErrorKind::NotFound))?;
|
||||
let version = pkg_model
|
||||
.clone()
|
||||
.manifest()
|
||||
@@ -179,40 +172,39 @@ pub async fn get(
|
||||
.get(&mut db, true)
|
||||
.await?;
|
||||
let volumes = pkg_model.manifest().volumes().get(&mut db, true).await?;
|
||||
action.get(ctx.extension(), &*version, &*volumes).await
|
||||
action.get(&id, &*version, &*volumes).await
|
||||
}
|
||||
|
||||
#[command(subcommands(self(set_impl(async)), set_dry), display(display_none))]
|
||||
pub fn set(
|
||||
#[context] ctx: ExtendedContext<EitherContext, PackageId>,
|
||||
#[context] ctx: RpcContext,
|
||||
#[parent_data] id: PackageId,
|
||||
#[allow(unused_variables)]
|
||||
#[arg(long = "format")]
|
||||
format: Option<IoFormat>,
|
||||
#[arg(long = "timeout", parse(parse_duration))] timeout: Option<Duration>,
|
||||
#[arg(stdin, parse(parse_stdin_deserializable))] config: Option<Config>,
|
||||
#[arg(rename = "expire-id", long = "expire-id")] expire_id: Option<String>,
|
||||
) -> Result<
|
||||
ExtendedContext<EitherContext, (PackageId, Option<Config>, Option<Duration>, Option<String>)>,
|
||||
Error,
|
||||
> {
|
||||
Ok(ctx.map(|id| (id, config, timeout, expire_id)))
|
||||
) -> Result<(PackageId, Option<Config>, Option<Duration>, Option<String>), Error> {
|
||||
Ok((id, config, timeout, expire_id))
|
||||
}
|
||||
|
||||
#[command(display(display_serializable))]
|
||||
pub async fn set_dry(
|
||||
#[context] ctx: ExtendedContext<
|
||||
EitherContext,
|
||||
(PackageId, Option<Config>, Option<Duration>, Option<String>),
|
||||
>,
|
||||
#[context] ctx: RpcContext,
|
||||
#[parent_data] (id, config, timeout, _): (
|
||||
PackageId,
|
||||
Option<Config>,
|
||||
Option<Duration>,
|
||||
Option<String>,
|
||||
),
|
||||
) -> Result<BreakageRes, Error> {
|
||||
let (ctx, (id, config, timeout, _)) = ctx.split();
|
||||
let rpc_ctx = ctx.as_rpc().unwrap();
|
||||
let mut db = rpc_ctx.db.handle();
|
||||
let mut db = ctx.db.handle();
|
||||
let mut tx = db.begin().await?;
|
||||
let mut breakages = IndexMap::new();
|
||||
configure(
|
||||
&mut tx,
|
||||
&rpc_ctx.docker,
|
||||
&ctx.docker,
|
||||
&id,
|
||||
config,
|
||||
&timeout,
|
||||
@@ -240,19 +232,15 @@ pub async fn set_dry(
|
||||
}
|
||||
|
||||
pub async fn set_impl(
|
||||
ctx: ExtendedContext<
|
||||
EitherContext,
|
||||
(PackageId, Option<Config>, Option<Duration>, Option<String>),
|
||||
>,
|
||||
ctx: RpcContext,
|
||||
(id, config, timeout, expire_id): (PackageId, Option<Config>, Option<Duration>, Option<String>),
|
||||
) -> Result<WithRevision<()>, Error> {
|
||||
let (ctx, (id, config, timeout, expire_id)) = ctx.split();
|
||||
let rpc_ctx = ctx.as_rpc().unwrap();
|
||||
let mut db = rpc_ctx.db.handle();
|
||||
let mut db = ctx.db.handle();
|
||||
let mut tx = db.begin().await?;
|
||||
let mut breakages = IndexMap::new();
|
||||
configure(
|
||||
&mut tx,
|
||||
&rpc_ctx.docker,
|
||||
&ctx.docker,
|
||||
&id,
|
||||
config,
|
||||
&timeout,
|
||||
|
||||
@@ -1,121 +1,30 @@
|
||||
use rpc_toolkit::reqwest::Client;
|
||||
use rpc_toolkit::url::{Host, Url};
|
||||
use rpc_toolkit::Context;
|
||||
|
||||
mod cli;
|
||||
mod rpc;
|
||||
|
||||
pub use cli::CliContext;
|
||||
pub use rpc::RpcContext;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ExtendedContext<T, U> {
|
||||
base: T,
|
||||
extension: U,
|
||||
}
|
||||
impl<T, U> ExtendedContext<T, U> {
|
||||
pub fn map<F: FnOnce(U) -> V, V>(self, f: F) -> ExtendedContext<T, V> {
|
||||
ExtendedContext {
|
||||
base: self.base,
|
||||
extension: f(self.extension),
|
||||
}
|
||||
}
|
||||
pub fn split(self) -> (T, U) {
|
||||
(self.base, self.extension)
|
||||
}
|
||||
pub fn base(&self) -> &T {
|
||||
&self.base
|
||||
}
|
||||
pub fn extension(&self) -> &U {
|
||||
&self.extension
|
||||
impl From<CliContext> for () {
|
||||
fn from(_: CliContext) -> Self {
|
||||
()
|
||||
}
|
||||
}
|
||||
impl<T> From<T> for ExtendedContext<T, ()> {
|
||||
fn from(base: T) -> Self {
|
||||
ExtendedContext {
|
||||
base,
|
||||
extension: (),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T: Context, U> Context for ExtendedContext<T, U> {
|
||||
fn host(&self) -> Host<&str> {
|
||||
self.base.host()
|
||||
}
|
||||
fn port(&self) -> u16 {
|
||||
self.base.port()
|
||||
}
|
||||
fn protocol(&self) -> &str {
|
||||
self.base.protocol()
|
||||
}
|
||||
fn url(&self) -> Url {
|
||||
self.base.url()
|
||||
}
|
||||
fn client(&self) -> &Client {
|
||||
self.base.client()
|
||||
impl From<RpcContext> for () {
|
||||
fn from(_: RpcContext) -> Self {
|
||||
()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum EitherContext {
|
||||
Cli(CliContext),
|
||||
Rpc(RpcContext),
|
||||
}
|
||||
impl EitherContext {
|
||||
pub fn as_cli(&self) -> Option<&CliContext> {
|
||||
match self {
|
||||
EitherContext::Cli(a) => Some(a),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
pub fn as_rpc(&self) -> Option<&RpcContext> {
|
||||
match self {
|
||||
EitherContext::Rpc(a) => Some(a),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
pub fn to_cli(self) -> Option<CliContext> {
|
||||
match self {
|
||||
EitherContext::Cli(a) => Some(a),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
pub fn to_rpc(self) -> Option<RpcContext> {
|
||||
match self {
|
||||
EitherContext::Rpc(a) => Some(a),
|
||||
_ => None,
|
||||
}
|
||||
// TODO: these shouldn't be necessary
|
||||
|
||||
impl From<CliContext> for RpcContext {
|
||||
fn from(_: CliContext) -> Self {
|
||||
panic!("RPC Context used in CLI Handler")
|
||||
}
|
||||
}
|
||||
impl Context for EitherContext {
|
||||
fn host(&self) -> Host<&str> {
|
||||
match self {
|
||||
EitherContext::Cli(a) => a.host(),
|
||||
EitherContext::Rpc(b) => b.host(),
|
||||
}
|
||||
}
|
||||
fn port(&self) -> u16 {
|
||||
match self {
|
||||
EitherContext::Cli(a) => a.port(),
|
||||
EitherContext::Rpc(b) => b.port(),
|
||||
}
|
||||
}
|
||||
fn protocol(&self) -> &str {
|
||||
match self {
|
||||
EitherContext::Cli(a) => a.protocol(),
|
||||
EitherContext::Rpc(b) => b.protocol(),
|
||||
}
|
||||
}
|
||||
fn url(&self) -> Url {
|
||||
match self {
|
||||
EitherContext::Cli(a) => a.url(),
|
||||
EitherContext::Rpc(b) => b.url(),
|
||||
}
|
||||
}
|
||||
fn client(&self) -> &Client {
|
||||
match self {
|
||||
EitherContext::Cli(a) => a.client(),
|
||||
EitherContext::Rpc(b) => b.client(),
|
||||
}
|
||||
|
||||
impl From<RpcContext> for CliContext {
|
||||
fn from(_: RpcContext) -> Self {
|
||||
panic!("CLI Context used in RPC Handler")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ use indexmap::IndexMap;
|
||||
use patch_db::DbHandle;
|
||||
use rpc_toolkit::command;
|
||||
|
||||
use crate::context::EitherContext;
|
||||
use crate::context::RpcContext;
|
||||
use crate::db::util::WithRevision;
|
||||
use crate::s9pk::manifest::PackageId;
|
||||
use crate::status::MainStatus;
|
||||
@@ -13,11 +13,10 @@ use crate::{Error, ResultExt};
|
||||
|
||||
#[command(display(display_none))]
|
||||
pub async fn start(
|
||||
#[context] ctx: EitherContext,
|
||||
#[context] ctx: RpcContext,
|
||||
#[arg] id: PackageId,
|
||||
) -> Result<WithRevision<()>, Error> {
|
||||
let rpc_ctx = ctx.as_rpc().unwrap();
|
||||
let mut db = rpc_ctx.db.handle();
|
||||
let mut db = ctx.db.handle();
|
||||
let mut tx = db.begin().await?;
|
||||
let installed = crate::db::DatabaseModel::new()
|
||||
.package_data()
|
||||
@@ -46,7 +45,7 @@ pub async fn start(
|
||||
};
|
||||
status
|
||||
.synchronize(
|
||||
&*rpc_ctx.managers.get(&(id, version)).await.ok_or_else(|| {
|
||||
&*ctx.managers.get(&(id, version)).await.ok_or_else(|| {
|
||||
Error::new(anyhow!("Manager not found"), crate::ErrorKind::Docker)
|
||||
})?,
|
||||
)
|
||||
@@ -61,11 +60,10 @@ pub async fn start(
|
||||
|
||||
#[command(display(display_none))]
|
||||
pub async fn stop(
|
||||
#[context] ctx: EitherContext,
|
||||
#[context] ctx: RpcContext,
|
||||
#[arg] id: PackageId,
|
||||
) -> Result<WithRevision<()>, Error> {
|
||||
let rpc_ctx = ctx.as_rpc().unwrap();
|
||||
let mut db = rpc_ctx.db.handle();
|
||||
let mut db = ctx.db.handle();
|
||||
let mut tx = db.begin().await?;
|
||||
|
||||
let mut status = crate::db::DatabaseModel::new()
|
||||
|
||||
@@ -6,7 +6,7 @@ use std::sync::Arc;
|
||||
|
||||
use futures::{SinkExt, StreamExt};
|
||||
use patch_db::json_ptr::JsonPointer;
|
||||
use patch_db::{DiffPatch, Dump, Revision};
|
||||
use patch_db::{Dump, Revision};
|
||||
use rpc_toolkit::command;
|
||||
use rpc_toolkit::hyper::upgrade::Upgraded;
|
||||
use rpc_toolkit::hyper::{Body, Error as HyperError, Request, Response};
|
||||
@@ -19,8 +19,7 @@ use tokio_tungstenite::WebSocketStream;
|
||||
|
||||
pub use self::model::DatabaseModel;
|
||||
use self::util::WithRevision;
|
||||
use crate::context::{EitherContext, RpcContext};
|
||||
use crate::middleware::auth::is_authed;
|
||||
use crate::context::RpcContext;
|
||||
use crate::util::{display_serializable, IoFormat};
|
||||
use crate::{Error, ResultExt};
|
||||
|
||||
@@ -73,8 +72,8 @@ pub async fn subscribe(ctx: RpcContext, req: Request<Body>) -> Result<Response<B
|
||||
}
|
||||
|
||||
#[command(subcommands(revisions, dump, put))]
|
||||
pub fn db(#[context] ctx: EitherContext) -> Result<EitherContext, RpcError> {
|
||||
Ok(ctx)
|
||||
pub fn db() -> Result<(), RpcError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
@@ -86,14 +85,13 @@ pub enum RevisionsRes {
|
||||
|
||||
#[command(display(display_serializable))]
|
||||
pub async fn revisions(
|
||||
#[context] ctx: EitherContext,
|
||||
#[context] ctx: RpcContext,
|
||||
#[arg] since: u64,
|
||||
#[allow(unused_variables)]
|
||||
#[arg(long = "format")]
|
||||
format: Option<IoFormat>,
|
||||
) -> Result<RevisionsRes, RpcError> {
|
||||
let rpc_ctx = ctx.as_rpc().unwrap();
|
||||
let cache = rpc_ctx.revision_cache.read().await;
|
||||
let cache = ctx.revision_cache.read().await;
|
||||
if cache
|
||||
.front()
|
||||
.map(|rev| rev.id <= since + 1)
|
||||
@@ -108,28 +106,28 @@ pub async fn revisions(
|
||||
))
|
||||
} else {
|
||||
drop(cache);
|
||||
Ok(RevisionsRes::Dump(rpc_ctx.db.dump().await))
|
||||
Ok(RevisionsRes::Dump(ctx.db.dump().await))
|
||||
}
|
||||
}
|
||||
|
||||
#[command(display(display_serializable))]
|
||||
pub async fn dump(
|
||||
#[context] ctx: EitherContext,
|
||||
#[context] ctx: RpcContext,
|
||||
#[allow(unused_variables)]
|
||||
#[arg(long = "format")]
|
||||
format: Option<IoFormat>,
|
||||
) -> Result<Dump, RpcError> {
|
||||
Ok(ctx.as_rpc().unwrap().db.dump().await)
|
||||
Ok(ctx.db.dump().await)
|
||||
}
|
||||
|
||||
#[command(subcommands(ui))]
|
||||
pub fn put(#[context] ctx: EitherContext) -> Result<EitherContext, RpcError> {
|
||||
Ok(ctx)
|
||||
pub fn put() -> Result<(), RpcError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[command(display(display_serializable))]
|
||||
pub async fn ui(
|
||||
#[context] ctx: EitherContext,
|
||||
#[context] ctx: RpcContext,
|
||||
#[arg] pointer: JsonPointer,
|
||||
#[arg] value: Value,
|
||||
#[allow(unused_variables)]
|
||||
@@ -139,6 +137,6 @@ pub async fn ui(
|
||||
let ptr = "/ui".parse::<JsonPointer>()? + &pointer;
|
||||
Ok(WithRevision {
|
||||
response: (),
|
||||
revision: ctx.as_rpc().unwrap().db.put(&ptr, &value, None).await?,
|
||||
revision: ctx.db.put(&ptr, &value, None).await?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -5,13 +5,12 @@ use std::path::Path;
|
||||
use ed25519_dalek::Keypair;
|
||||
use rpc_toolkit::command;
|
||||
|
||||
use crate::context::EitherContext;
|
||||
use crate::context::CliContext;
|
||||
use crate::util::display_none;
|
||||
use crate::{Error, ResultExt};
|
||||
|
||||
#[command(cli_only, blocking, display(display_none))]
|
||||
pub fn init(#[context] ctx: EitherContext) -> Result<(), Error> {
|
||||
let ctx = ctx.as_cli().unwrap();
|
||||
pub fn init(#[context] ctx: CliContext) -> Result<(), Error> {
|
||||
if !ctx.developer_key_path.exists() {
|
||||
let parent = ctx.developer_key_path.parent().unwrap_or(Path::new("/"));
|
||||
if !parent.exists() {
|
||||
|
||||
@@ -2,14 +2,14 @@ use std::path::PathBuf;
|
||||
|
||||
use rpc_toolkit::command;
|
||||
|
||||
use crate::context::{CliContext, EitherContext};
|
||||
use crate::context::CliContext;
|
||||
use crate::s9pk::manifest::Manifest;
|
||||
use crate::s9pk::reader::S9pkReader;
|
||||
use crate::util::{display_none, display_serializable, IoFormat};
|
||||
use crate::Error;
|
||||
|
||||
#[command(subcommands(hash, manifest, license, icon, instructions, docker_images))]
|
||||
pub fn inspect(#[context] _ctx: EitherContext) -> Result<(), Error> {
|
||||
pub fn inspect() -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ use tokio::fs::{File, OpenOptions};
|
||||
use tokio::io::{AsyncRead, AsyncSeek, AsyncSeekExt, AsyncWrite, AsyncWriteExt};
|
||||
|
||||
use self::cleanup::cleanup_failed;
|
||||
use crate::context::{EitherContext, ExtendedContext, RpcContext};
|
||||
use crate::context::RpcContext;
|
||||
use crate::db::model::{
|
||||
CurrentDependencyInfo, InstalledPackageDataEntry, PackageDataEntry, StaticDependencyInfo,
|
||||
StaticFiles,
|
||||
@@ -50,17 +50,16 @@ pub const PKG_PUBLIC_DIR: &'static str = "/mnt/embassy-os/public/package-data";
|
||||
|
||||
#[command(display(display_none))]
|
||||
pub async fn install(
|
||||
#[context] ctx: EitherContext,
|
||||
#[context] ctx: RpcContext,
|
||||
#[arg] id: String,
|
||||
) -> Result<WithRevision<()>, Error> {
|
||||
let rpc_ctx = ctx.to_rpc().unwrap();
|
||||
let (pkg_id, version_str) = if let Some(split) = id.split_once("@") {
|
||||
split
|
||||
} else {
|
||||
(id.as_str(), "*")
|
||||
};
|
||||
let version: VersionRange = version_str.parse()?;
|
||||
let reg_url = rpc_ctx.package_registry_url().await?;
|
||||
let reg_url = ctx.package_registry_url().await?;
|
||||
let (man_res, s9pk) = tokio::try_join!(
|
||||
reqwest::get(format!(
|
||||
"{}/package/manifest/{}?version={}",
|
||||
@@ -76,7 +75,7 @@ pub async fn install(
|
||||
|
||||
let progress = InstallProgress::new(s9pk.content_length());
|
||||
let static_files = StaticFiles::remote(&man.id, &man.version, man.assets.icon_type());
|
||||
let mut db_handle = rpc_ctx.db.handle();
|
||||
let mut db_handle = ctx.db.handle();
|
||||
let mut tx = db_handle.begin().await?;
|
||||
let mut pde = crate::db::DatabaseModel::new()
|
||||
.package_data()
|
||||
@@ -115,7 +114,7 @@ pub async fn install(
|
||||
drop(db_handle);
|
||||
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = download_install_s9pk(&rpc_ctx, &man, s9pk).await {
|
||||
if let Err(e) = download_install_s9pk(&ctx, &man, s9pk).await {
|
||||
log::error!("Install of {}@{} Failed: {}", man.id, man.version, e);
|
||||
}
|
||||
});
|
||||
@@ -128,10 +127,10 @@ pub async fn install(
|
||||
|
||||
#[command(display(display_none))]
|
||||
pub async fn uninstall(
|
||||
#[context] ctx: EitherContext,
|
||||
#[context] ctx: RpcContext,
|
||||
#[arg] id: PackageId,
|
||||
) -> Result<WithRevision<()>, Error> {
|
||||
let mut handle = ctx.as_rpc().unwrap().db.handle();
|
||||
let mut handle = ctx.db.handle();
|
||||
let mut tx = handle.begin().await?;
|
||||
|
||||
let mut pde = crate::db::DatabaseModel::new()
|
||||
@@ -161,8 +160,7 @@ pub async fn uninstall(
|
||||
drop(handle);
|
||||
|
||||
tokio::spawn(async move {
|
||||
let rpc_ctx = ctx.as_rpc().unwrap();
|
||||
if let Err(e) = cleanup::uninstall(rpc_ctx, &mut rpc_ctx.db.handle(), &installed).await {
|
||||
if let Err(e) = cleanup::uninstall(&ctx, &mut ctx.db.handle(), &installed).await {
|
||||
log::error!("Uninstall of {} Failed: {}", id, e);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -46,14 +46,14 @@ pub mod version;
|
||||
pub mod volume;
|
||||
|
||||
pub use config::Config;
|
||||
use context::{CliContext, EitherContext};
|
||||
use context::CliContext;
|
||||
pub use error::{Error, ErrorKind, ResultExt};
|
||||
use rpc_toolkit::command;
|
||||
use rpc_toolkit::yajrc::RpcError;
|
||||
pub use version::{init, self_update};
|
||||
|
||||
#[command(metadata(authenticated = false))]
|
||||
pub fn echo(#[context] _ctx: EitherContext, #[arg] message: String) -> Result<String, RpcError> {
|
||||
pub fn echo(#[arg] message: String) -> Result<String, RpcError> {
|
||||
Ok(message)
|
||||
}
|
||||
|
||||
@@ -68,8 +68,8 @@ pub fn echo(#[context] _ctx: EitherContext, #[arg] message: String) -> Result<St
|
||||
auth::auth,
|
||||
db::db,
|
||||
))]
|
||||
pub fn main_api(#[context] ctx: EitherContext) -> Result<EitherContext, RpcError> {
|
||||
Ok(ctx)
|
||||
pub fn main_api() -> Result<(), RpcError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[command(subcommands(
|
||||
@@ -79,8 +79,8 @@ pub fn main_api(#[context] ctx: EitherContext) -> Result<EitherContext, RpcError
|
||||
control::start,
|
||||
control::stop
|
||||
))]
|
||||
pub fn package(#[context] ctx: EitherContext) -> Result<EitherContext, RpcError> {
|
||||
Ok(ctx)
|
||||
pub fn package() -> Result<(), RpcError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[command(subcommands(
|
||||
@@ -90,6 +90,6 @@ pub fn package(#[context] ctx: EitherContext) -> Result<EitherContext, RpcError>
|
||||
developer::init,
|
||||
inspect::inspect
|
||||
))]
|
||||
pub fn portable_api(#[context] ctx: EitherContext) -> Result<EitherContext, RpcError> {
|
||||
Ok(ctx)
|
||||
pub fn portable_api() -> Result<(), RpcError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -6,18 +6,16 @@ use isocountry::CountryCode;
|
||||
use rpc_toolkit::command;
|
||||
use tokio::process::Command;
|
||||
|
||||
use crate::context::EitherContext;
|
||||
use crate::util::{display_none, display_serializable, Invoke, IoFormat};
|
||||
use crate::{Error, ErrorKind};
|
||||
|
||||
#[command(subcommands(add, connect, delete, get, set_country))]
|
||||
pub async fn wifi(#[context] ctx: EitherContext) -> Result<EitherContext, Error> {
|
||||
Ok(ctx)
|
||||
pub async fn wifi() -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[command(display(display_none))]
|
||||
pub async fn add(
|
||||
#[context] _ctx: EitherContext,
|
||||
#[arg] ssid: String,
|
||||
#[arg] password: String,
|
||||
#[arg] priority: isize,
|
||||
@@ -73,7 +71,7 @@ pub async fn add(
|
||||
}
|
||||
|
||||
#[command(display(display_none))]
|
||||
pub async fn connect(#[context] _ctx: EitherContext, #[arg] ssid: String) -> Result<(), Error> {
|
||||
pub async fn connect(#[arg] ssid: String) -> Result<(), Error> {
|
||||
if !ssid.is_ascii() {
|
||||
return Err(Error::new(
|
||||
anyhow::anyhow!("SSID may not have special characters"),
|
||||
@@ -111,7 +109,7 @@ pub async fn connect(#[context] _ctx: EitherContext, #[arg] ssid: String) -> Res
|
||||
}
|
||||
|
||||
#[command(display(display_none))]
|
||||
pub async fn delete(#[context] _ctx: EitherContext, #[arg] ssid: String) -> Result<(), Error> {
|
||||
pub async fn delete(#[arg] ssid: String) -> Result<(), Error> {
|
||||
if !ssid.is_ascii() {
|
||||
return Err(Error::new(
|
||||
anyhow::anyhow!("SSID may not have special characters"),
|
||||
@@ -195,7 +193,6 @@ fn display_wifi_info(info: WiFiInfo, matches: &ArgMatches<'_>) {
|
||||
|
||||
#[command(display(display_wifi_info))]
|
||||
pub async fn get(
|
||||
#[context] _ctx: EitherContext,
|
||||
#[allow(unused_variables)]
|
||||
#[arg(long = "format")]
|
||||
format: Option<IoFormat>,
|
||||
@@ -239,7 +236,6 @@ pub async fn get(
|
||||
|
||||
#[command(display(display_none))]
|
||||
pub async fn set_country(
|
||||
#[context] _ctx: EitherContext,
|
||||
#[arg(parse(country_code_parse))] country: CountryCode,
|
||||
) -> Result<(), Error> {
|
||||
let wpa_supplicant = WpaCli { interface: "wlan0" };
|
||||
|
||||
@@ -5,7 +5,7 @@ use anyhow::anyhow;
|
||||
use rpc_toolkit::command;
|
||||
use rpc_toolkit::yajrc::RpcError;
|
||||
|
||||
use crate::context::{CliContext, EitherContext};
|
||||
use crate::context::CliContext;
|
||||
use crate::s9pk::builder::S9pkPacker;
|
||||
use crate::s9pk::manifest::Manifest;
|
||||
use crate::s9pk::reader::S9pkReader;
|
||||
@@ -21,12 +21,10 @@ pub mod reader;
|
||||
pub const SIG_CONTEXT: &'static [u8] = b"s9pk";
|
||||
|
||||
#[command(cli_only, display(display_none), blocking)]
|
||||
pub fn pack(#[context] ctx: EitherContext, #[arg] path: Option<PathBuf>) -> Result<(), Error> {
|
||||
pub fn pack(#[context] ctx: CliContext, #[arg] path: Option<PathBuf>) -> Result<(), Error> {
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
|
||||
let ctx = ctx.as_cli().unwrap();
|
||||
|
||||
let path = if let Some(path) = path {
|
||||
path
|
||||
} else {
|
||||
@@ -110,7 +108,7 @@ pub fn pack(#[context] ctx: EitherContext, #[arg] path: Option<PathBuf>) -> Resu
|
||||
}
|
||||
|
||||
#[command(cli_only, display(display_none))]
|
||||
pub async fn verify(#[context] _ctx: EitherContext, #[arg] path: PathBuf) -> Result<(), Error> {
|
||||
pub async fn verify(#[arg] path: PathBuf) -> Result<(), Error> {
|
||||
let mut s9pk = S9pkReader::open(path).await?;
|
||||
s9pk.validate().await?;
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ use clap::ArgMatches;
|
||||
use rpc_toolkit::command;
|
||||
use sqlx::{Pool, Sqlite};
|
||||
|
||||
use crate::context::EitherContext;
|
||||
use crate::context::RpcContext;
|
||||
use crate::util::{display_none, display_serializable, IoFormat};
|
||||
use crate::Error;
|
||||
|
||||
@@ -48,13 +48,13 @@ impl std::str::FromStr for PubKey {
|
||||
}
|
||||
|
||||
#[command(subcommands(add, remove, list,))]
|
||||
pub fn ssh(#[context] ctx: EitherContext) -> Result<EitherContext, Error> {
|
||||
Ok(ctx)
|
||||
pub fn ssh() -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[command(display(display_none))]
|
||||
pub async fn add(#[context] ctx: EitherContext, #[arg] key: PubKey) -> Result<String, Error> {
|
||||
let pool = &ctx.as_rpc().unwrap().secret_store;
|
||||
pub async fn add(#[context] ctx: RpcContext, #[arg] key: PubKey) -> Result<String, Error> {
|
||||
let pool = &ctx.secret_store;
|
||||
// check fingerprint for duplicates
|
||||
let fp = key.0.fingerprint_md5();
|
||||
if sqlx::query!("SELECT * FROM ssh_keys WHERE fingerprint = ?", fp)
|
||||
@@ -75,11 +75,8 @@ pub async fn add(#[context] ctx: EitherContext, #[arg] key: PubKey) -> Result<St
|
||||
Ok(fp)
|
||||
}
|
||||
#[command(display(display_none))]
|
||||
pub async fn remove(
|
||||
#[context] ctx: EitherContext,
|
||||
#[arg] fingerprint: String,
|
||||
) -> Result<(), Error> {
|
||||
let pool = &ctx.as_rpc().unwrap().secret_store;
|
||||
pub async fn remove(#[context] ctx: RpcContext, #[arg] fingerprint: String) -> Result<(), Error> {
|
||||
let pool = &ctx.secret_store;
|
||||
// check if fingerprint is in DB
|
||||
// if in DB, remove it from DB
|
||||
let n = sqlx::query!("DELETE FROM ssh_keys WHERE fingerprint = ?", fingerprint)
|
||||
@@ -128,12 +125,12 @@ fn display_all_ssh_keys(all: Vec<SshKeyResponse>, matches: &ArgMatches<'_>) {
|
||||
|
||||
#[command(display(display_all_ssh_keys))]
|
||||
pub async fn list(
|
||||
#[context] ctx: EitherContext,
|
||||
#[context] ctx: RpcContext,
|
||||
#[allow(unused_variables)]
|
||||
#[arg(long = "format")]
|
||||
format: Option<IoFormat>,
|
||||
) -> Result<Vec<SshKeyResponse>, Error> {
|
||||
let pool = &ctx.as_rpc().unwrap().secret_store;
|
||||
let pool = &ctx.secret_store;
|
||||
// list keys in DB and return them
|
||||
let entries = sqlx::query!("SELECT fingerprint, openssh_pubkey, created_at FROM ssh_keys")
|
||||
.fetch_all(pool)
|
||||
|
||||
@@ -31,7 +31,7 @@ use tokio_compat_02::FutureExt;
|
||||
// pub use v0_2_12::Version as Current;
|
||||
pub type Current = ();
|
||||
|
||||
use crate::context::{CliContext, EitherContext, RpcContext};
|
||||
use crate::context::{CliContext, RpcContext};
|
||||
use crate::util::{to_yaml_async_writer, AsyncCompat};
|
||||
use crate::{Error, ResultExt as _};
|
||||
|
||||
@@ -180,7 +180,7 @@ pub async fn self_update(requirement: emver::VersionRange) -> Result<(), Error>
|
||||
}
|
||||
|
||||
#[command(rename = "git-info", local)]
|
||||
pub fn git_info(#[context] _ctx: EitherContext) -> Result<String, Error> {
|
||||
pub fn git_info() -> Result<String, Error> {
|
||||
Ok(
|
||||
git_version::git_version!(args = ["--always", "--abbrev=40", "--dirty=-modified"])
|
||||
.to_owned(),
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
use super::*;
|
||||
|
||||
const V0_2_14: emver::Version = emver::Version::new(0, 2, 14, 0);
|
||||
|
||||
pub struct Version;
|
||||
#[async_trait]
|
||||
impl VersionT for Version {
|
||||
type Previous = v0_2_13::Version;
|
||||
fn new() -> Self {
|
||||
Version
|
||||
}
|
||||
fn semver(&self) -> &'static emver::Version {
|
||||
&V0_2_14
|
||||
}
|
||||
async fn up(&self) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
async fn down(&self) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user