From 457e3689fb3eba7d67ad575cf824ab4b6a6fe67b Mon Sep 17 00:00:00 2001 From: Justin Miller Date: Sat, 25 Sep 2021 15:48:32 -0600 Subject: [PATCH] chore: Make the download --- README.md | 2 +- appmgr/src/update/mod.rs | 67 ++++++++++++++++++++++++++++++++++------ 2 files changed, 58 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 880118572..86b1ea29b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# EmbassyOS +-# EmbassyOS [![Version](https://img.shields.io/github/v/tag/Start9Labs/embassy-os?color=success)](https://github.com/Start9Labs/embassy-os/releases) [![community](https://img.shields.io/badge/community-matrix-yellow)](https://matrix.to/#/#community:matrix.start9labs.com) [![community](https://img.shields.io/badge/community-telegram-informational)](https://t.me/start9_labs) diff --git a/appmgr/src/update/mod.rs b/appmgr/src/update/mod.rs index c40be2830..f95c06728 100644 --- a/appmgr/src/update/mod.rs +++ b/appmgr/src/update/mod.rs @@ -1,12 +1,20 @@ +use anyhow::anyhow; use clap::ArgMatches; +use digest::Digest; +use futures::Stream; use rpc_toolkit::command; use serde_json::Value; +use sha2::Sha256; +use tokio::io::AsyncWriteExt; +use tokio::pin; +use tokio_stream::StreamExt; use crate::context::RpcContext; use crate::update::latest_information::LatestInformation; use crate::{Error, ErrorKind, ResultExt}; const URL: &str = "https://beta-registry-0-3.start9labs.com/eos/latest"; +const HEADER_KEY: &str = "CHECKSUM"; mod latest_information; pub fn display_properties(response: (), _: &ArgMatches<'_>) { @@ -14,13 +22,13 @@ pub fn display_properties(response: (), _: &ArgMatches<'_>) { } #[command(display(display_properties))] pub async fn update_system(#[context] ctx: RpcContext) -> Result<(), Error> { - if let None = fetch_file(ctx).await? { + if let None = maybe_do_update(ctx).await? { return Ok(()); } todo!() } -pub async fn fetch_file(ctx: RpcContext) -> Result, Error> { +pub async fn maybe_do_update(mut ctx: RpcContext) -> Result, Error> { let mut db = ctx.db.handle(); let latest_version = reqwest::get(URL) .await @@ -32,22 +40,61 @@ pub async fn fetch_file(ctx: RpcContext) -> Result, Error> { let current_version = crate::db::DatabaseModel::new() .server_info() .version() - .get(&mut db, false) + .get_mut(&mut db) .await?; if &latest_version > ¤t_version { - todo!("If new pull down only one (Mutex lock this)") + let file_name = "/tmp/test"; + download_file(file_name).await?; + swap(&mut ctx).await?; + Ok(Some(())) } else { - todo!("Skip the rest") + Ok(None) } } -pub async fn check_download(ctx: RpcContext) -> Result { - let hash_from_header = todo!(); - let hash_from_file = todo!(); - todo!("Fail if bad check") +pub async fn download_file(file_name: &str) -> Result<(), Error> { + let download_request = reqwest::get(URL).await.with_kind(ErrorKind::Network)?; + let hash_from_header: String = download_request + .headers() + .get(HEADER_KEY) + .ok_or_else(|| Error::new(anyhow!("No {} in headers", HEADER_KEY), ErrorKind::Network))? + .to_str() + .with_kind(ErrorKind::InvalidRequest)? + .to_owned(); + let stream_download = download_request.bytes_stream(); + let file_sum = write_stream_to_file(stream_download, file_name).await?; + check_download(&hash_from_header, file_sum).await?; + Ok(()) } -pub async fn swap(ctx: RpcContext) -> Result { +async fn write_stream_to_file( + stream_download: impl Stream>, + file: &str, +) -> Result, Error> { + let mut file = tokio::fs::File::create(file) + .await + .with_kind(ErrorKind::Filesystem)?; + let mut hasher = Sha256::new(); + pin!(stream_download); + while let Some(Ok(item)) = stream_download.next().await { + file.write(&item).await.with_kind(ErrorKind::Filesystem)?; + hasher.update(item); + } + Ok(hasher.finalize().to_vec()) +} + +pub async fn check_download(hash_from_header: &str, file_digest: Vec) -> Result<(), Error> { + if hex::decode(hash_from_header).with_kind(ErrorKind::Network)? != file_digest { + return Err(Error::new( + anyhow!("Hash sum does not match source"), + ErrorKind::Network, + )); + } + Ok(()) +} + +pub async fn swap(ctx: &mut RpcContext) -> Result { + // disk/util add setLabel todo!("Do swap"); todo!("Let system know that we need a reboot or something") }