mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 02:11:53 +00:00
feat: Make the start clear
Have messaging to let user know of update complete/ failure
This commit is contained in:
committed by
Aiden McClelland
parent
2b2451d22f
commit
7fc4cb175c
3
Makefile
3
Makefile
@@ -6,7 +6,7 @@ APPMGR_SRC := $(shell find appmgr/src) appmgr/Cargo.toml appmgr/Cargo.lock
|
|||||||
UI_SRC := $(shell find ui/src)
|
UI_SRC := $(shell find ui/src)
|
||||||
SETUP_WIZARD_SRC := $(shell find setup-wizard/src)
|
SETUP_WIZARD_SRC := $(shell find setup-wizard/src)
|
||||||
DIAGNOSTIC_UI_SRC := $(shell find diagnostic-ui/src)
|
DIAGNOSTIC_UI_SRC := $(shell find diagnostic-ui/src)
|
||||||
PATCH_DB_CLIENT_SRC = $(shell find patch-db/client)
|
PATCH_DB_CLIENT_SRC = $(shell find patch-db/client -not -path patch-db/client/dist)
|
||||||
|
|
||||||
all: eos.img
|
all: eos.img
|
||||||
|
|
||||||
@@ -71,6 +71,7 @@ patch-db/client/node_modules: patch-db/client/package.json
|
|||||||
npm --prefix patch-db/client install
|
npm --prefix patch-db/client install
|
||||||
|
|
||||||
patch-db/client/dist: $(PATCH_DB_CLIENT_SRC) patch-db/client/node_modules
|
patch-db/client/dist: $(PATCH_DB_CLIENT_SRC) patch-db/client/node_modules
|
||||||
|
! test -d patch-db/client/dist || rm -rf patch-db/client/dist
|
||||||
npm --prefix patch-db/client run build
|
npm --prefix patch-db/client run build
|
||||||
|
|
||||||
ui: $(EMBASSY_UIS)
|
ui: $(EMBASSY_UIS)
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use embassy::context::rpc::RpcContextConfig;
|
use embassy::context::rpc::RpcContextConfig;
|
||||||
use embassy::context::{DiagnosticContext, SetupContext};
|
use embassy::context::{DiagnosticContext, SetupContext};
|
||||||
|
use embassy::db::model::ServerStatus;
|
||||||
|
use embassy::db::DatabaseModel;
|
||||||
use embassy::disk::main::DEFAULT_PASSWORD;
|
use embassy::disk::main::DEFAULT_PASSWORD;
|
||||||
use embassy::hostname::get_product_key;
|
use embassy::hostname::get_product_key;
|
||||||
use embassy::middleware::cors::cors;
|
use embassy::middleware::cors::cors;
|
||||||
@@ -11,7 +13,7 @@ use embassy::middleware::encrypt::encrypt;
|
|||||||
#[cfg(feature = "avahi")]
|
#[cfg(feature = "avahi")]
|
||||||
use embassy::net::mdns::MdnsController;
|
use embassy::net::mdns::MdnsController;
|
||||||
use embassy::sound::MARIO_COIN;
|
use embassy::sound::MARIO_COIN;
|
||||||
use embassy::util::Invoke;
|
use embassy::util::{Invoke, Version};
|
||||||
use embassy::{Error, ResultExt};
|
use embassy::{Error, ResultExt};
|
||||||
use http::StatusCode;
|
use http::StatusCode;
|
||||||
use rpc_toolkit::rpc_server;
|
use rpc_toolkit::rpc_server;
|
||||||
@@ -144,6 +146,25 @@ async fn init(cfg_path: Option<&str>) -> Result<(), Error> {
|
|||||||
log::info!("Enabled nginx public dir");
|
log::info!("Enabled nginx public dir");
|
||||||
embassy::net::wifi::synchronize_wpa_supplicant_conf(&cfg.datadir().join("main")).await?;
|
embassy::net::wifi::synchronize_wpa_supplicant_conf(&cfg.datadir().join("main")).await?;
|
||||||
|
|
||||||
|
let db = cfg.db(&secret_store).await?;
|
||||||
|
let mut handle = db.handle();
|
||||||
|
let mut info = embassy::db::DatabaseModel::new()
|
||||||
|
.server_info()
|
||||||
|
.get_mut(&mut handle)
|
||||||
|
.await?;
|
||||||
|
match info.status {
|
||||||
|
ServerStatus::Running | ServerStatus::Updated | ServerStatus::BackingUp => {
|
||||||
|
info.status = ServerStatus::Running;
|
||||||
|
}
|
||||||
|
ServerStatus::Updating => {
|
||||||
|
info.update_progress = None;
|
||||||
|
info.status = ServerStatus::Running;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info.version = emver::Version::new(0, 3, 0, 0).into();
|
||||||
|
// TODO: run migrations
|
||||||
|
info.save(&mut handle).await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ pub struct ServerInfo {
|
|||||||
pub enum ServerStatus {
|
pub enum ServerStatus {
|
||||||
Running,
|
Running,
|
||||||
Updating,
|
Updating,
|
||||||
|
Updated,
|
||||||
BackingUp,
|
BackingUp,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -213,9 +213,9 @@ pub enum NotificationSubtype {
|
|||||||
}
|
}
|
||||||
impl NotificationSubtype {
|
impl NotificationSubtype {
|
||||||
fn to_json(&self) -> serde_json::Value {
|
fn to_json(&self) -> serde_json::Value {
|
||||||
match &self {
|
match self {
|
||||||
&NotificationSubtype::General => serde_json::Value::Null,
|
NotificationSubtype::General => serde_json::Value::Null,
|
||||||
&NotificationSubtype::BackupReport {
|
NotificationSubtype::BackupReport {
|
||||||
server_attempted,
|
server_attempted,
|
||||||
server_error,
|
server_error,
|
||||||
packages,
|
packages,
|
||||||
@@ -241,9 +241,9 @@ impl NotificationSubtype {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn code(&self) -> u32 {
|
fn code(&self) -> u32 {
|
||||||
match &self {
|
match self {
|
||||||
&Self::General => 0,
|
Self::General => 0,
|
||||||
&Self::BackupReport {
|
Self::BackupReport {
|
||||||
server_attempted: _,
|
server_attempted: _,
|
||||||
server_error: _,
|
server_error: _,
|
||||||
packages: _,
|
packages: _,
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
use anyhow::{anyhow, bail, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use clap::ArgMatches;
|
use clap::ArgMatches;
|
||||||
use digest::Digest;
|
use digest::Digest;
|
||||||
use emver::Version;
|
use emver::Version;
|
||||||
@@ -13,21 +14,31 @@ use regex::Regex;
|
|||||||
use reqwest::Url;
|
use reqwest::Url;
|
||||||
use rpc_toolkit::command;
|
use rpc_toolkit::command;
|
||||||
use sha2::Sha256;
|
use sha2::Sha256;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use tokio::io::AsyncWriteExt;
|
use tokio::io::AsyncWriteExt;
|
||||||
use tokio::pin;
|
use tokio::pin;
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
|
use tokio::time::Instant;
|
||||||
use tokio_stream::StreamExt;
|
use tokio_stream::StreamExt;
|
||||||
|
|
||||||
use crate::context::RpcContext;
|
use crate::context::RpcContext;
|
||||||
use crate::db::model::{ServerStatus, UpdateProgress};
|
use crate::db::model::{ServerStatus, UpdateProgress};
|
||||||
|
use crate::notifications::{NotificationLevel, NotificationSubtype};
|
||||||
use crate::update::latest_information::LatestInformation;
|
use crate::update::latest_information::LatestInformation;
|
||||||
use crate::util::Invoke;
|
use crate::util::Invoke;
|
||||||
use crate::{Error, ErrorKind, ResultExt};
|
use crate::{Error, ErrorKind, ResultExt};
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref UPDATED: AtomicBool = AtomicBool::new(false);
|
||||||
|
}
|
||||||
|
|
||||||
/// An user/ daemon would call this to update the system to the latest version and do the updates available,
|
/// An user/ daemon would call this to update the system to the latest version and do the updates available,
|
||||||
/// and this will return something if there is an update, and in that case there will need to be a restart.
|
/// and this will return something if there is an update, and in that case there will need to be a restart.
|
||||||
#[command(rename = "update", display(display_properties))]
|
#[command(rename = "update", display(display_properties))]
|
||||||
pub async fn update_system(#[context] ctx: RpcContext) -> Result<UpdateSystem, Error> {
|
pub async fn update_system(#[context] ctx: RpcContext) -> Result<UpdateSystem, Error> {
|
||||||
|
if UPDATED.load(Ordering::SeqCst) {
|
||||||
|
return Ok(UpdateSystem::NoUpdates);
|
||||||
|
}
|
||||||
if let None = maybe_do_update(ctx).await? {
|
if let None = maybe_do_update(ctx).await? {
|
||||||
return Ok(UpdateSystem::Updated);
|
return Ok(UpdateSystem::Updated);
|
||||||
}
|
}
|
||||||
@@ -52,7 +63,7 @@ fn display_properties(status: UpdateSystem, _: &ArgMatches<'_>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const HEADER_KEY: &str = "CHECKSUM";
|
const HEADER_KEY: &str = "x-eos-hash";
|
||||||
mod latest_information;
|
mod latest_information;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
@@ -170,13 +181,16 @@ async fn maybe_do_update(ctx: RpcContext) -> Result<Option<Arc<Revision>>, Error
|
|||||||
.get_mut(&mut tx)
|
.get_mut(&mut tx)
|
||||||
.await?;
|
.await?;
|
||||||
match &info.status {
|
match &info.status {
|
||||||
ServerStatus::Updating { .. } => {
|
ServerStatus::Updating => {
|
||||||
return Err(Error::new(
|
return Err(Error::new(
|
||||||
anyhow!("Server is already updating!"),
|
anyhow!("Server is already updating!"),
|
||||||
crate::ErrorKind::InvalidRequest,
|
crate::ErrorKind::InvalidRequest,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
ServerStatus::BackingUp {} => {
|
ServerStatus::Updated => {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
ServerStatus::BackingUp => {
|
||||||
return Err(Error::new(
|
return Err(Error::new(
|
||||||
anyhow!("Server is backing up!"),
|
anyhow!("Server is backing up!"),
|
||||||
crate::ErrorKind::InvalidRequest,
|
crate::ErrorKind::InvalidRequest,
|
||||||
@@ -191,7 +205,7 @@ async fn maybe_do_update(ctx: RpcContext) -> Result<Option<Arc<Revision>>, Error
|
|||||||
ctx.db.handle(),
|
ctx.db.handle(),
|
||||||
&EosUrl {
|
&EosUrl {
|
||||||
base: info.eos_marketplace.clone(),
|
base: info.eos_marketplace.clone(),
|
||||||
version: latest_version,
|
version: latest_version.clone(),
|
||||||
},
|
},
|
||||||
new_label,
|
new_label,
|
||||||
)
|
)
|
||||||
@@ -212,13 +226,26 @@ async fn maybe_do_update(ctx: RpcContext) -> Result<Option<Arc<Revision>>, Error
|
|||||||
.get_mut(&mut db)
|
.get_mut(&mut db)
|
||||||
.await
|
.await
|
||||||
.expect("could not access status");
|
.expect("could not access status");
|
||||||
info.status = ServerStatus::Running;
|
|
||||||
info.update_progress = None;
|
info.update_progress = None;
|
||||||
info.save(&mut db).await.expect("could not save status");
|
|
||||||
match res {
|
match res {
|
||||||
Ok(()) => todo!("issue notification"),
|
Ok(()) => {
|
||||||
|
info.status = ServerStatus::Updated;
|
||||||
|
info.save(&mut db).await.expect("could not save status");
|
||||||
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
todo!("{}, issue notification", e)
|
info.status = ServerStatus::Running;
|
||||||
|
info.save(&mut db).await.expect("could not save status");
|
||||||
|
drop(db);
|
||||||
|
ctx.notification_manager
|
||||||
|
.notify(
|
||||||
|
None,
|
||||||
|
NotificationLevel::Error,
|
||||||
|
"EmbassyOS Update Failed".to_owned(),
|
||||||
|
format!("Update was not successful because of {}", e),
|
||||||
|
NotificationSubtype::General,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.expect("")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -321,16 +348,20 @@ async fn write_stream_to_label<Db: DbHandle>(
|
|||||||
let mut hasher = Sha256::new();
|
let mut hasher = Sha256::new();
|
||||||
pin!(stream_download);
|
pin!(stream_download);
|
||||||
let mut downloaded = 0;
|
let mut downloaded = 0;
|
||||||
|
let mut last_progress_update = Instant::now();
|
||||||
while let Some(Ok(item)) = stream_download.next().await {
|
while let Some(Ok(item)) = stream_download.next().await {
|
||||||
file.write_all(&item)
|
file.write_all(&item)
|
||||||
.await
|
.await
|
||||||
.with_kind(ErrorKind::Filesystem)?;
|
.with_kind(ErrorKind::Filesystem)?;
|
||||||
downloaded += item.len() as u64;
|
downloaded += item.len() as u64;
|
||||||
crate::db::DatabaseModel::new()
|
if last_progress_update.elapsed() > Duration::from_secs(1) {
|
||||||
.server_info()
|
last_progress_update = Instant::now();
|
||||||
.update_progress()
|
crate::db::DatabaseModel::new()
|
||||||
.put(db, &UpdateProgress { size, downloaded })
|
.server_info()
|
||||||
.await?;
|
.update_progress()
|
||||||
|
.put(db, &UpdateProgress { size, downloaded })
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
hasher.update(item);
|
hasher.update(item);
|
||||||
}
|
}
|
||||||
file.flush().await.with_kind(ErrorKind::Filesystem)?;
|
file.flush().await.with_kind(ErrorKind::Filesystem)?;
|
||||||
@@ -373,6 +404,8 @@ async fn swap_boot_label(
|
|||||||
.arg(mounted_boot.value.mount_folder().join("cmdline.txt"))
|
.arg(mounted_boot.value.mount_folder().join("cmdline.txt"))
|
||||||
.output()
|
.output()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
UPDATED.store(true, Ordering::SeqCst);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user