Merge branch 'next/minor' of github.com:Start9Labs/start-os into next/major

This commit is contained in:
Aiden McClelland
2023-11-16 15:15:30 -07:00
27 changed files with 179 additions and 370 deletions

2
core/Cargo.lock generated
View File

@@ -4964,7 +4964,7 @@ dependencies = [
[[package]] [[package]]
name = "start-os" name = "start-os"
version = "0.3.5" version = "0.3.5-rev.1"
dependencies = [ dependencies = [
"aes", "aes",
"async-compression", "async-compression",

View File

@@ -14,7 +14,7 @@ keywords = [
name = "start-os" name = "start-os"
readme = "README.md" readme = "README.md"
repository = "https://github.com/Start9Labs/start-os" repository = "https://github.com/Start9Labs/start-os"
version = "0.3.5" version = "0.3.5-rev.1"
license = "MIT" license = "MIT"
[lib] [lib]

View File

@@ -18,7 +18,7 @@ fn select_executable(name: &str) -> Option<fn()> {
match name { match name {
#[cfg(feature = "avahi-alias")] #[cfg(feature = "avahi-alias")]
"avahi-alias" => Some(avahi_alias::main), "avahi-alias" => Some(avahi_alias::main),
#[cfg(feature = "js_engine")] #[cfg(feature = "js-engine")]
"start-deno" => Some(start_deno::main), "start-deno" => Some(start_deno::main),
#[cfg(feature = "cli")] #[cfg(feature = "cli")]
"start-cli" => Some(start_cli::main), "start-cli" => Some(start_cli::main),
@@ -36,24 +36,14 @@ fn select_executable(name: &str) -> Option<fn()> {
pub fn startbox() { pub fn startbox() {
let args = std::env::args().take(2).collect::<Vec<_>>(); let args = std::env::args().take(2).collect::<Vec<_>>();
if let Some(x) = args let executable = args
.get(0) .get(0)
.and_then(|s| Path::new(&*s).file_name()) .and_then(|s| Path::new(&*s).file_name())
.and_then(|s| s.to_str()) .and_then(|s| s.to_str());
.and_then(|s| select_executable(&s)) if let Some(x) = executable.and_then(|s| select_executable(&s)) {
{
x()
} else if let Some(x) = args.get(1).and_then(|s| select_executable(&s)) {
x() x()
} else { } else {
eprintln!( eprintln!("unknown executable: {}", executable.unwrap_or("N/A"));
"unknown executable: {}",
args.get(0)
.filter(|x| &**x != "startbox")
.or_else(|| args.get(1))
.map(|s| s.as_str())
.unwrap_or("N/A")
);
std::process::exit(1); std::process::exit(1);
} }
} }

View File

@@ -3,6 +3,7 @@ use std::path::{Path, PathBuf};
use std::sync::Arc; use std::sync::Arc;
use std::time::Duration; use std::time::Duration;
use helpers::NonDetachingJoinHandle;
use tokio::process::Command; use tokio::process::Command;
use tracing::instrument; use tracing::instrument;
@@ -15,12 +16,20 @@ use crate::firmware::update_firmware;
use crate::init::STANDBY_MODE_PATH; use crate::init::STANDBY_MODE_PATH;
use crate::net::web_server::WebServer; use crate::net::web_server::WebServer;
use crate::shutdown::Shutdown; use crate::shutdown::Shutdown;
use crate::sound::CHIME; use crate::sound::{BEP, CHIME};
use crate::util::Invoke; use crate::util::Invoke;
use crate::{Error, ErrorKind, ResultExt, PLATFORM}; use crate::{Error, ErrorKind, ResultExt, PLATFORM};
#[instrument(skip_all)] #[instrument(skip_all)]
async fn setup_or_init(cfg_path: Option<PathBuf>) -> Result<Option<Shutdown>, Error> { async fn setup_or_init(cfg_path: Option<PathBuf>) -> Result<Option<Shutdown>, Error> {
let song = NonDetachingJoinHandle::from(tokio::spawn(async {
loop {
BEP.play().await.unwrap();
BEP.play().await.unwrap();
tokio::time::sleep(Duration::from_secs(30)).await;
}
}));
if update_firmware().await?.0 { if update_firmware().await?.0 {
return Ok(Some(Shutdown { return Ok(Some(Shutdown {
export_args: None, export_args: None,
@@ -74,6 +83,7 @@ async fn setup_or_init(cfg_path: Option<PathBuf>) -> Result<Option<Shutdown>, Er
) )
.await?; .await?;
drop(song);
tokio::time::sleep(Duration::from_secs(1)).await; // let the record state that I hate this tokio::time::sleep(Duration::from_secs(1)).await; // let the record state that I hate this
CHIME.play().await?; CHIME.play().await?;
@@ -100,8 +110,10 @@ async fn setup_or_init(cfg_path: Option<PathBuf>) -> Result<Option<Shutdown>, Er
) )
.await?; .await?;
drop(song);
tokio::time::sleep(Duration::from_secs(1)).await; // let the record state that I hate this tokio::time::sleep(Duration::from_secs(1)).await; // let the record state that I hate this
CHIME.play().await?; CHIME.play().await?;
ctx.shutdown ctx.shutdown
.subscribe() .subscribe()
.recv() .recv()
@@ -152,6 +164,7 @@ async fn setup_or_init(cfg_path: Option<PathBuf>) -> Result<Option<Shutdown>, Er
} }
tracing::info!("Loaded Disk"); tracing::info!("Loaded Disk");
crate::init::init(&cfg).await?; crate::init::init(&cfg).await?;
drop(song);
} }
Ok(None) Ok(None)

View File

@@ -23,6 +23,7 @@ use crate::net::utils::{get_iface_ipv4_addr, get_iface_ipv6_addr};
use crate::prelude::*; use crate::prelude::*;
use crate::s9pk::manifest::{Manifest, PackageId}; use crate::s9pk::manifest::{Manifest, PackageId};
use crate::status::Status; use crate::status::Status;
use crate::util::cpupower::{get_preferred_governor, Governor};
use crate::util::Version; use crate::util::Version;
use crate::version::{Current, VersionT}; use crate::version::{Current, VersionT};
use crate::{ARCH, PLATFORM}; use crate::{ARCH, PLATFORM};
@@ -85,6 +86,7 @@ impl Database {
.join(":"), .join(":"),
ntp_synced: false, ntp_synced: false,
zram: true, zram: true,
governor: None,
}, },
package_data: AllPackageData::default(), package_data: AllPackageData::default(),
lan_port_forwards: LanPortForwards::new(), lan_port_forwards: LanPortForwards::new(),
@@ -137,6 +139,7 @@ pub struct ServerInfo {
pub ntp_synced: bool, pub ntp_synced: bool,
#[serde(default)] #[serde(default)]
pub zram: bool, pub zram: bool,
pub governor: Option<Governor>,
} }
#[derive(Debug, Deserialize, Serialize, HasModel)] #[derive(Debug, Deserialize, Serialize, HasModel)]

View File

@@ -20,7 +20,7 @@ use crate::middleware::auth::LOCAL_AUTH_COOKIE_PATH;
use crate::prelude::*; use crate::prelude::*;
use crate::sound::BEP; use crate::sound::BEP;
use crate::util::cpupower::{ use crate::util::cpupower::{
current_governor, get_available_governors, set_governor, GOVERNOR_PERFORMANCE, current_governor, get_available_governors, get_preferred_governor, set_governor,
}; };
use crate::util::docker::{create_bridge_network, CONTAINER_DATADIR, CONTAINER_TOOL}; use crate::util::docker::{create_bridge_network, CONTAINER_DATADIR, CONTAINER_TOOL};
use crate::util::Invoke; use crate::util::Invoke;
@@ -230,18 +230,6 @@ pub async fn init(cfg: &RpcContextConfig) -> Result<InitResult, Error> {
|| &*server_info.version < &emver::Version::new(0, 3, 2, 0) || &*server_info.version < &emver::Version::new(0, 3, 2, 0)
|| (*ARCH == "x86_64" && &*server_info.version < &emver::Version::new(0, 3, 4, 0)); || (*ARCH == "x86_64" && &*server_info.version < &emver::Version::new(0, 3, 4, 0));
let song = if should_rebuild {
Some(NonDetachingJoinHandle::from(tokio::spawn(async {
loop {
BEP.play().await.unwrap();
BEP.play().await.unwrap();
tokio::time::sleep(Duration::from_secs(60)).await;
}
})))
} else {
None
};
let log_dir = cfg.datadir().join("main/logs"); let log_dir = cfg.datadir().join("main/logs");
if tokio::fs::metadata(&log_dir).await.is_err() { if tokio::fs::metadata(&log_dir).await.is_err() {
tokio::fs::create_dir_all(&log_dir).await?; tokio::fs::create_dir_all(&log_dir).await?;
@@ -354,21 +342,20 @@ pub async fn init(cfg: &RpcContextConfig) -> Result<InitResult, Error> {
.await?; .await?;
tracing::info!("Enabled Docker QEMU Emulation"); tracing::info!("Enabled Docker QEMU Emulation");
if current_governor() let governor = if let Some(governor) = &server_info.governor {
.await? if get_available_governors().await?.contains(governor) {
.map(|g| &g != &GOVERNOR_PERFORMANCE) Some(governor)
.unwrap_or(false)
{
tracing::info!("Setting CPU Governor to \"{}\"", GOVERNOR_PERFORMANCE);
if get_available_governors()
.await?
.contains(&GOVERNOR_PERFORMANCE)
{
set_governor(&GOVERNOR_PERFORMANCE).await?;
tracing::info!("Set CPU Governor");
} else { } else {
tracing::warn!("CPU Governor \"{}\" Not Available", GOVERNOR_PERFORMANCE) tracing::warn!("CPU Governor \"{governor}\" Not Available");
None
} }
} else {
get_preferred_governor().await?
};
if let Some(governor) = governor {
tracing::info!("Setting CPU Governor to \"{governor}\"");
set_governor(governor).await?;
tracing::info!("Set CPU Governor");
} }
let mut time_not_synced = true; let mut time_not_synced = true;
@@ -447,8 +434,6 @@ pub async fn init(cfg: &RpcContextConfig) -> Result<InitResult, Error> {
}?; }?;
} }
drop(song);
tracing::info!("System initialized."); tracing::info!("System initialized.");
Ok(InitResult { secret_store, db }) Ok(InitResult { secret_store, db })

View File

@@ -1,5 +1,3 @@
#![recursion_limit = "256"]
pub const DEFAULT_MARKETPLACE: &str = "https://registry.start9.com"; pub const DEFAULT_MARKETPLACE: &str = "https://registry.start9.com";
// pub const COMMUNITY_MARKETPLACE: &str = "https://community-registry.start9.com"; // pub const COMMUNITY_MARKETPLACE: &str = "https://community-registry.start9.com";
pub const BUFFER_SIZE: usize = 1024; pub const BUFFER_SIZE: usize = 1024;

View File

@@ -225,18 +225,18 @@ async fn test_start_deno_command() -> Result<Command, Error> {
.arg("build") .arg("build")
.invoke(ErrorKind::Unknown) .invoke(ErrorKind::Unknown)
.await?; .await?;
if tokio::fs::metadata("target/debug/start-deno") if tokio::fs::metadata("../target/debug/start-deno")
.await .await
.is_err() .is_err()
{ {
Command::new("ln") Command::new("ln")
.arg("-rsf") .arg("-rsf")
.arg("target/debug/startbox") .arg("../target/debug/startbox")
.arg("target/debug/start-deno") .arg("../target/debug/start-deno")
.invoke(crate::ErrorKind::Filesystem) .invoke(crate::ErrorKind::Filesystem)
.await?; .await?;
} }
Ok(Command::new("target/debug/start-deno")) Ok(Command::new("../target/debug/start-deno"))
} }
#[cfg(test)] #[cfg(test)]

View File

@@ -1,3 +1,4 @@
use std::collections::BTreeSet;
use std::fmt; use std::fmt;
use chrono::Utc; use chrono::Utc;
@@ -20,11 +21,12 @@ use crate::logs::{
}; };
use crate::prelude::*; use crate::prelude::*;
use crate::shutdown::Shutdown; use crate::shutdown::Shutdown;
use crate::util::cpupower::{get_available_governors, set_governor, Governor};
use crate::util::serde::{display_serializable, IoFormat}; use crate::util::serde::{display_serializable, IoFormat};
use crate::util::{display_none, Invoke}; use crate::util::{display_none, Invoke};
use crate::{Error, ErrorKind, ResultExt}; use crate::{Error, ErrorKind, ResultExt};
#[command(subcommands(zram))] #[command(subcommands(zram, governor))]
pub async fn experimental() -> Result<(), Error> { pub async fn experimental() -> Result<(), Error> {
Ok(()) Ok(())
} }
@@ -85,6 +87,56 @@ pub async fn zram(#[context] ctx: RpcContext, #[arg] enable: bool) -> Result<(),
Ok(()) Ok(())
} }
#[derive(Debug, Deserialize, Serialize)]
pub struct GovernorInfo {
current: Option<Governor>,
available: BTreeSet<Governor>,
}
fn display_governor_info(arg: GovernorInfo, matches: &ArgMatches) {
use prettytable::*;
if matches.is_present("format") {
return display_serializable(arg, matches);
}
let mut table = Table::new();
table.add_row(row![bc -> "GOVERNORS"]);
for entry in arg.available {
if Some(&entry) == arg.current.as_ref() {
table.add_row(row![g -> format!("* {entry} (current)")]);
} else {
table.add_row(row![entry]);
}
}
table.print_tty(false).unwrap();
}
#[command(display(display_governor_info))]
pub async fn governor(
#[context] ctx: RpcContext,
#[allow(unused_variables)]
#[arg(long = "format")]
format: Option<IoFormat>,
#[arg] set: Option<Governor>,
) -> Result<GovernorInfo, Error> {
let available = get_available_governors().await?;
if let Some(set) = set {
if !available.contains(&set) {
return Err(Error::new(
eyre!("Governor {set} not available"),
ErrorKind::InvalidRequest,
));
}
set_governor(&set).await?;
ctx.db
.mutate(|d| d.as_server_info_mut().as_governor_mut().ser(&Some(set)))
.await?;
}
let current = ctx.db.peek().await.as_server_info().as_governor().de()?;
Ok(GovernorInfo { current, available })
}
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct TimeInfo { pub struct TimeInfo {
now: String, now: String,

View File

@@ -7,10 +7,20 @@ use tokio::process::Command;
use crate::prelude::*; use crate::prelude::*;
use crate::util::Invoke; use crate::util::Invoke;
pub const GOVERNOR_PERFORMANCE: Governor = Governor(Cow::Borrowed("performance")); pub const GOVERNOR_HEIRARCHY: &[Governor] = &[
Governor(Cow::Borrowed("ondemand")),
Governor(Cow::Borrowed("schedutil")),
Governor(Cow::Borrowed("conservative")),
];
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
pub struct Governor(Cow<'static, str>); pub struct Governor(Cow<'static, str>);
impl std::str::FromStr for Governor {
type Err = std::convert::Infallible;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self(s.to_owned().into()))
}
}
impl std::fmt::Display for Governor { impl std::fmt::Display for Governor {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f) self.0.fmt(f)
@@ -29,13 +39,12 @@ impl std::borrow::Borrow<str> for Governor {
} }
pub async fn get_available_governors() -> Result<BTreeSet<Governor>, Error> { pub async fn get_available_governors() -> Result<BTreeSet<Governor>, Error> {
let raw = String::from_utf8( let raw = Command::new("cpupower")
Command::new("cpupower") .arg("frequency-info")
.arg("frequency-info") .arg("-g")
.arg("-g") .invoke(ErrorKind::CpuSettings)
.invoke(ErrorKind::CpuSettings) .await
.await?, .map_or_else(|e| Ok(e.source.to_string()), String::from_utf8)?;
)?;
let mut for_cpu: OrdMap<u32, BTreeSet<Governor>> = OrdMap::new(); let mut for_cpu: OrdMap<u32, BTreeSet<Governor>> = OrdMap::new();
let mut current_cpu = None; let mut current_cpu = None;
for line in raw.lines() { for line in raw.lines() {
@@ -114,6 +123,16 @@ pub async fn current_governor() -> Result<Option<Governor>, Error> {
)) ))
} }
pub async fn get_preferred_governor() -> Result<Option<&'static Governor>, Error> {
let governors = get_available_governors().await?;
for governor in GOVERNOR_HEIRARCHY {
if governors.contains(governor) {
return Ok(Some(governor));
}
}
Ok(None)
}
pub async fn set_governor(governor: &Governor) -> Result<(), Error> { pub async fn set_governor(governor: &Governor) -> Result<(), Error> {
Command::new("cpupower") Command::new("cpupower")
.arg("frequency-set") .arg("frequency-set")

View File

@@ -8,7 +8,7 @@ use sqlx::PgPool;
use crate::prelude::*; use crate::prelude::*;
use crate::Error; use crate::Error;
mod v0_3_5; mod v0_3_5_1;
mod v0_4_0; mod v0_4_0;
pub type Current = v0_4_0::Version; pub type Current = v0_4_0::Version;
@@ -16,8 +16,8 @@ pub type Current = v0_4_0::Version;
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
#[serde(untagged)] #[serde(untagged)]
enum Version { enum Version {
LT0_3_5(LTWrapper<v0_3_5::Version>), LT0_3_5_1(LTWrapper<v0_3_5_1::Version>),
V0_3_5(Wrapper<v0_3_5::Version>), V0_3_5_1(Wrapper<v0_3_5_1::Version>),
V0_4_0(Wrapper<v0_4_0::Version>), V0_4_0(Wrapper<v0_4_0::Version>),
Other(emver::Version), Other(emver::Version),
} }
@@ -34,8 +34,8 @@ impl Version {
#[cfg(test)] #[cfg(test)]
fn as_sem_ver(&self) -> emver::Version { fn as_sem_ver(&self) -> emver::Version {
match self { match self {
Version::LT0_3_5(LTWrapper(_, x)) => x.clone(), Version::LT0_3_5_1(LTWrapper(_, x)) => x.clone(),
Version::V0_3_5(Wrapper(x)) => x.semver(), Version::V0_3_5_1(Wrapper(x)) => x.semver(),
Version::V0_4_0(Wrapper(x)) => x.semver(), Version::V0_4_0(Wrapper(x)) => x.semver(),
Version::Other(x) => x.clone(), Version::Other(x) => x.clone(),
} }
@@ -182,13 +182,13 @@ pub async fn init(db: &PatchDb, secrets: &PgPool) -> Result<(), Error> {
let version = Version::from_util_version(db.peek().await.as_server_info().as_version().de()?); let version = Version::from_util_version(db.peek().await.as_server_info().as_version().de()?);
match version { match version {
Version::LT0_3_5(_) => { Version::LT0_3_5_1(_) => {
return Err(Error::new( return Err(Error::new(
eyre!("Cannot migrate from pre-0.3.5. Please update to v0.3.5 first."), eyre!("Cannot migrate from pre-0.3.5.1. Please update to v0.3.5.1 first."),
crate::ErrorKind::MigrationFailed, crate::ErrorKind::MigrationFailed,
)); ));
} }
Version::V0_3_5(v) => v.0.migrate_to(&Current::new(), db, secrets).await?, Version::V0_3_5_1(v) => v.0.migrate_to(&Current::new(), db, secrets).await?,
Version::V0_4_0(v) => v.0.migrate_to(&Current::new(), db, secrets).await?, Version::V0_4_0(v) => v.0.migrate_to(&Current::new(), db, secrets).await?,
Version::Other(_) => { Version::Other(_) => {
return Err(Error::new( return Err(Error::new(
@@ -222,15 +222,15 @@ mod tests {
fn versions() -> impl Strategy<Value = Version> { fn versions() -> impl Strategy<Value = Version> {
prop_oneof![ prop_oneof![
em_version().prop_map(|v| if v < v0_3_5::Version::new().semver() { em_version().prop_map(|v| if v < v0_3_5_1::Version::new().semver() {
Version::LT0_3_5(LTWrapper(v0_3_5::Version::new(), v)) Version::LT0_3_5_1(LTWrapper(v0_3_5_1::Version::new(), v))
} else { } else {
Version::LT0_3_5(LTWrapper( Version::LT0_3_5_1(LTWrapper(
v0_3_5::Version::new(), v0_3_5_1::Version::new(),
emver::Version::new(0, 3, 0, 0), emver::Version::new(0, 3, 0, 0),
)) ))
}), }),
Just(Version::V0_3_5(Wrapper(v0_3_5::Version::new()))), Just(Version::V0_3_5_1(Wrapper(v0_3_5_1::Version::new()))),
Just(Version::V0_4_0(Wrapper(v0_4_0::Version::new()))), Just(Version::V0_4_0(Wrapper(v0_4_0::Version::new()))),
em_version().prop_map(Version::Other), em_version().prop_map(Version::Other),
] ]

View File

@@ -1,135 +0,0 @@
use async_trait::async_trait;
use emver::VersionRange;
use itertools::Itertools;
use openssl::hash::MessageDigest;
use serde_json::json;
use ssh_key::public::Ed25519PublicKey;
use super::*;
use crate::account::AccountInfo;
use crate::hostname::{sync_hostname, Hostname};
use crate::prelude::*;
const V0_3_4: emver::Version = emver::Version::new(0, 3, 4, 0);
lazy_static::lazy_static! {
pub static ref V0_3_0_COMPAT: VersionRange = VersionRange::Conj(
Box::new(VersionRange::Anchor(
emver::GTE,
emver::Version::new(0, 3, 0, 0),
)),
Box::new(VersionRange::Anchor(emver::LTE, Current::new().semver())),
);
}
const COMMUNITY_URL: &str = "https://community-registry.start9.com/";
const MAIN_REGISTRY: &str = "https://registry.start9.com/";
const COMMUNITY_SERVICES: &[&str] = &[
"ipfs",
"agora",
"lightning-jet",
"balanceofsatoshis",
"mastodon",
"lndg",
"robosats",
"thunderhub",
"syncthing",
"sphinx-relay",
];
#[derive(Clone, Debug)]
pub struct Version;
#[async_trait]
impl VersionT for Version {
type Previous = Self;
fn new() -> Self {
Version
}
fn semver(&self) -> emver::Version {
V0_3_4
}
fn compat(&self) -> &'static VersionRange {
&*V0_3_0_COMPAT
}
async fn up(&self, db: PatchDb, secrets: &PgPool) -> Result<(), Error> {
let mut account = AccountInfo::load(secrets).await?;
let account = db
.mutate(|d| {
d.as_server_info_mut().as_pubkey_mut().ser(
&ssh_key::PublicKey::from(Ed25519PublicKey::from(&account.key.ssh_key()))
.to_openssh()?,
)?;
d.as_server_info_mut().as_ca_fingerprint_mut().ser(
&account
.root_ca_cert
.digest(MessageDigest::sha256())
.unwrap()
.iter()
.map(|x| format!("{x:X}"))
.join(":"),
)?;
let server_info = d.as_server_info();
account.hostname = server_info.as_hostname().de().map(Hostname)?;
account.server_id = server_info.as_id().de()?;
Ok(account)
})
.await?;
account.save(secrets).await?;
sync_hostname(&account.hostname).await?;
let parsed_url = Some(COMMUNITY_URL.parse().unwrap());
db.mutate(|d| {
let mut ui = d.as_ui().de()?;
use imbl_value::json;
ui["marketplace"]["known-hosts"][COMMUNITY_URL] = json!({});
ui["marketplace"]["known-hosts"][MAIN_REGISTRY] = json!({});
for package_id in d.as_package_data().keys()? {
if !COMMUNITY_SERVICES.contains(&&*package_id.to_string()) {
continue;
}
d.as_package_data_mut()
.as_idx_mut(&package_id)
.or_not_found(&package_id)?
.as_installed_mut()
.or_not_found(&package_id)?
.as_marketplace_url_mut()
.ser(&parsed_url)?;
}
ui["theme"] = json!("Dark".to_string());
ui["widgets"] = json!([]);
d.as_ui_mut().ser(&ui)
})
.await
}
async fn down(&self, db: PatchDb, _secrets: &PgPool) -> Result<(), Error> {
db.mutate(|d| {
let mut ui = d.as_ui().de()?;
let parsed_url = Some(MAIN_REGISTRY.parse().unwrap());
for package_id in d.as_package_data().keys()? {
if !COMMUNITY_SERVICES.contains(&&*package_id.to_string()) {
continue;
}
d.as_package_data_mut()
.as_idx_mut(&package_id)
.or_not_found(&package_id)?
.as_installed_mut()
.or_not_found(&package_id)?
.as_marketplace_url_mut()
.ser(&parsed_url)?;
}
if let imbl_value::Value::Object(ref mut obj) = ui {
obj.remove("theme");
obj.remove("widgets");
}
ui["marketplace"]["known-hosts"][COMMUNITY_URL].take();
ui["marketplace"]["known-hosts"][MAIN_REGISTRY].take();
d.as_ui_mut().ser(&ui)
})
.await
}
}

View File

@@ -1,31 +0,0 @@
use async_trait::async_trait;
use emver::VersionRange;
use super::v0_3_4::V0_3_0_COMPAT;
use super::*;
use crate::prelude::*;
const V0_3_4_1: emver::Version = emver::Version::new(0, 3, 4, 1);
#[derive(Clone, Debug)]
pub struct Version;
#[async_trait]
impl VersionT for Version {
type Previous = v0_3_4::Version;
fn new() -> Self {
Version
}
fn semver(&self) -> emver::Version {
V0_3_4_1
}
fn compat(&self) -> &'static VersionRange {
&*V0_3_0_COMPAT
}
async fn up(&self, _db: PatchDb, _secrets: &PgPool) -> Result<(), Error> {
Ok(())
}
async fn down(&self, _db: PatchDb, _secrets: &PgPool) -> Result<(), Error> {
Ok(())
}
}

View File

@@ -1,31 +0,0 @@
use async_trait::async_trait;
use emver::VersionRange;
use super::v0_3_4::V0_3_0_COMPAT;
use super::*;
use crate::prelude::*;
const V0_3_4_2: emver::Version = emver::Version::new(0, 3, 4, 2);
#[derive(Clone, Debug)]
pub struct Version;
#[async_trait]
impl VersionT for Version {
type Previous = v0_3_4_1::Version;
fn new() -> Self {
Version
}
fn semver(&self) -> emver::Version {
V0_3_4_2
}
fn compat(&self) -> &'static VersionRange {
&*V0_3_0_COMPAT
}
async fn up(&self, _db: PatchDb, _secrets: &PgPool) -> Result<(), Error> {
Ok(())
}
async fn down(&self, _db: PatchDb, _secrets: &PgPool) -> Result<(), Error> {
Ok(())
}
}

View File

@@ -1,31 +0,0 @@
use async_trait::async_trait;
use emver::VersionRange;
use super::v0_3_4::V0_3_0_COMPAT;
use super::*;
use crate::prelude::*;
const V0_3_4_3: emver::Version = emver::Version::new(0, 3, 4, 3);
#[derive(Clone, Debug)]
pub struct Version;
#[async_trait]
impl VersionT for Version {
type Previous = v0_3_4_2::Version;
fn new() -> Self {
Version
}
fn semver(&self) -> emver::Version {
V0_3_4_3
}
fn compat(&self) -> &'static VersionRange {
&V0_3_0_COMPAT
}
async fn up(&self, _db: PatchDb, _secrets: &PgPool) -> Result<(), Error> {
Ok(())
}
async fn down(&self, _db: PatchDb, _secrets: &PgPool) -> Result<(), Error> {
Ok(())
}
}

View File

@@ -1,43 +0,0 @@
use async_trait::async_trait;
use emver::VersionRange;
use models::ResultExt;
use sqlx::PgPool;
use super::v0_3_4::V0_3_0_COMPAT;
use super::{v0_3_4_3, VersionT};
use crate::prelude::*;
const V0_3_4_4: emver::Version = emver::Version::new(0, 3, 4, 4);
#[derive(Clone, Debug)]
pub struct Version;
#[async_trait]
impl VersionT for Version {
type Previous = v0_3_4_3::Version;
fn new() -> Self {
Version
}
fn semver(&self) -> emver::Version {
V0_3_4_4
}
fn compat(&self) -> &'static VersionRange {
&V0_3_0_COMPAT
}
async fn up(&self, db: PatchDb, _secrets: &PgPool) -> Result<(), Error> {
db.mutate(|v| {
let tor_address_lens = v.as_server_info_mut().as_tor_address_mut();
let mut tor_addr = tor_address_lens.de()?;
tor_addr
.set_scheme("https")
.map_err(|_| eyre!("unable to update url scheme to https"))
.with_kind(crate::ErrorKind::ParseUrl)?;
tor_address_lens.ser(&tor_addr)
})
.await?;
Ok(())
}
async fn down(&self, _db: PatchDb, _secrets: &PgPool) -> Result<(), Error> {
Ok(())
}
}

View File

@@ -1,11 +1,11 @@
use async_trait::async_trait; use async_trait::async_trait;
use emver::VersionRange; use emver::VersionRange;
use lazy_static::lazy_static; use sqlx::PgPool;
use super::*; use super::v0_3_4::V0_3_0_COMPAT;
use super::VersionT;
use crate::prelude::*; use crate::prelude::*;
const V0_3_5: emver::Version = emver::Version::new(0, 3, 5, 0);
lazy_static! { lazy_static! {
static ref V0_3_0_COMPAT: VersionRange = VersionRange::Conj( static ref V0_3_0_COMPAT: VersionRange = VersionRange::Conj(
Box::new(VersionRange::Anchor( Box::new(VersionRange::Anchor(
@@ -15,6 +15,7 @@ lazy_static! {
Box::new(VersionRange::Anchor(emver::LTE, Current::new().semver())), Box::new(VersionRange::Anchor(emver::LTE, Current::new().semver())),
); );
} }
const V0_3_5_1: emver::Version = emver::Version::new(0, 3, 5, 1);
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Version; pub struct Version;
@@ -26,15 +27,15 @@ impl VersionT for Version {
Version Version
} }
fn semver(&self) -> emver::Version { fn semver(&self) -> emver::Version {
V0_3_5 V0_3_5_1
} }
fn compat(&self) -> &'static VersionRange { fn compat(&self) -> &'static VersionRange {
&V0_3_0_COMPAT &V0_3_0_COMPAT
} }
async fn up(&self, _db: &PatchDb, _secrets: &PgPool) -> Result<(), Error> { async fn up(&self, _db: PatchDb, _secrets: &PgPool) -> Result<(), Error> {
Ok(()) Ok(())
} }
async fn down(&self, _db: &PatchDb, _secrets: &PgPool) -> Result<(), Error> { async fn down(&self, _db: PatchDb, _secrets: &PgPool) -> Result<(), Error> {
Ok(()) Ok(())
} }
} }

View File

@@ -158,8 +158,8 @@ echo "deb [arch=${IB_TARGET_ARCH} signed-by=/etc/apt/trusted.gpg.d/tor.key.gpg]
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o config/archives/docker.key curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o config/archives/docker.key
echo "deb [arch=${IB_TARGET_ARCH} signed-by=/etc/apt/trusted.gpg.d/docker.key.gpg] https://download.docker.com/linux/debian ${IB_SUITE} stable" > config/archives/docker.list echo "deb [arch=${IB_TARGET_ARCH} signed-by=/etc/apt/trusted.gpg.d/docker.key.gpg] https://download.docker.com/linux/debian ${IB_SUITE} stable" > config/archives/docker.list
curl -fsSL https://download.opensuse.org/repositories/devel:kubic:libcontainers:unstable/Debian_Testing/Release.key | gpg --dearmor -o config/archives/podman.key curl -fsSL https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/unstable/Debian_Testing/Release.key | gpg --dearmor -o config/archives/podman.key
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/trusted.gpg.d/podman.key.gpg] https://download.opensuse.org/repositories/devel:kubic:libcontainers:unstable/Debian_Testing/ /" > config/archives/podman.list echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/trusted.gpg.d/podman.key.gpg] https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/unstable/Debian_Testing/ /" > config/archives/podman.list
# Dependencies # Dependencies

View File

@@ -4418,7 +4418,7 @@ dependencies = [
[[package]] [[package]]
name = "start-os" name = "start-os"
version = "0.3.5" version = "0.3.5-rev.1"
dependencies = [ dependencies = [
"aes", "aes",
"async-compression", "async-compression",

4
web/package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "startos-ui", "name": "startos-ui",
"version": "0.3.5", "version": "0.3.5.1",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "startos-ui", "name": "startos-ui",
"version": "0.3.5", "version": "0.3.5.1",
"dependencies": { "dependencies": {
"@angular/animations": "^14.1.0", "@angular/animations": "^14.1.0",
"@angular/common": "^14.1.0", "@angular/common": "^14.1.0",

View File

@@ -1,6 +1,6 @@
{ {
"name": "startos-ui", "name": "startos-ui",
"version": "0.3.5", "version": "0.3.5.1",
"author": "Start9 Labs, Inc", "author": "Start9 Labs, Inc",
"homepage": "https://start9.com/", "homepage": "https://start9.com/",
"scripts": { "scripts": {

View File

@@ -27,8 +27,8 @@
<ion-label> <ion-label>
<h2>{{ server.zram ? 'Disable' : 'Enable' }} zram</h2> <h2>{{ server.zram ? 'Disable' : 'Enable' }} zram</h2>
<p> <p>
Enabling zram may improve server performance, especially on low RAM Zram creates compressed swap in memory, resulting in faster I/O for
devices low RAM devices
</p> </p>
</ion-label> </ion-label>
</ion-item> </ion-item>

View File

@@ -65,10 +65,10 @@ export class ExperimentalFeaturesPage {
async presentAlertZram(enabled: boolean) { async presentAlertZram(enabled: boolean) {
const alert = await this.alertCtrl.create({ const alert = await this.alertCtrl.create({
header: enabled ? 'Confirm' : 'Warning', header: 'Confirm',
message: enabled message: enabled
? 'Are you sure you want to disable zram?' ? 'Are you sure you want to disable zram? It provides significant performance benefits on low RAM devices.'
: 'zram on StartOS is experimental. It may increase performance of you server, especially if it is a low RAM device.', : 'Enable zram? It will only make a difference on lower RAM devices.',
buttons: [ buttons: [
{ {
text: 'Cancel', text: 'Cancel',
@@ -82,7 +82,6 @@ export class ExperimentalFeaturesPage {
cssClass: 'enter-click', cssClass: 'enter-click',
}, },
], ],
cssClass: enabled ? '' : 'alert-warning-message',
}) })
await alert.present() await alert.present()
} }
@@ -122,7 +121,7 @@ export class ExperimentalFeaturesPage {
private async toggleZram(enabled: boolean) { private async toggleZram(enabled: boolean) {
const loader = await this.loadingCtrl.create({ const loader = await this.loadingCtrl.create({
message: enabled ? 'Disabling zram...' : 'Enabling zram', message: enabled ? 'Disabling zram...' : 'Enabling zram...',
}) })
await loader.present() await loader.present()

View File

@@ -12,6 +12,26 @@
<ion-content class="ion-padding"> <ion-content class="ion-padding">
<h2>This Release</h2> <h2>This Release</h2>
<h4>0.3.5.1</h4>
<p class="note-padding">
View the complete
<a
href="https://github.com/Start9Labs/start-os/releases/tag/v0.3.5.1"
target="_blank"
noreferrer
>
release notes
</a>
for more details.
</p>
<h6>Highlights</h6>
<ul class="spaced-list">
<li>Revert perpetual performance mode for quieter fan</li>
<li>Minor bug fixes</li>
</ul>
<h2>Previous 0.3.5.x Releases</h2>
<h4>0.3.5</h4> <h4>0.3.5</h4>
<p class="note-padding"> <p class="note-padding">
View the complete View the complete

View File

@@ -35,10 +35,10 @@ export module Mock {
'shutting-down': false, 'shutting-down': false,
} }
export const MarketplaceEos: RR.GetMarketplaceEosRes = { export const MarketplaceEos: RR.GetMarketplaceEosRes = {
version: '0.3.5', version: '0.3.5.1',
headline: 'Our biggest release ever.', headline: 'Our biggest release ever.',
'release-notes': { 'release-notes': {
'0.3.5': 'Some **Markdown** release _notes_ for 0.3.5', '0.3.5.1': 'Some **Markdown** release _notes_ for 0.3.5.1',
'0.3.4.4': 'Some **Markdown** release _notes_ for 0.3.4.4', '0.3.4.4': 'Some **Markdown** release _notes_ for 0.3.4.4',
'0.3.4.3': 'Some **Markdown** release _notes_ for 0.3.4.3', '0.3.4.3': 'Some **Markdown** release _notes_ for 0.3.4.3',
'0.3.4.2': 'Some **Markdown** release _notes_ for 0.3.4.2', '0.3.4.2': 'Some **Markdown** release _notes_ for 0.3.4.2',

View File

@@ -35,7 +35,7 @@ export const mockPatchData: DataModel = {
}, },
'server-info': { 'server-info': {
id: 'abcdefgh', id: 'abcdefgh',
version: '0.3.5', version: '0.3.5.1',
country: 'us', country: 'us',
'last-backup': new Date(new Date().valueOf() - 604800001).toISOString(), 'last-backup': new Date(new Date().valueOf() - 604800001).toISOString(),
'lan-address': 'https://adjective-noun.local', 'lan-address': 'https://adjective-noun.local',

View File

@@ -5,8 +5,8 @@
"background_color": "#1e1e1e", "background_color": "#1e1e1e",
"display": "standalone", "display": "standalone",
"scope": ".", "scope": ".",
"start_url": "/?version=035", "start_url": "/?version=0351",
"id": "/?version=035", "id": "/?version=0351",
"icons": [ "icons": [
{ {
"src": "assets/img/icon.png", "src": "assets/img/icon.png",