mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-04-04 14:29:45 +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,55 +1,46 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::path::Path;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use clap::ArgMatches;
|
||||
use futures::future::BoxFuture;
|
||||
use futures::{stream, FutureExt, StreamExt};
|
||||
use clap::Parser;
|
||||
use futures::{stream, StreamExt};
|
||||
use models::PackageId;
|
||||
use openssl::x509::X509;
|
||||
use rpc_toolkit::command;
|
||||
use sqlx::Connection;
|
||||
use tokio::fs::File;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use torut::onion::OnionAddressV3;
|
||||
use tracing::instrument;
|
||||
|
||||
use super::target::BackupTargetId;
|
||||
use crate::backup::os::OsBackup;
|
||||
use crate::backup::BackupMetadata;
|
||||
use crate::context::rpc::RpcContextConfig;
|
||||
use crate::context::{RpcContext, SetupContext};
|
||||
use crate::db::model::{PackageDataEntry, PackageDataEntryRestoring, StaticFiles};
|
||||
use crate::disk::mount::backup::{BackupMountGuard, PackageBackupMountGuard};
|
||||
use crate::disk::mount::backup::BackupMountGuard;
|
||||
use crate::disk::mount::filesystem::ReadWrite;
|
||||
use crate::disk::mount::guard::TmpMountGuard;
|
||||
use crate::disk::mount::guard::{GenericMountGuard, TmpMountGuard};
|
||||
use crate::hostname::Hostname;
|
||||
use crate::init::init;
|
||||
use crate::install::progress::InstallProgress;
|
||||
use crate::install::{download_install_s9pk, PKG_PUBLIC_DIR};
|
||||
use crate::notifications::NotificationLevel;
|
||||
use crate::prelude::*;
|
||||
use crate::s9pk::manifest::{Manifest, PackageId};
|
||||
use crate::s9pk::reader::S9pkReader;
|
||||
use crate::setup::SetupStatus;
|
||||
use crate::util::display_none;
|
||||
use crate::util::io::dir_size;
|
||||
use crate::s9pk::S9pk;
|
||||
use crate::service::service_map::DownloadInstallFuture;
|
||||
use crate::util::serde::IoFormat;
|
||||
use crate::volume::{backup_dir, BACKUP_DIR, PKG_VOLUME_DIR};
|
||||
|
||||
fn parse_comma_separated(arg: &str, _: &ArgMatches) -> Result<Vec<PackageId>, Error> {
|
||||
arg.split(',')
|
||||
.map(|s| s.trim().parse().map_err(Error::from))
|
||||
.collect()
|
||||
#[derive(Deserialize, Serialize, Parser)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
#[command(rename_all = "kebab-case")]
|
||||
pub struct RestorePackageParams {
|
||||
pub ids: Vec<PackageId>,
|
||||
pub target_id: BackupTargetId,
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
#[command(rename = "restore", display(display_none))]
|
||||
// TODO dr Why doesn't anything use this
|
||||
// #[command(rename = "restore", display(display_none))]
|
||||
#[instrument(skip(ctx, password))]
|
||||
pub async fn restore_packages_rpc(
|
||||
#[context] ctx: RpcContext,
|
||||
#[arg(parse(parse_comma_separated))] ids: Vec<PackageId>,
|
||||
#[arg(rename = "target-id")] target_id: BackupTargetId,
|
||||
#[arg] password: String,
|
||||
ctx: RpcContext,
|
||||
RestorePackageParams {
|
||||
ids,
|
||||
target_id,
|
||||
password,
|
||||
}: RestorePackageParams,
|
||||
) -> Result<(), Error> {
|
||||
let fs = target_id
|
||||
.load(ctx.secret_store.acquire().await?.as_mut())
|
||||
@@ -57,114 +48,25 @@ pub async fn restore_packages_rpc(
|
||||
let backup_guard =
|
||||
BackupMountGuard::mount(TmpMountGuard::mount(&fs, ReadWrite).await?, &password).await?;
|
||||
|
||||
let (backup_guard, tasks, _) = restore_packages(&ctx, backup_guard, ids).await?;
|
||||
let tasks = restore_packages(&ctx, backup_guard, ids).await?;
|
||||
|
||||
tokio::spawn(async move {
|
||||
stream::iter(tasks.into_iter().map(|x| (x, ctx.clone())))
|
||||
.for_each_concurrent(5, |(res, ctx)| async move {
|
||||
match res.await {
|
||||
(Ok(_), _) => (),
|
||||
(Err(err), package_id) => {
|
||||
if let Err(err) = ctx
|
||||
.notification_manager
|
||||
.notify(
|
||||
ctx.db.clone(),
|
||||
Some(package_id.clone()),
|
||||
NotificationLevel::Error,
|
||||
"Restoration Failure".to_string(),
|
||||
format!("Error restoring package {}: {}", package_id, err),
|
||||
(),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
{
|
||||
tracing::error!("Failed to notify: {}", err);
|
||||
tracing::debug!("{:?}", err);
|
||||
};
|
||||
tracing::error!("Error restoring package {}: {}", package_id, err);
|
||||
stream::iter(tasks)
|
||||
.for_each_concurrent(5, |(id, res)| async move {
|
||||
match async { res.await?.await }.await {
|
||||
Ok(_) => (),
|
||||
Err(err) => {
|
||||
tracing::error!("Error restoring package {}: {}", id, err);
|
||||
tracing::debug!("{:?}", err);
|
||||
}
|
||||
}
|
||||
})
|
||||
.await;
|
||||
if let Err(e) = backup_guard.unmount().await {
|
||||
tracing::error!("Error unmounting backup drive: {}", e);
|
||||
tracing::debug!("{:?}", e);
|
||||
}
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn approximate_progress(
|
||||
rpc_ctx: &RpcContext,
|
||||
progress: &mut ProgressInfo,
|
||||
) -> Result<(), Error> {
|
||||
for (id, size) in &mut progress.target_volume_size {
|
||||
let dir = rpc_ctx.datadir.join(PKG_VOLUME_DIR).join(id).join("data");
|
||||
if tokio::fs::metadata(&dir).await.is_err() {
|
||||
*size = 0;
|
||||
} else {
|
||||
*size = dir_size(&dir, None).await?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn approximate_progress_loop(
|
||||
ctx: &SetupContext,
|
||||
rpc_ctx: &RpcContext,
|
||||
mut starting_info: ProgressInfo,
|
||||
) {
|
||||
loop {
|
||||
if let Err(e) = approximate_progress(rpc_ctx, &mut starting_info).await {
|
||||
tracing::error!("Failed to approximate restore progress: {}", e);
|
||||
tracing::debug!("{:?}", e);
|
||||
} else {
|
||||
*ctx.setup_status.write().await = Some(Ok(starting_info.flatten()));
|
||||
}
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct ProgressInfo {
|
||||
package_installs: BTreeMap<PackageId, Arc<InstallProgress>>,
|
||||
src_volume_size: BTreeMap<PackageId, u64>,
|
||||
target_volume_size: BTreeMap<PackageId, u64>,
|
||||
}
|
||||
impl ProgressInfo {
|
||||
fn flatten(&self) -> SetupStatus {
|
||||
let mut total_bytes = 0;
|
||||
let mut bytes_transferred = 0;
|
||||
|
||||
for progress in self.package_installs.values() {
|
||||
total_bytes += ((progress.size.unwrap_or(0) as f64) * 2.2) as u64;
|
||||
bytes_transferred += progress.downloaded.load(Ordering::SeqCst);
|
||||
bytes_transferred += ((progress.validated.load(Ordering::SeqCst) as f64) * 0.2) as u64;
|
||||
bytes_transferred += progress.unpacked.load(Ordering::SeqCst);
|
||||
}
|
||||
|
||||
for size in self.src_volume_size.values() {
|
||||
total_bytes += *size;
|
||||
}
|
||||
|
||||
for size in self.target_volume_size.values() {
|
||||
bytes_transferred += *size;
|
||||
}
|
||||
|
||||
if bytes_transferred > total_bytes {
|
||||
bytes_transferred = total_bytes;
|
||||
}
|
||||
|
||||
SetupStatus {
|
||||
total_bytes: Some(total_bytes),
|
||||
bytes_transferred,
|
||||
complete: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(ctx))]
|
||||
pub async fn recover_full_embassy(
|
||||
ctx: SetupContext,
|
||||
@@ -179,7 +81,7 @@ pub async fn recover_full_embassy(
|
||||
)
|
||||
.await?;
|
||||
|
||||
let os_backup_path = backup_guard.as_ref().join("os-backup.cbor");
|
||||
let os_backup_path = backup_guard.path().join("os-backup.cbor");
|
||||
let mut os_backup: OsBackup = IoFormat::Cbor.from_slice(
|
||||
&tokio::fs::read(&os_backup_path)
|
||||
.await
|
||||
@@ -199,11 +101,9 @@ pub async fn recover_full_embassy(
|
||||
|
||||
secret_store.close().await;
|
||||
|
||||
let cfg = RpcContextConfig::load(ctx.config_path.clone()).await?;
|
||||
init(&ctx.config).await?;
|
||||
|
||||
init(&cfg).await?;
|
||||
|
||||
let rpc_ctx = RpcContext::init(ctx.config_path.clone(), disk_guid.clone()).await?;
|
||||
let rpc_ctx = RpcContext::init(&ctx.config, disk_guid.clone()).await?;
|
||||
|
||||
let ids: Vec<_> = backup_guard
|
||||
.metadata
|
||||
@@ -211,37 +111,19 @@ pub async fn recover_full_embassy(
|
||||
.keys()
|
||||
.cloned()
|
||||
.collect();
|
||||
let (backup_guard, tasks, progress_info) =
|
||||
restore_packages(&rpc_ctx, backup_guard, ids).await?;
|
||||
let task_consumer_rpc_ctx = rpc_ctx.clone();
|
||||
tokio::select! {
|
||||
_ = async move {
|
||||
stream::iter(tasks.into_iter().map(|x| (x, task_consumer_rpc_ctx.clone())))
|
||||
.for_each_concurrent(5, |(res, ctx)| async move {
|
||||
match res.await {
|
||||
(Ok(_), _) => (),
|
||||
(Err(err), package_id) => {
|
||||
if let Err(err) = ctx.notification_manager.notify(
|
||||
ctx.db.clone(),
|
||||
Some(package_id.clone()),
|
||||
NotificationLevel::Error,
|
||||
"Restoration Failure".to_string(), format!("Error restoring package {}: {}", package_id,err), (), None).await{
|
||||
tracing::error!("Failed to notify: {}", err);
|
||||
tracing::debug!("{:?}", err);
|
||||
};
|
||||
tracing::error!("Error restoring package {}: {}", package_id, err);
|
||||
tracing::debug!("{:?}", err);
|
||||
},
|
||||
}
|
||||
}).await;
|
||||
let tasks = restore_packages(&rpc_ctx, backup_guard, ids).await?;
|
||||
stream::iter(tasks)
|
||||
.for_each_concurrent(5, |(id, res)| async move {
|
||||
match async { res.await?.await }.await {
|
||||
Ok(_) => (),
|
||||
Err(err) => {
|
||||
tracing::error!("Error restoring package {}: {}", id, err);
|
||||
tracing::debug!("{:?}", err);
|
||||
}
|
||||
}
|
||||
})
|
||||
.await;
|
||||
|
||||
} => {
|
||||
|
||||
},
|
||||
_ = approximate_progress_loop(&ctx, &rpc_ctx, progress_info) => unreachable!(concat!(module_path!(), "::approximate_progress_loop should not terminate")),
|
||||
}
|
||||
|
||||
backup_guard.unmount().await?;
|
||||
rpc_ctx.shutdown().await?;
|
||||
|
||||
Ok((
|
||||
@@ -257,205 +139,25 @@ async fn restore_packages(
|
||||
ctx: &RpcContext,
|
||||
backup_guard: BackupMountGuard<TmpMountGuard>,
|
||||
ids: Vec<PackageId>,
|
||||
) -> Result<
|
||||
(
|
||||
BackupMountGuard<TmpMountGuard>,
|
||||
Vec<BoxFuture<'static, (Result<(), Error>, PackageId)>>,
|
||||
ProgressInfo,
|
||||
),
|
||||
Error,
|
||||
> {
|
||||
let guards = assure_restoring(ctx, ids, &backup_guard).await?;
|
||||
|
||||
let mut progress_info = ProgressInfo::default();
|
||||
|
||||
let mut tasks = Vec::with_capacity(guards.len());
|
||||
for (manifest, guard) in guards {
|
||||
let id = manifest.id.clone();
|
||||
let (progress, task) = restore_package(ctx.clone(), manifest, guard).await?;
|
||||
progress_info
|
||||
.package_installs
|
||||
.insert(id.clone(), progress.clone());
|
||||
progress_info
|
||||
.src_volume_size
|
||||
.insert(id.clone(), dir_size(backup_dir(&id), None).await?);
|
||||
progress_info.target_volume_size.insert(id.clone(), 0);
|
||||
let package_id = id.clone();
|
||||
tasks.push(
|
||||
async move {
|
||||
if let Err(e) = task.await {
|
||||
tracing::error!("Error restoring package {}: {}", id, e);
|
||||
tracing::debug!("{:?}", e);
|
||||
Err(e)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
.map(|x| (x, package_id))
|
||||
.boxed(),
|
||||
);
|
||||
}
|
||||
|
||||
Ok((backup_guard, tasks, progress_info))
|
||||
}
|
||||
|
||||
#[instrument(skip(ctx, backup_guard))]
|
||||
async fn assure_restoring(
|
||||
ctx: &RpcContext,
|
||||
ids: Vec<PackageId>,
|
||||
backup_guard: &BackupMountGuard<TmpMountGuard>,
|
||||
) -> Result<Vec<(Manifest, PackageBackupMountGuard)>, Error> {
|
||||
let mut guards = Vec::with_capacity(ids.len());
|
||||
|
||||
let mut insert_packages = BTreeMap::new();
|
||||
|
||||
) -> Result<BTreeMap<PackageId, DownloadInstallFuture>, Error> {
|
||||
let backup_guard = Arc::new(backup_guard);
|
||||
let mut tasks = BTreeMap::new();
|
||||
for id in ids {
|
||||
let peek = ctx.db.peek().await;
|
||||
|
||||
let model = peek.as_package_data().as_idx(&id);
|
||||
|
||||
if !model.is_none() {
|
||||
return Err(Error::new(
|
||||
eyre!("Can't restore over existing package: {}", id),
|
||||
crate::ErrorKind::InvalidRequest,
|
||||
));
|
||||
}
|
||||
let guard = backup_guard.mount_package_backup(&id).await?;
|
||||
let s9pk_path = Path::new(BACKUP_DIR).join(&id).join(format!("{}.s9pk", id));
|
||||
let mut rdr = S9pkReader::open(&s9pk_path, false).await?;
|
||||
|
||||
let manifest = rdr.manifest().await?;
|
||||
let version = manifest.version.clone();
|
||||
let progress = Arc::new(InstallProgress::new(Some(
|
||||
tokio::fs::metadata(&s9pk_path).await?.len(),
|
||||
)));
|
||||
|
||||
let public_dir_path = ctx
|
||||
.datadir
|
||||
.join(PKG_PUBLIC_DIR)
|
||||
.join(&id)
|
||||
.join(version.as_str());
|
||||
tokio::fs::create_dir_all(&public_dir_path).await?;
|
||||
|
||||
let license_path = public_dir_path.join("LICENSE.md");
|
||||
let mut dst = File::create(&license_path).await?;
|
||||
tokio::io::copy(&mut rdr.license().await?, &mut dst).await?;
|
||||
dst.sync_all().await?;
|
||||
|
||||
let instructions_path = public_dir_path.join("INSTRUCTIONS.md");
|
||||
let mut dst = File::create(&instructions_path).await?;
|
||||
tokio::io::copy(&mut rdr.instructions().await?, &mut dst).await?;
|
||||
dst.sync_all().await?;
|
||||
|
||||
let icon_path = Path::new("icon").with_extension(&manifest.assets.icon_type());
|
||||
let icon_path = public_dir_path.join(&icon_path);
|
||||
let mut dst = File::create(&icon_path).await?;
|
||||
tokio::io::copy(&mut rdr.icon().await?, &mut dst).await?;
|
||||
dst.sync_all().await?;
|
||||
insert_packages.insert(
|
||||
id.clone(),
|
||||
PackageDataEntry::Restoring(PackageDataEntryRestoring {
|
||||
install_progress: progress.clone(),
|
||||
static_files: StaticFiles::local(&id, &version, manifest.assets.icon_type()),
|
||||
manifest: manifest.clone(),
|
||||
}),
|
||||
);
|
||||
|
||||
guards.push((manifest, guard));
|
||||
}
|
||||
ctx.db
|
||||
.mutate(|db| {
|
||||
for (id, package) in insert_packages {
|
||||
db.as_package_data_mut().insert(&id, &package)?;
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.await?;
|
||||
Ok(guards)
|
||||
}
|
||||
|
||||
#[instrument(skip(ctx, guard))]
|
||||
async fn restore_package<'a>(
|
||||
ctx: RpcContext,
|
||||
manifest: Manifest,
|
||||
guard: PackageBackupMountGuard,
|
||||
) -> Result<(Arc<InstallProgress>, BoxFuture<'static, Result<(), Error>>), Error> {
|
||||
let id = manifest.id.clone();
|
||||
let s9pk_path = Path::new(BACKUP_DIR)
|
||||
.join(&manifest.id)
|
||||
.join(format!("{}.s9pk", id));
|
||||
|
||||
let metadata_path = Path::new(BACKUP_DIR).join(&id).join("metadata.cbor");
|
||||
let metadata: BackupMetadata = IoFormat::Cbor.from_slice(
|
||||
&tokio::fs::read(&metadata_path)
|
||||
.await
|
||||
.with_ctx(|_| (ErrorKind::Filesystem, metadata_path.display().to_string()))?,
|
||||
)?;
|
||||
|
||||
let mut secrets = ctx.secret_store.acquire().await?;
|
||||
let mut secrets_tx = secrets.begin().await?;
|
||||
for (iface, key) in metadata.network_keys {
|
||||
let k = key.0.as_slice();
|
||||
sqlx::query!(
|
||||
"INSERT INTO network_keys (package, interface, key) VALUES ($1, $2, $3) ON CONFLICT (package, interface) DO NOTHING",
|
||||
id.to_string(),
|
||||
iface.to_string(),
|
||||
k,
|
||||
)
|
||||
.execute(secrets_tx.as_mut()).await?;
|
||||
}
|
||||
// DEPRECATED
|
||||
for (iface, key) in metadata.tor_keys {
|
||||
let k = key.0.as_slice();
|
||||
sqlx::query!(
|
||||
"INSERT INTO tor (package, interface, key) VALUES ($1, $2, $3) ON CONFLICT (package, interface) DO NOTHING",
|
||||
id.to_string(),
|
||||
iface.to_string(),
|
||||
k,
|
||||
)
|
||||
.execute(secrets_tx.as_mut()).await?;
|
||||
}
|
||||
secrets_tx.commit().await?;
|
||||
drop(secrets);
|
||||
|
||||
let len = tokio::fs::metadata(&s9pk_path)
|
||||
.await
|
||||
.with_ctx(|_| (ErrorKind::Filesystem, s9pk_path.display().to_string()))?
|
||||
.len();
|
||||
let file = File::open(&s9pk_path)
|
||||
.await
|
||||
.with_ctx(|_| (ErrorKind::Filesystem, s9pk_path.display().to_string()))?;
|
||||
|
||||
let progress = InstallProgress::new(Some(len));
|
||||
let marketplace_url = metadata.marketplace_url;
|
||||
|
||||
let progress = Arc::new(progress);
|
||||
|
||||
ctx.db
|
||||
.mutate(|db| {
|
||||
db.as_package_data_mut().insert(
|
||||
&id,
|
||||
&PackageDataEntry::Restoring(PackageDataEntryRestoring {
|
||||
install_progress: progress.clone(),
|
||||
static_files: StaticFiles::local(
|
||||
&id,
|
||||
&manifest.version,
|
||||
manifest.assets.icon_type(),
|
||||
),
|
||||
manifest: manifest.clone(),
|
||||
}),
|
||||
let backup_dir = backup_guard.clone().package_backup(&id);
|
||||
let task = ctx
|
||||
.services
|
||||
.install(
|
||||
ctx.clone(),
|
||||
S9pk::open(
|
||||
backup_dir.path().join(&id).with_extension("s9pk"),
|
||||
Some(&id),
|
||||
)
|
||||
.await?,
|
||||
Some(backup_dir),
|
||||
)
|
||||
})
|
||||
.await?;
|
||||
Ok((
|
||||
progress.clone(),
|
||||
async move {
|
||||
download_install_s9pk(ctx, manifest, marketplace_url, progress, file, None).await?;
|
||||
.await?;
|
||||
tasks.insert(id, task);
|
||||
}
|
||||
|
||||
guard.unmount().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
.boxed(),
|
||||
))
|
||||
Ok(tasks)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user