mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 20:14:49 +00:00
Merge branch 'next/minor' of github.com:Start9Labs/start-os into next/major
This commit is contained in:
2
core/Cargo.lock
generated
2
core/Cargo.lock
generated
@@ -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",
|
||||||
|
|||||||
@@ -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]
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)]
|
||||||
|
|||||||
@@ -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 })
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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)]
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
@@ -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),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
2
system-images/compat/Cargo.lock
generated
2
system-images/compat/Cargo.lock
generated
@@ -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
4
web/package-lock.json
generated
@@ -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",
|
||||||
|
|||||||
@@ -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": {
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
Reference in New Issue
Block a user