mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
Feature/lxc container runtime (#2514)
* wip: static-server errors * wip: fix wifi * wip: Fix the service_effects * wip: Fix cors in the middleware * wip(chore): Auth clean up the lint. * wip(fix): Vhost * wip: continue manager refactor Co-authored-by: J H <Blu-J@users.noreply.github.com> * wip: service manager refactor * wip: Some fixes * wip(fix): Fix the lib.rs * wip * wip(fix): Logs * wip: bins * wip(innspect): Add in the inspect * wip: config * wip(fix): Diagnostic * wip(fix): Dependencies * wip: context * wip(fix) Sorta auth * wip: warnings * wip(fix): registry/admin * wip(fix) marketplace * wip(fix) Some more converted and fixed with the linter and config * wip: Working on the static server * wip(fix)static server * wip: Remove some asynnc * wip: Something about the request and regular rpc * wip: gut install Co-authored-by: J H <Blu-J@users.noreply.github.com> * wip: Convert the static server into the new system * wip delete file * test * wip(fix) vhost does not need the with safe defaults * wip: Adding in the wifi * wip: Fix the developer and the verify * wip: new install flow Co-authored-by: J H <Blu-J@users.noreply.github.com> * fix middleware * wip * wip: Fix the auth * wip * continue service refactor * feature: Service get_config * feat: Action * wip: Fighting the great fight against the borrow checker * wip: Remove an error in a file that I just need to deel with later * chore: Add in some more lifetime stuff to the services * wip: Install fix on lifetime * cleanup * wip: Deal with the borrow later * more cleanup * resolve borrowchecker errors * wip(feat): add in the handler for the socket, for now * wip(feat): Update the service_effect_handler::action * chore: Add in the changes to make sure the from_service goes to context * chore: Change the * refactor service map * fix references to service map * fill out restore * wip: Before I work on the store stuff * fix backup module * handle some warnings * feat: add in the ui components on the rust side * feature: Update the procedures * chore: Update the js side of the main and a few of the others * chore: Update the rpc listener to match the persistant container * wip: Working on updating some things to have a better name * wip(feat): Try and get the rpc to return the correct shape? * lxc wip * wip(feat): Try and get the rpc to return the correct shape? * build for container runtime wip * remove container-init * fix build * fix error * chore: Update to work I suppose * lxc wip * remove docker module and feature * download alpine squashfs automatically * overlays effect Co-authored-by: Jade <Blu-J@users.noreply.github.com> * chore: Add the overlay effect * feat: Add the mounter in the main * chore: Convert to use the mounts, still need to work with the sandbox * install fixes * fix ssl * fixes from testing * implement tmpfile for upload * wip * misc fixes * cleanup * cleanup * better progress reporting * progress for sideload * return real guid * add devmode script * fix lxc rootfs path * fix percentage bar * fix progress bar styling * fix build for unstable * tweaks * label progress * tweaks * update progress more often * make symlink in rpc_client * make socket dir * fix parent path * add start-cli to container * add echo and gitInfo commands * wip: Add the init + errors * chore: Add in the exit effect for the system * chore: Change the type to null for failure to parse * move sigterm timeout to stopping status * update order * chore: Update the return type * remove dbg * change the map error * chore: Update the thing to capture id * chore add some life changes * chore: Update the loging * chore: Update the package to run module * us From for RpcError * chore: Update to use import instead * chore: update * chore: Use require for the backup * fix a default * update the type that is wrong * chore: Update the type of the manifest * chore: Update to make null * only symlink if not exists * get rid of double result * better debug info for ErrorCollection * chore: Update effects * chore: fix * mount assets and volumes * add exec instead of spawn * fix mounting in image * fix overlay mounts Co-authored-by: Jade <Blu-J@users.noreply.github.com> * misc fixes * feat: Fix two * fix: systemForEmbassy main * chore: Fix small part of main loop * chore: Modify the bundle * merge * fixMain loop" * move tsc to makefile * chore: Update the return types of the health check * fix client * chore: Convert the todo to use tsmatches * add in the fixes for the seen and create the hack to allow demo * chore: Update to include the systemForStartOs * chore UPdate to the latest types from the expected outout * fixes * fix typo * Don't emit if failure on tsc * wip Co-authored-by: Jade <Blu-J@users.noreply.github.com> * add s9pk api * add inspection * add inspect manifest * newline after display serializable * fix squashfs in image name * edit manifest Co-authored-by: Jade <Blu-J@users.noreply.github.com> * wait for response on repl * ignore sig for now * ignore sig for now * re-enable sig verification * fix * wip * env and chroot * add profiling logs * set uid & gid in squashfs to 100000 * set uid of sqfs to 100000 * fix mksquashfs args * add env to compat * fix * re-add docker feature flag * fix docker output format being stupid * here be dragons * chore: Add in the cross compiling for something * fix npm link * extract logs from container on exit * chore: Update for testing * add log capture to drop trait * chore: add in the modifications that I make * chore: Update small things for no updates * chore: Update the types of something * chore: Make main not complain * idmapped mounts * idmapped volumes * re-enable kiosk * chore: Add in some logging for the new system * bring in start-sdk * remove avahi * chore: Update the deps * switch to musl * chore: Update the version of prettier * chore: Organize' * chore: Update some of the headers back to the standard of fetch * fix musl build * fix idmapped mounts * fix cross build * use cross compiler for correct arch * feat: Add in the faked ssl stuff for the effects * @dr_bonez Did a solution here * chore: Something that DrBonez * chore: up * wip: We have a working server!!! * wip * uninstall * wip * tes --------- Co-authored-by: J H <dragondef@gmail.com> Co-authored-by: J H <Blu-J@users.noreply.github.com> Co-authored-by: J H <2364004+Blu-J@users.noreply.github.com>
This commit is contained in:
@@ -1,61 +1,52 @@
|
||||
pub mod model;
|
||||
pub mod package;
|
||||
pub mod prelude;
|
||||
|
||||
use std::future::Future;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
use futures::{FutureExt, SinkExt, StreamExt};
|
||||
use axum::extract::ws::{self, WebSocket};
|
||||
use axum::extract::WebSocketUpgrade;
|
||||
use axum::response::Response;
|
||||
use clap::Parser;
|
||||
use futures::{FutureExt, StreamExt};
|
||||
use http::header::COOKIE;
|
||||
use http::HeaderMap;
|
||||
use patch_db::json_ptr::JsonPointer;
|
||||
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};
|
||||
use rpc_toolkit::yajrc::RpcError;
|
||||
use rpc_toolkit::{command, from_fn_async, CallRemote, HandlerExt, ParentHandler};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use tokio::sync::oneshot;
|
||||
use tokio::task::JoinError;
|
||||
use tokio_tungstenite::tungstenite::protocol::frame::coding::CloseCode;
|
||||
use tokio_tungstenite::tungstenite::protocol::CloseFrame;
|
||||
use tokio_tungstenite::tungstenite::Message;
|
||||
use tokio_tungstenite::WebSocketStream;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::context::{CliContext, RpcContext};
|
||||
use crate::middleware::auth::{HasValidSession, HashSessionToken};
|
||||
use crate::prelude::*;
|
||||
use crate::util::display_none;
|
||||
use crate::util::serde::{display_serializable, IoFormat};
|
||||
use crate::util::serde::{apply_expr, HandlerExtSerde};
|
||||
|
||||
#[instrument(skip_all)]
|
||||
async fn ws_handler<
|
||||
WSFut: Future<Output = Result<Result<WebSocketStream<Upgraded>, HyperError>, JoinError>>,
|
||||
>(
|
||||
async fn ws_handler(
|
||||
ctx: RpcContext,
|
||||
session: Option<(HasValidSession, HashSessionToken)>,
|
||||
ws_fut: WSFut,
|
||||
mut stream: WebSocket,
|
||||
) -> Result<(), Error> {
|
||||
let (dump, sub) = ctx.db.dump_and_sub().await;
|
||||
let mut stream = ws_fut
|
||||
.await
|
||||
.with_kind(ErrorKind::Network)?
|
||||
.with_kind(ErrorKind::Unknown)?;
|
||||
|
||||
if let Some((session, token)) = session {
|
||||
let kill = subscribe_to_session_kill(&ctx, token).await;
|
||||
send_dump(session, &mut stream, dump).await?;
|
||||
send_dump(session.clone(), &mut stream, dump).await?;
|
||||
|
||||
deal_with_messages(session, kill, sub, stream).await?;
|
||||
} else {
|
||||
stream
|
||||
.close(Some(CloseFrame {
|
||||
code: CloseCode::Error,
|
||||
.send(ws::Message::Close(Some(ws::CloseFrame {
|
||||
code: ws::close_code::ERROR,
|
||||
reason: "UNAUTHORIZED".into(),
|
||||
}))
|
||||
})))
|
||||
.await
|
||||
.with_kind(ErrorKind::Network)?;
|
||||
drop(stream);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -80,7 +71,7 @@ async fn deal_with_messages(
|
||||
_has_valid_authentication: HasValidSession,
|
||||
mut kill: oneshot::Receiver<()>,
|
||||
mut sub: patch_db::Subscriber,
|
||||
mut stream: WebSocketStream<Upgraded>,
|
||||
mut stream: WebSocket,
|
||||
) -> Result<(), Error> {
|
||||
let mut timer = tokio::time::interval(tokio::time::Duration::from_secs(5));
|
||||
|
||||
@@ -89,18 +80,18 @@ async fn deal_with_messages(
|
||||
_ = (&mut kill).fuse() => {
|
||||
tracing::info!("Closing WebSocket: Reason: Session Terminated");
|
||||
stream
|
||||
.close(Some(CloseFrame {
|
||||
code: CloseCode::Error,
|
||||
reason: "UNAUTHORIZED".into(),
|
||||
}))
|
||||
.await
|
||||
.with_kind(ErrorKind::Network)?;
|
||||
.send(ws::Message::Close(Some(ws::CloseFrame {
|
||||
code: ws::close_code::ERROR,
|
||||
reason: "UNAUTHORIZED".into(),
|
||||
}))).await
|
||||
.with_kind(ErrorKind::Network)?;
|
||||
drop(stream);
|
||||
return Ok(())
|
||||
}
|
||||
new_rev = sub.recv().fuse() => {
|
||||
let rev = new_rev.expect("UNREACHABLE: patch-db is dropped");
|
||||
stream
|
||||
.send(Message::Text(serde_json::to_string(&rev).with_kind(ErrorKind::Serialization)?))
|
||||
.send(ws::Message::Text(serde_json::to_string(&rev).with_kind(ErrorKind::Serialization)?))
|
||||
.await
|
||||
.with_kind(ErrorKind::Network)?;
|
||||
}
|
||||
@@ -117,7 +108,7 @@ async fn deal_with_messages(
|
||||
// This is trying to give a health checks to the home to keep the ui alive.
|
||||
_ = timer.tick().fuse() => {
|
||||
stream
|
||||
.send(Message::Ping(vec![]))
|
||||
.send(ws::Message::Ping(vec![]))
|
||||
.await
|
||||
.with_kind(crate::ErrorKind::Network)?;
|
||||
}
|
||||
@@ -127,11 +118,11 @@ async fn deal_with_messages(
|
||||
|
||||
async fn send_dump(
|
||||
_has_valid_authentication: HasValidSession,
|
||||
stream: &mut WebSocketStream<Upgraded>,
|
||||
stream: &mut WebSocket,
|
||||
dump: Dump,
|
||||
) -> Result<(), Error> {
|
||||
stream
|
||||
.send(Message::Text(
|
||||
.send(ws::Message::Text(
|
||||
serde_json::to_string(&dump).with_kind(ErrorKind::Serialization)?,
|
||||
))
|
||||
.await
|
||||
@@ -139,11 +130,14 @@ async fn send_dump(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn subscribe(ctx: RpcContext, req: Request<Body>) -> Result<Response<Body>, Error> {
|
||||
let (parts, body) = req.into_parts();
|
||||
pub async fn subscribe(
|
||||
ctx: RpcContext,
|
||||
headers: HeaderMap,
|
||||
ws: WebSocketUpgrade,
|
||||
) -> Result<Response, Error> {
|
||||
let session = match async {
|
||||
let token = HashSessionToken::from_request_parts(&parts)?;
|
||||
let session = HasValidSession::from_request_parts(&parts, &ctx).await?;
|
||||
let token = HashSessionToken::from_header(headers.get(COOKIE))?;
|
||||
let session = HasValidSession::from_header(headers.get(COOKIE), &ctx).await?;
|
||||
Ok::<_, Error>((session, token))
|
||||
}
|
||||
.await
|
||||
@@ -157,26 +151,24 @@ pub async fn subscribe(ctx: RpcContext, req: Request<Body>) -> Result<Response<B
|
||||
None
|
||||
}
|
||||
};
|
||||
let req = Request::from_parts(parts, body);
|
||||
let (res, ws_fut) = hyper_ws_listener::create_ws(req).with_kind(ErrorKind::Network)?;
|
||||
if let Some(ws_fut) = ws_fut {
|
||||
tokio::task::spawn(async move {
|
||||
match ws_handler(ctx, session, ws_fut).await {
|
||||
Ok(()) => (),
|
||||
Err(e) => {
|
||||
tracing::error!("WebSocket Closed: {}", e);
|
||||
tracing::debug!("{:?}", e);
|
||||
}
|
||||
Ok(ws.on_upgrade(|ws| async move {
|
||||
match ws_handler(ctx, session, ws).await {
|
||||
Ok(()) => (),
|
||||
Err(e) => {
|
||||
tracing::error!("WebSocket Closed: {}", e);
|
||||
tracing::debug!("{:?}", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
#[command(subcommands(dump, put, apply))]
|
||||
pub fn db() -> Result<(), RpcError> {
|
||||
Ok(())
|
||||
pub fn db() -> ParentHandler {
|
||||
ParentHandler::new()
|
||||
.subcommand("dump", from_fn_async(cli_dump).with_display_serializable())
|
||||
.subcommand("dump", from_fn_async(dump).no_cli())
|
||||
.subcommand("put", put())
|
||||
.subcommand("apply", from_fn_async(cli_apply).no_display())
|
||||
.subcommand("apply", from_fn_async(apply).no_cli())
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
@@ -187,96 +179,36 @@ pub enum RevisionsRes {
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
async fn cli_dump(
|
||||
ctx: CliContext,
|
||||
_format: Option<IoFormat>,
|
||||
path: Option<PathBuf>,
|
||||
) -> Result<Dump, RpcError> {
|
||||
async fn cli_dump(ctx: CliContext, DumpParams { path }: DumpParams) -> Result<Dump, RpcError> {
|
||||
let dump = if let Some(path) = path {
|
||||
PatchDb::open(path).await?.dump().await
|
||||
} else {
|
||||
rpc_toolkit::command_helpers::call_remote(
|
||||
ctx,
|
||||
"db.dump",
|
||||
serde_json::json!({}),
|
||||
std::marker::PhantomData::<Dump>,
|
||||
)
|
||||
.await?
|
||||
.result?
|
||||
from_value::<Dump>(ctx.call_remote("db.dump", imbl_value::json!({})).await?)?
|
||||
};
|
||||
|
||||
Ok(dump)
|
||||
}
|
||||
|
||||
#[command(
|
||||
custom_cli(cli_dump(async, context(CliContext))),
|
||||
display(display_serializable)
|
||||
)]
|
||||
pub async fn dump(
|
||||
#[context] ctx: RpcContext,
|
||||
#[allow(unused_variables)]
|
||||
#[arg(long = "format")]
|
||||
format: Option<IoFormat>,
|
||||
#[allow(unused_variables)]
|
||||
#[arg]
|
||||
#[derive(Deserialize, Serialize, Parser)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
#[command(rename_all = "kebab-case")]
|
||||
pub struct DumpParams {
|
||||
path: Option<PathBuf>,
|
||||
) -> Result<Dump, Error> {
|
||||
}
|
||||
|
||||
// #[command(
|
||||
// custom_cli(cli_dump(async, context(CliContext))),
|
||||
// display(display_serializable)
|
||||
// )]
|
||||
pub async fn dump(ctx: RpcContext, _: DumpParams) -> Result<Dump, Error> {
|
||||
Ok(ctx.db.dump().await)
|
||||
}
|
||||
|
||||
fn apply_expr(input: jaq_core::Val, expr: &str) -> Result<jaq_core::Val, Error> {
|
||||
let (expr, errs) = jaq_core::parse::parse(expr, jaq_core::parse::main());
|
||||
|
||||
let Some(expr) = expr else {
|
||||
return Err(Error::new(
|
||||
eyre!("Failed to parse expression: {:?}", errs),
|
||||
crate::ErrorKind::InvalidRequest,
|
||||
));
|
||||
};
|
||||
|
||||
let mut errs = Vec::new();
|
||||
|
||||
let mut defs = jaq_core::Definitions::core();
|
||||
for def in jaq_std::std() {
|
||||
defs.insert(def, &mut errs);
|
||||
}
|
||||
|
||||
let filter = defs.finish(expr, Vec::new(), &mut errs);
|
||||
|
||||
if !errs.is_empty() {
|
||||
return Err(Error::new(
|
||||
eyre!("Failed to compile expression: {:?}", errs),
|
||||
crate::ErrorKind::InvalidRequest,
|
||||
));
|
||||
};
|
||||
|
||||
let inputs = jaq_core::RcIter::new(std::iter::empty());
|
||||
let mut res_iter = filter.run(jaq_core::Ctx::new([], &inputs), input);
|
||||
|
||||
let Some(res) = res_iter
|
||||
.next()
|
||||
.transpose()
|
||||
.map_err(|e| eyre!("{e}"))
|
||||
.with_kind(crate::ErrorKind::Deserialization)?
|
||||
else {
|
||||
return Err(Error::new(
|
||||
eyre!("expr returned no results"),
|
||||
crate::ErrorKind::InvalidRequest,
|
||||
));
|
||||
};
|
||||
|
||||
if res_iter.next().is_some() {
|
||||
return Err(Error::new(
|
||||
eyre!("expr returned too many results"),
|
||||
crate::ErrorKind::InvalidRequest,
|
||||
));
|
||||
}
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
async fn cli_apply(ctx: CliContext, expr: String, path: Option<PathBuf>) -> Result<(), RpcError> {
|
||||
async fn cli_apply(
|
||||
ctx: CliContext,
|
||||
ApplyParams { expr, path }: ApplyParams,
|
||||
) -> Result<(), RpcError> {
|
||||
if let Some(path) = path {
|
||||
PatchDb::open(path)
|
||||
.await?
|
||||
@@ -301,30 +233,22 @@ async fn cli_apply(ctx: CliContext, expr: String, path: Option<PathBuf>) -> Resu
|
||||
})
|
||||
.await?;
|
||||
} else {
|
||||
rpc_toolkit::command_helpers::call_remote(
|
||||
ctx,
|
||||
"db.apply",
|
||||
serde_json::json!({ "expr": expr }),
|
||||
std::marker::PhantomData::<()>,
|
||||
)
|
||||
.await?
|
||||
.result?;
|
||||
ctx.call_remote("db.apply", imbl_value::json!({ "expr": expr }))
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[command(
|
||||
custom_cli(cli_apply(async, context(CliContext))),
|
||||
display(display_none)
|
||||
)]
|
||||
pub async fn apply(
|
||||
#[context] ctx: RpcContext,
|
||||
#[arg] expr: String,
|
||||
#[allow(unused_variables)]
|
||||
#[arg]
|
||||
#[derive(Deserialize, Serialize, Parser)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
#[command(rename_all = "kebab-case")]
|
||||
pub struct ApplyParams {
|
||||
expr: String,
|
||||
path: Option<PathBuf>,
|
||||
) -> Result<(), Error> {
|
||||
}
|
||||
|
||||
pub async fn apply(ctx: RpcContext, ApplyParams { expr, .. }: ApplyParams) -> Result<(), Error> {
|
||||
ctx.db
|
||||
.mutate(|db| {
|
||||
let res = apply_expr(
|
||||
@@ -346,21 +270,25 @@ pub async fn apply(
|
||||
.await
|
||||
}
|
||||
|
||||
#[command(subcommands(ui))]
|
||||
pub fn put() -> Result<(), RpcError> {
|
||||
Ok(())
|
||||
pub fn put() -> ParentHandler {
|
||||
ParentHandler::new().subcommand(
|
||||
"ui",
|
||||
from_fn_async(ui)
|
||||
.with_display_serializable()
|
||||
.with_remote_cli::<CliContext>(),
|
||||
)
|
||||
}
|
||||
#[derive(Deserialize, Serialize, Parser)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
#[command(rename_all = "kebab-case")]
|
||||
pub struct UiParams {
|
||||
pointer: JsonPointer,
|
||||
value: Value,
|
||||
}
|
||||
|
||||
#[command(display(display_serializable))]
|
||||
// #[command(display(display_serializable))]
|
||||
#[instrument(skip_all)]
|
||||
pub async fn ui(
|
||||
#[context] ctx: RpcContext,
|
||||
#[arg] pointer: JsonPointer,
|
||||
#[arg] value: Value,
|
||||
#[allow(unused_variables)]
|
||||
#[arg(long = "format")]
|
||||
format: Option<IoFormat>,
|
||||
) -> Result<(), Error> {
|
||||
pub async fn ui(ctx: RpcContext, UiParams { pointer, value, .. }: UiParams) -> Result<(), Error> {
|
||||
let ptr = "/ui"
|
||||
.parse::<JsonPointer>()
|
||||
.with_kind(ErrorKind::Database)?
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||
use std::sync::Arc;
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use emver::VersionRange;
|
||||
@@ -8,8 +7,9 @@ use imbl_value::InternedString;
|
||||
use ipnet::{Ipv4Net, Ipv6Net};
|
||||
use isocountry::CountryCode;
|
||||
use itertools::Itertools;
|
||||
use models::{DataUrl, HealthCheckId, InterfaceId};
|
||||
use models::{DataUrl, HealthCheckId, InterfaceId, PackageId};
|
||||
use openssl::hash::MessageDigest;
|
||||
use patch_db::json_ptr::JsonPointer;
|
||||
use patch_db::{HasModel, Value};
|
||||
use reqwest::Url;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -17,12 +17,12 @@ use ssh_key::public::Ed25519PublicKey;
|
||||
|
||||
use crate::account::AccountInfo;
|
||||
use crate::config::spec::PackagePointerSpec;
|
||||
use crate::install::progress::InstallProgress;
|
||||
use crate::net::utils::{get_iface_ipv4_addr, get_iface_ipv6_addr};
|
||||
use crate::prelude::*;
|
||||
use crate::s9pk::manifest::{Manifest, PackageId};
|
||||
use crate::progress::FullProgress;
|
||||
use crate::s9pk::manifest::Manifest;
|
||||
use crate::status::Status;
|
||||
use crate::util::cpupower::{Governor};
|
||||
use crate::util::cpupower::Governor;
|
||||
use crate::util::Version;
|
||||
use crate::version::{Current, VersionT};
|
||||
use crate::{ARCH, PLATFORM};
|
||||
@@ -225,14 +225,14 @@ impl Map for AllPackageData {
|
||||
pub struct StaticFiles {
|
||||
license: String,
|
||||
instructions: String,
|
||||
icon: String,
|
||||
icon: DataUrl<'static>,
|
||||
}
|
||||
impl StaticFiles {
|
||||
pub fn local(id: &PackageId, version: &Version, icon_type: &str) -> Self {
|
||||
pub fn local(id: &PackageId, version: &Version, icon: DataUrl<'static>) -> Self {
|
||||
StaticFiles {
|
||||
license: format!("/public/package-data/{}/{}/LICENSE.md", id, version),
|
||||
instructions: format!("/public/package-data/{}/{}/INSTRUCTIONS.md", id, version),
|
||||
icon: format!("/public/package-data/{}/{}/icon.{}", id, version, icon_type),
|
||||
icon,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -243,7 +243,7 @@ impl StaticFiles {
|
||||
pub struct PackageDataEntryInstalling {
|
||||
pub static_files: StaticFiles,
|
||||
pub manifest: Manifest,
|
||||
pub install_progress: Arc<InstallProgress>,
|
||||
pub install_progress: FullProgress,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, HasModel)]
|
||||
@@ -253,7 +253,7 @@ pub struct PackageDataEntryUpdating {
|
||||
pub static_files: StaticFiles,
|
||||
pub manifest: Manifest,
|
||||
pub installed: InstalledPackageInfo,
|
||||
pub install_progress: Arc<InstallProgress>,
|
||||
pub install_progress: FullProgress,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, HasModel)]
|
||||
@@ -262,7 +262,7 @@ pub struct PackageDataEntryUpdating {
|
||||
pub struct PackageDataEntryRestoring {
|
||||
pub static_files: StaticFiles,
|
||||
pub manifest: Manifest,
|
||||
pub install_progress: Arc<InstallProgress>,
|
||||
pub install_progress: FullProgress,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, HasModel)]
|
||||
@@ -422,7 +422,7 @@ impl Model<PackageDataEntry> {
|
||||
PackageDataEntryMatchModelMut::Error(_) => None,
|
||||
}
|
||||
}
|
||||
pub fn as_install_progress(&self) -> Option<&Model<Arc<InstallProgress>>> {
|
||||
pub fn as_install_progress(&self) -> Option<&Model<FullProgress>> {
|
||||
match self.as_match() {
|
||||
PackageDataEntryMatchModelRef::Installing(a) => Some(a.as_install_progress()),
|
||||
PackageDataEntryMatchModelRef::Updating(a) => Some(a.as_install_progress()),
|
||||
@@ -432,7 +432,7 @@ impl Model<PackageDataEntry> {
|
||||
PackageDataEntryMatchModelRef::Error(_) => None,
|
||||
}
|
||||
}
|
||||
pub fn as_install_progress_mut(&mut self) -> Option<&mut Model<Arc<InstallProgress>>> {
|
||||
pub fn as_install_progress_mut(&mut self) -> Option<&mut Model<FullProgress>> {
|
||||
match self.as_match_mut() {
|
||||
PackageDataEntryMatchModelMut::Installing(a) => Some(a.as_install_progress_mut()),
|
||||
PackageDataEntryMatchModelMut::Updating(a) => Some(a.as_install_progress_mut()),
|
||||
@@ -459,6 +459,29 @@ pub struct InstalledPackageInfo {
|
||||
pub current_dependents: CurrentDependents,
|
||||
pub current_dependencies: CurrentDependencies,
|
||||
pub interface_addresses: InterfaceAddressMap,
|
||||
pub store: Value,
|
||||
pub store_exposed_ui: Vec<ExposedUI>,
|
||||
pub store_exposed_dependents: Vec<JsonPointer>,
|
||||
}
|
||||
#[derive(Debug, Deserialize, Serialize, HasModel)]
|
||||
#[model = "Model<Self>"]
|
||||
pub struct ExposedDependent {
|
||||
path: String,
|
||||
title: String,
|
||||
description: Option<String>,
|
||||
masked: Option<bool>,
|
||||
copyable: Option<bool>,
|
||||
qr: Option<bool>,
|
||||
}
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, HasModel)]
|
||||
#[model = "Model<Self>"]
|
||||
pub struct ExposedUI {
|
||||
path: Vec<JsonPointer>,
|
||||
title: String,
|
||||
description: Option<String>,
|
||||
masked: Option<bool>,
|
||||
copyable: Option<bool>,
|
||||
qr: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
||||
@@ -478,7 +501,6 @@ impl Map for CurrentDependents {
|
||||
type Key = PackageId;
|
||||
type Value = CurrentDependencyInfo;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
||||
pub struct CurrentDependencies(pub BTreeMap<PackageId, CurrentDependencyInfo>);
|
||||
impl CurrentDependencies {
|
||||
@@ -514,7 +536,7 @@ pub struct CurrentDependencyInfo {
|
||||
pub health_checks: BTreeSet<HealthCheckId>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Default, Deserialize, Serialize)]
|
||||
pub struct InterfaceAddressMap(pub BTreeMap<InterfaceId, InterfaceAddresses>);
|
||||
impl Map for InterfaceAddressMap {
|
||||
type Key = InterfaceId;
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
use models::Version;
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::s9pk::manifest::PackageId;
|
||||
|
||||
pub fn get_packages(db: Peeked) -> Result<Vec<(PackageId, Version)>, Error> {
|
||||
Ok(db
|
||||
.as_package_data()
|
||||
.keys()?
|
||||
.into_iter()
|
||||
.flat_map(|package_id| {
|
||||
let version = db
|
||||
.as_package_data()
|
||||
.as_idx(&package_id)?
|
||||
.as_manifest()
|
||||
.as_version()
|
||||
.de()
|
||||
.ok()?;
|
||||
Some((package_id, version))
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
@@ -2,8 +2,9 @@ use std::collections::BTreeMap;
|
||||
use std::marker::PhantomData;
|
||||
use std::panic::UnwindSafe;
|
||||
|
||||
pub use imbl_value::Value;
|
||||
use patch_db::value::InternedString;
|
||||
pub use patch_db::{HasModel, PatchDb, Value};
|
||||
pub use patch_db::{HasModel, PatchDb};
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::Serialize;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user