mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 02:11:53 +00:00
export patchdb ts types from rust
This commit is contained in:
2
Makefile
2
Makefile
@@ -174,8 +174,8 @@ container-runtime/node_modules: container-runtime/package.json container-runtime
|
||||
touch container-runtime/node_modules
|
||||
|
||||
core/startos/bindings: $(shell git ls-files core) $(ENVIRONMENT_FILE) $(PLATFORM_FILE)
|
||||
rm -rf core/startos/bindings
|
||||
(cd core/ && cargo test)
|
||||
touch core/startos/bindings
|
||||
|
||||
sdk/lib/test: $(shell git ls-files sdk) core/startos/bindings
|
||||
(cd sdk && make test)
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type BindOptionsSecure = { ssl: boolean, };
|
||||
export type ServiceInterfaceId = string;
|
||||
@@ -6,21 +6,21 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use yasi::InternedString;
|
||||
|
||||
mod action;
|
||||
mod address;
|
||||
mod health_check;
|
||||
mod host;
|
||||
mod image;
|
||||
mod invalid_id;
|
||||
mod package;
|
||||
mod service_interface;
|
||||
mod volume;
|
||||
|
||||
pub use action::ActionId;
|
||||
pub use address::AddressId;
|
||||
pub use health_check::HealthCheckId;
|
||||
pub use host::HostId;
|
||||
pub use image::ImageId;
|
||||
pub use invalid_id::InvalidId;
|
||||
pub use package::{PackageId, SYSTEM_PACKAGE_ID};
|
||||
pub use service_interface::ServiceInterfaceId;
|
||||
pub use volume::VolumeId;
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
|
||||
@@ -1,46 +1,48 @@
|
||||
use std::path::Path;
|
||||
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use ts_rs::TS;
|
||||
|
||||
use crate::Id;
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
|
||||
pub struct AddressId(Id);
|
||||
impl From<Id> for AddressId {
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, TS)]
|
||||
#[ts(export, type = "string")]
|
||||
pub struct ServiceInterfaceId(Id);
|
||||
impl From<Id> for ServiceInterfaceId {
|
||||
fn from(id: Id) -> Self {
|
||||
Self(id)
|
||||
}
|
||||
}
|
||||
impl std::fmt::Display for AddressId {
|
||||
impl std::fmt::Display for ServiceInterfaceId {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", &self.0)
|
||||
}
|
||||
}
|
||||
impl std::ops::Deref for AddressId {
|
||||
impl std::ops::Deref for ServiceInterfaceId {
|
||||
type Target = str;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&*self.0
|
||||
}
|
||||
}
|
||||
impl AsRef<str> for AddressId {
|
||||
impl AsRef<str> for ServiceInterfaceId {
|
||||
fn as_ref(&self) -> &str {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
impl<'de> Deserialize<'de> for AddressId {
|
||||
impl<'de> Deserialize<'de> for ServiceInterfaceId {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Ok(AddressId(Deserialize::deserialize(deserializer)?))
|
||||
Ok(ServiceInterfaceId(Deserialize::deserialize(deserializer)?))
|
||||
}
|
||||
}
|
||||
impl AsRef<Path> for AddressId {
|
||||
impl AsRef<Path> for ServiceInterfaceId {
|
||||
fn as_ref(&self) -> &Path {
|
||||
self.0.as_ref().as_ref()
|
||||
}
|
||||
}
|
||||
impl<'q> sqlx::Encode<'q, sqlx::Postgres> for AddressId {
|
||||
impl<'q> sqlx::Encode<'q, sqlx::Postgres> for ServiceInterfaceId {
|
||||
fn encode_by_ref(
|
||||
&self,
|
||||
buf: &mut <sqlx::Postgres as sqlx::database::HasArguments<'q>>::ArgumentBuffer,
|
||||
@@ -48,7 +50,7 @@ impl<'q> sqlx::Encode<'q, sqlx::Postgres> for AddressId {
|
||||
<&str as sqlx::Encode<'q, sqlx::Postgres>>::encode_by_ref(&&**self, buf)
|
||||
}
|
||||
}
|
||||
impl sqlx::Type<sqlx::Postgres> for AddressId {
|
||||
impl sqlx::Type<sqlx::Postgres> for ServiceInterfaceId {
|
||||
fn type_info() -> sqlx::postgres::PgTypeInfo {
|
||||
<&str as sqlx::Type<sqlx::Postgres>>::type_info()
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type BindKind = "static" | "single" | "multi";
|
||||
export type ActionId = string;
|
||||
@@ -1,4 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { AllowedStatuses } from "./AllowedStatuses";
|
||||
|
||||
export type ActionMetadata = { name: string, description: string, warning: string | null, disabled: boolean, input: {[key: string]: any}, allowedStatuses: AllowedStatuses, group: string | null, };
|
||||
export type ActionMetadata = { name: string, description: string, warning: string | null, input: any, disabled: boolean, allowedStatuses: AllowedStatuses, group: string | null, };
|
||||
@@ -1,4 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { AlpnInfo } from "./AlpnInfo";
|
||||
|
||||
export type AddSslOptions = { scheme: string, preferredExternalPort: number, alpn: AlpnInfo, };
|
||||
export type AddSslOptions = { scheme: string | null, preferredExternalPort: number, alpn: AlpnInfo, };
|
||||
@@ -1,4 +1,5 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { BindOptions } from "./BindOptions";
|
||||
import type { HostId } from "./HostId";
|
||||
|
||||
export type AddressInfo = { username: string | null, hostId: string, bindOptions: BindOptions, suffix: string, };
|
||||
export type AddressInfo = { username: string | null, hostId: HostId, bindOptions: BindOptions, suffix: string, };
|
||||
@@ -1,4 +1,5 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { AddSslOptions } from "./AddSslOptions";
|
||||
import type { Security } from "./Security";
|
||||
|
||||
export type BindOptions = { scheme: string, preferredExternalPort: number, addSsl: AddSslOptions | null, secure: boolean, ssl: boolean, };
|
||||
export type BindOptions = { scheme: string | null, preferredExternalPort: number, addSsl: AddSslOptions | null, secure: Security | null, };
|
||||
@@ -1,6 +1,7 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { AddSslOptions } from "./AddSslOptions";
|
||||
import type { BindKind } from "./BindKind";
|
||||
import type { BindOptionsSecure } from "./BindOptionsSecure";
|
||||
import type { HostId } from "./HostId";
|
||||
import type { HostKind } from "./HostKind";
|
||||
import type { Security } from "./Security";
|
||||
|
||||
export type BindParams = { kind: BindKind, id: string, internalPort: number, scheme: string, preferredExternalPort: number, addSsl: AddSslOptions | null, secure: BindOptionsSecure | null, };
|
||||
export type BindParams = { kind: HostKind, id: HostId, internalPort: number, scheme: string | null, preferredExternalPort: number, addSsl: AddSslOptions | null, secure: Security | null, };
|
||||
@@ -1,4 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { DataUrl } from "./DataUrl";
|
||||
|
||||
export type CurrentDependencyInfo = { title: string, icon: DataUrl, registry: string, versionSpec: string, } & ({ "kind": "exists" } | { "kind": "running", healthChecks: string[], });
|
||||
export type CurrentDependencyInfo = { title: string, icon: DataUrl, registryUrl: string, versionSpec: string, } & ({ "kind": "exists" } | { "kind": "running", healthChecks: string[], });
|
||||
@@ -1,3 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type DependencyRequirement = { "kind": "running", id: string, healthChecks: string[], versionSpec: string, registry: string, } | { "kind": "exists", id: string, versionSpec: string, registry: string, };
|
||||
export type DependencyRequirement = { "kind": "running", id: string, healthChecks: string[], versionSpec: string, registryUrl: string, } | { "kind": "exists", id: string, versionSpec: string, registryUrl: string, };
|
||||
6
core/startos/bindings/ExportedHostInfo.ts
Normal file
6
core/startos/bindings/ExportedHostInfo.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ExportedHostnameInfo } from "./ExportedHostnameInfo";
|
||||
import type { HostId } from "./HostId";
|
||||
import type { HostKind } from "./HostKind";
|
||||
|
||||
export type ExportedHostInfo = { id: HostId, kind: HostKind, hostnames: Array<ExportedHostnameInfo>, };
|
||||
5
core/startos/bindings/ExportedHostnameInfo.ts
Normal file
5
core/startos/bindings/ExportedHostnameInfo.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ExportedIpHostname } from "./ExportedIpHostname";
|
||||
import type { ExportedOnionHostname } from "./ExportedOnionHostname";
|
||||
|
||||
export type ExportedHostnameInfo = { "kind": "ip", networkInterfaceId: string, public: boolean, hostname: ExportedIpHostname, } | { "kind": "onion", hostname: ExportedOnionHostname, };
|
||||
3
core/startos/bindings/ExportedIpHostname.ts
Normal file
3
core/startos/bindings/ExportedIpHostname.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type ExportedIpHostname = { "kind": "ipv4", value: string, port: number | null, sslPort: number | null, } | { "kind": "ipv6", value: string, port: number | null, sslPort: number | null, } | { "kind": "local", value: string, port: number | null, sslPort: number | null, } | { "kind": "domain", domain: string, subdomain: string | null, port: number | null, sslPort: number | null, };
|
||||
3
core/startos/bindings/ExportedOnionHostname.ts
Normal file
3
core/startos/bindings/ExportedOnionHostname.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type ExportedOnionHostname = { value: string, port: number | null, sslPort: number | null, };
|
||||
@@ -1,3 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type HealthCheckResult = { "result": "success" } | { "result": "disabled" } | { "result": "starting" } | { "result": "loading", message: string, } | { "result": "failure", error: string, };
|
||||
export type HealthCheckResult = { name: string, } & ({ "result": "success", message: string, } | { "result": "disabled" } | { "result": "starting" } | { "result": "loading", message: string, } | { "result": "failure", message: string, });
|
||||
@@ -1,8 +1,12 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ActionId } from "./ActionId";
|
||||
import type { ActionMetadata } from "./ActionMetadata";
|
||||
import type { CurrentDependencies } from "./CurrentDependencies";
|
||||
import type { DataUrl } from "./DataUrl";
|
||||
import type { HostInfo } from "./HostInfo";
|
||||
import type { PackageState } from "./PackageState";
|
||||
import type { ServiceInterfaceId } from "./ServiceInterfaceId";
|
||||
import type { ServiceInterfaceWithHostInfo } from "./ServiceInterfaceWithHostInfo";
|
||||
import type { Status } from "./Status";
|
||||
|
||||
export type PackageDataEntry = { stateInfo: PackageState, status: Status, marketplaceUrl: string | null, developerKey: string, icon: DataUrl, lastBackup: string | null, currentDependencies: CurrentDependencies, hosts: HostInfo, storeExposedDependents: string[], };
|
||||
export type PackageDataEntry = { stateInfo: PackageState, status: Status, marketplaceUrl: string | null, developerKey: string, icon: DataUrl, lastBackup: string | null, currentDependencies: CurrentDependencies, actions: { [key: ActionId]: ActionMetadata }, serviceInterfaces: { [key: ServiceInterfaceId]: ServiceInterfaceWithHostInfo }, hosts: HostInfo, storeExposedDependents: string[], };
|
||||
@@ -1,3 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type Progress = boolean | { done: bigint, total: bigint | null, };
|
||||
export type Progress = boolean | { done: number, total: number | null, };
|
||||
@@ -1,3 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type ConnectionAddresses = { tor: Array<string>, clearnet: Array<string>, };
|
||||
export type Security = { ssl: boolean, };
|
||||
@@ -1,5 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ConnectionAddresses } from "./ConnectionAddresses";
|
||||
import type { Governor } from "./Governor";
|
||||
import type { IpInfo } from "./IpInfo";
|
||||
import type { ServerStatus } from "./ServerStatus";
|
||||
@@ -13,4 +12,4 @@ lastWifiRegion: string | null, eosVersionCompat: string, lanAddress: string, oni
|
||||
/**
|
||||
* for backwards compatibility
|
||||
*/
|
||||
torAddress: string, ipInfo: { [key: string]: IpInfo }, statusInfo: ServerStatus, wifi: WifiInfo, unreadNotificationCount: bigint, connectionAddresses: ConnectionAddresses, passwordHash: string, pubkey: string, caFingerprint: string, ntpSynced: boolean, zram: boolean, governor: Governor | null, };
|
||||
torAddress: string, ipInfo: { [key: string]: IpInfo }, statusInfo: ServerStatus, wifi: WifiInfo, unreadNotificationCount: number, passwordHash: string, pubkey: string, caFingerprint: string, ntpSynced: boolean, zram: boolean, governor: Governor | null, };
|
||||
6
core/startos/bindings/ServiceInterface.ts
Normal file
6
core/startos/bindings/ServiceInterface.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { AddressInfo } from "./AddressInfo";
|
||||
import type { ServiceInterfaceId } from "./ServiceInterfaceId";
|
||||
import type { ServiceInterfaceType } from "./ServiceInterfaceType";
|
||||
|
||||
export type ServiceInterface = { id: ServiceInterfaceId, name: string, description: string, hasPrimary: boolean, disabled: boolean, masked: boolean, addressInfo: AddressInfo, type: ServiceInterfaceType, };
|
||||
@@ -1,3 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type HealthCheckString = "passing" | "disabled" | "starting" | "warning" | "failure";
|
||||
export type ServiceInterfaceId = string;
|
||||
7
core/startos/bindings/ServiceInterfaceWithHostInfo.ts
Normal file
7
core/startos/bindings/ServiceInterfaceWithHostInfo.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { AddressInfo } from "./AddressInfo";
|
||||
import type { ExportedHostInfo } from "./ExportedHostInfo";
|
||||
import type { ServiceInterfaceId } from "./ServiceInterfaceId";
|
||||
import type { ServiceInterfaceType } from "./ServiceInterfaceType";
|
||||
|
||||
export type ServiceInterfaceWithHostInfo = { hostInfo: ExportedHostInfo, id: ServiceInterfaceId, name: string, description: string, hasPrimary: boolean, disabled: boolean, masked: boolean, addressInfo: AddressInfo, type: ServiceInterfaceType, };
|
||||
@@ -1,4 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { HealthCheckString } from "./HealthCheckString";
|
||||
import type { HealthCheckId } from "./HealthCheckId";
|
||||
|
||||
export type SetHealth = { name: string, status: HealthCheckString, message: string | null, };
|
||||
export type SetHealth = { id: HealthCheckId, name: string, } & ({ "result": "success", message: string, } | { "result": "disabled" } | { "result": "starting" } | { "result": "loading", message: string, } | { "result": "failure", message: string, });
|
||||
@@ -1,3 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type UpdateProgress = { size: bigint | null, downloaded: bigint, };
|
||||
export type UpdateProgress = { size: number | null, downloaded: number, };
|
||||
@@ -3,7 +3,7 @@ use std::collections::{BTreeMap, BTreeSet};
|
||||
use chrono::{DateTime, Utc};
|
||||
use emver::VersionRange;
|
||||
use imbl_value::InternedString;
|
||||
use models::{ActionId, DataUrl, HealthCheckId, HostId, PackageId};
|
||||
use models::{ActionId, DataUrl, HealthCheckId, HostId, PackageId, ServiceInterfaceId};
|
||||
use patch_db::json_ptr::JsonPointer;
|
||||
use patch_db::HasModel;
|
||||
use reqwest::Url;
|
||||
@@ -11,6 +11,7 @@ use serde::{Deserialize, Serialize};
|
||||
use ts_rs::TS;
|
||||
|
||||
use crate::net::host::HostInfo;
|
||||
use crate::net::service_interface::ServiceInterfaceWithHostInfo;
|
||||
use crate::prelude::*;
|
||||
use crate::progress::FullProgress;
|
||||
use crate::s9pk::manifest::Manifest;
|
||||
@@ -306,14 +307,14 @@ pub enum AllowedStatuses {
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[model = "Model<Self>"]
|
||||
pub struct ActionMetadata {
|
||||
name: String,
|
||||
description: String,
|
||||
warning: Option<String>,
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
pub warning: Option<String>,
|
||||
#[ts(type = "any")]
|
||||
input: Value,
|
||||
disabled: bool,
|
||||
allowedStatuses: AllowedStatuses,
|
||||
group: Option<String>,
|
||||
pub input: Value,
|
||||
pub disabled: bool,
|
||||
pub allowed_statuses: AllowedStatuses,
|
||||
pub group: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, HasModel, TS)]
|
||||
@@ -331,10 +332,11 @@ pub struct PackageDataEntry {
|
||||
#[ts(type = "string | null")]
|
||||
pub last_backup: Option<DateTime<Utc>>,
|
||||
pub current_dependencies: CurrentDependencies,
|
||||
pub actions: BTreeMap<ActionId, ActionMetadata>,
|
||||
pub service_interfaces: BTreeMap<ServiceInterfaceId, ServiceInterfaceWithHostInfo>,
|
||||
pub hosts: HostInfo,
|
||||
#[ts(type = "string[]")]
|
||||
pub store_exposed_dependents: Vec<JsonPointer>,
|
||||
pub exposed_actions: BTreeMap<ActionId, ActionMetadata>,
|
||||
}
|
||||
impl AsRef<PackageDataEntry> for PackageDataEntry {
|
||||
fn as_ref(&self) -> &PackageDataEntry {
|
||||
@@ -375,7 +377,7 @@ pub struct CurrentDependencyInfo {
|
||||
pub title: String,
|
||||
pub icon: DataUrl<'static>,
|
||||
#[ts(type = "string")]
|
||||
pub registry: Url,
|
||||
pub registry_url: Url,
|
||||
#[ts(type = "string")]
|
||||
pub version_spec: VersionRange,
|
||||
}
|
||||
|
||||
@@ -66,10 +66,6 @@ impl Public {
|
||||
selected: None,
|
||||
},
|
||||
unread_notification_count: 0,
|
||||
connection_addresses: ConnectionAddresses {
|
||||
tor: Vec::new(),
|
||||
clearnet: Vec::new(),
|
||||
},
|
||||
password_hash: account.password.clone(),
|
||||
pubkey: ssh_key::PublicKey::from(&account.ssh_key)
|
||||
.to_openssh()
|
||||
@@ -136,8 +132,8 @@ pub struct ServerInfo {
|
||||
#[serde(default)]
|
||||
pub status_info: ServerStatus,
|
||||
pub wifi: WifiInfo,
|
||||
#[ts(type = "number")]
|
||||
pub unread_notification_count: u64,
|
||||
pub connection_addresses: ConnectionAddresses,
|
||||
pub password_hash: String,
|
||||
pub pubkey: String,
|
||||
pub ca_fingerprint: String,
|
||||
@@ -199,7 +195,9 @@ pub struct ServerStatus {
|
||||
#[model = "Model<Self>"]
|
||||
#[ts(export)]
|
||||
pub struct UpdateProgress {
|
||||
#[ts(type = "number | null")]
|
||||
pub size: Option<u64>,
|
||||
#[ts(type = "number")]
|
||||
pub downloaded: u64,
|
||||
}
|
||||
|
||||
@@ -221,11 +219,3 @@ pub struct ServerSpecs {
|
||||
pub disk: String,
|
||||
pub memory: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
pub struct ConnectionAddresses {
|
||||
pub tor: Vec<String>,
|
||||
pub clearnet: Vec<String>,
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ pub struct BindInfo {
|
||||
impl BindInfo {
|
||||
pub fn new(available_ports: &mut AvailablePorts, options: BindOptions) -> Result<Self, Error> {
|
||||
let mut assigned_lan_port = None;
|
||||
if options.add_ssl.is_some() || options.secure {
|
||||
if options.add_ssl.is_some() || options.secure.is_some() {
|
||||
assigned_lan_port = Some(available_ports.alloc()?);
|
||||
}
|
||||
Ok(Self {
|
||||
@@ -33,7 +33,7 @@ impl BindInfo {
|
||||
mut assigned_lan_port,
|
||||
..
|
||||
} = self;
|
||||
if options.add_ssl.is_some() || options.secure {
|
||||
if options.add_ssl.is_some() || options.secure.is_some() {
|
||||
assigned_lan_port = if let Some(port) = assigned_lan_port.take() {
|
||||
Some(port)
|
||||
} else {
|
||||
@@ -51,24 +51,30 @@ impl BindInfo {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, TS)]
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, TS)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Security {
|
||||
pub ssl: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
pub struct BindOptions {
|
||||
#[ts(type = "string")]
|
||||
pub scheme: InternedString,
|
||||
#[ts(type = "string | null")]
|
||||
pub scheme: Option<InternedString>,
|
||||
pub preferred_external_port: u16,
|
||||
pub add_ssl: Option<AddSslOptions>,
|
||||
pub secure: bool,
|
||||
pub ssl: bool,
|
||||
pub secure: Option<Security>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
pub struct AddSslOptions {
|
||||
#[ts(type = "string")]
|
||||
pub scheme: InternedString,
|
||||
#[ts(type = "string | null")]
|
||||
pub scheme: Option<InternedString>,
|
||||
pub preferred_external_port: u16,
|
||||
// #[serde(default)]
|
||||
// pub add_x_forwarded_headers: bool, // TODO
|
||||
|
||||
@@ -39,7 +39,7 @@ impl Host {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, TS)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
pub enum HostKind {
|
||||
|
||||
@@ -7,6 +7,7 @@ pub mod host;
|
||||
pub mod keys;
|
||||
pub mod mdns;
|
||||
pub mod net_controller;
|
||||
pub mod service_interface;
|
||||
pub mod ssl;
|
||||
pub mod static_server;
|
||||
pub mod tor;
|
||||
|
||||
@@ -247,7 +247,7 @@ impl NetService {
|
||||
None,
|
||||
external,
|
||||
(self.ip, *port).into(),
|
||||
if bind.options.ssl {
|
||||
if bind.options.secure.as_ref().map_or(false, |s| s.ssl) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(ssl.alpn.clone())
|
||||
|
||||
115
core/startos/src/net/service_interface.rs
Normal file
115
core/startos/src/net/service_interface.rs
Normal file
@@ -0,0 +1,115 @@
|
||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||
|
||||
use models::{HostId, ServiceInterfaceId};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ts_rs::TS;
|
||||
|
||||
use crate::net::host::binding::BindOptions;
|
||||
use crate::net::host::HostKind;
|
||||
use crate::prelude::*;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ServiceInterfaceWithHostInfo {
|
||||
#[serde(flatten)]
|
||||
pub service_interface: ServiceInterface,
|
||||
pub host_info: ExportedHostInfo,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ExportedHostInfo {
|
||||
pub id: HostId,
|
||||
pub kind: HostKind,
|
||||
pub hostnames: Vec<ExportedHostnameInfo>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(rename_all_fields = "camelCase")]
|
||||
#[serde(tag = "kind")]
|
||||
pub enum ExportedHostnameInfo {
|
||||
Ip {
|
||||
network_interface_id: String,
|
||||
public: bool,
|
||||
hostname: ExportedIpHostname,
|
||||
},
|
||||
Onion {
|
||||
hostname: ExportedOnionHostname,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ExportedOnionHostname {
|
||||
pub value: String,
|
||||
pub port: Option<u16>,
|
||||
pub ssl_port: Option<u16>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(rename_all_fields = "camelCase")]
|
||||
#[serde(tag = "kind")]
|
||||
pub enum ExportedIpHostname {
|
||||
Ipv4 {
|
||||
value: Ipv4Addr,
|
||||
port: Option<u16>,
|
||||
ssl_port: Option<u16>,
|
||||
},
|
||||
Ipv6 {
|
||||
value: Ipv6Addr,
|
||||
port: Option<u16>,
|
||||
ssl_port: Option<u16>,
|
||||
},
|
||||
Local {
|
||||
value: String,
|
||||
port: Option<u16>,
|
||||
ssl_port: Option<u16>,
|
||||
},
|
||||
Domain {
|
||||
domain: String,
|
||||
subdomain: Option<String>,
|
||||
port: Option<u16>,
|
||||
ssl_port: Option<u16>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ServiceInterface {
|
||||
pub id: ServiceInterfaceId,
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
pub has_primary: bool,
|
||||
pub disabled: bool,
|
||||
pub masked: bool,
|
||||
pub address_info: AddressInfo,
|
||||
#[serde(rename = "type")]
|
||||
pub interface_type: ServiceInterfaceType,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum ServiceInterfaceType {
|
||||
Ui,
|
||||
P2p,
|
||||
Api,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AddressInfo {
|
||||
pub username: Option<String>,
|
||||
pub host_id: HostId,
|
||||
pub bind_options: BindOptions,
|
||||
pub suffix: String,
|
||||
}
|
||||
@@ -24,7 +24,12 @@ lazy_static::lazy_static! {
|
||||
#[serde(untagged)]
|
||||
pub enum Progress {
|
||||
Complete(bool),
|
||||
Progress { done: u64, total: Option<u64> },
|
||||
Progress {
|
||||
#[ts(type = "number")]
|
||||
done: u64,
|
||||
#[ts(type = "number | null")]
|
||||
total: Option<u64>,
|
||||
},
|
||||
}
|
||||
impl Progress {
|
||||
pub fn new() -> Self {
|
||||
|
||||
@@ -11,7 +11,7 @@ use clap::Parser;
|
||||
use emver::VersionRange;
|
||||
use imbl::OrdMap;
|
||||
use imbl_value::{json, InternedString};
|
||||
use models::{ActionId, HealthCheckId, ImageId, PackageId, VolumeId};
|
||||
use models::{ActionId, HealthCheckId, HostId, ImageId, PackageId, VolumeId};
|
||||
use patch_db::json_ptr::JsonPointer;
|
||||
use rpc_toolkit::{from_fn, from_fn_async, AnyContext, Context, Empty, HandlerExt, ParentHandler};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -25,11 +25,13 @@ use crate::db::model::package::{
|
||||
use crate::disk::mount::filesystem::idmapped::IdMapped;
|
||||
use crate::disk::mount::filesystem::loop_dev::LoopDev;
|
||||
use crate::disk::mount::filesystem::overlayfs::OverlayGuard;
|
||||
use crate::net::host::binding::BindOptions;
|
||||
use crate::net::host::HostKind;
|
||||
use crate::prelude::*;
|
||||
use crate::s9pk::rpc::SKIP_ENV;
|
||||
use crate::service::cli::ContainerCliContext;
|
||||
use crate::service::ServiceActorSeed;
|
||||
use crate::status::health_check::{HealthCheckResult, HealthCheckString};
|
||||
use crate::status::health_check::HealthCheckResult;
|
||||
use crate::status::MainStatus;
|
||||
use crate::util::clap::FromStrParser;
|
||||
use crate::util::{new_guid, Invoke};
|
||||
@@ -185,21 +187,7 @@ struct GetServicePortForwardParams {
|
||||
package_id: Option<PackageId>,
|
||||
internal_port: u32,
|
||||
}
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, TS)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct BindOptionsSecure {
|
||||
ssl: bool,
|
||||
}
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, TS)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct BindOptions {
|
||||
scheme: Option<String>,
|
||||
preferred_external_port: u32,
|
||||
add_ssl: Option<AddSslOptions>,
|
||||
secure: Option<BindOptionsSecure>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, TS)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
@@ -379,7 +367,7 @@ async fn export_action(context: EffectContext, data: ExportActionParams) -> Resu
|
||||
.as_package_data_mut()
|
||||
.as_idx_mut(&package_id)
|
||||
.or_not_found(&package_id)?
|
||||
.as_exposed_actions_mut();
|
||||
.as_actions_mut();
|
||||
let mut value = model.de()?;
|
||||
value
|
||||
.insert(data.id, data.metadata)
|
||||
@@ -402,7 +390,7 @@ async fn remove_action(context: EffectContext, data: RemoveActionParams) -> Resu
|
||||
.as_package_data_mut()
|
||||
.as_idx_mut(&package_id)
|
||||
.or_not_found(&package_id)?
|
||||
.as_exposed_actions_mut();
|
||||
.as_actions_mut();
|
||||
let mut value = model.de()?;
|
||||
value.remove(&data.id).map(|_| ()).unwrap_or_default();
|
||||
model.ser(&value)
|
||||
@@ -447,35 +435,16 @@ async fn get_host_info(
|
||||
async fn clear_bindings(context: EffectContext, _: Empty) -> Result<Value, Error> {
|
||||
todo!()
|
||||
}
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
|
||||
enum BindKind {
|
||||
Static,
|
||||
Single,
|
||||
Multi,
|
||||
}
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
|
||||
struct AddSslOptions {
|
||||
scheme: Option<String>,
|
||||
preferred_external_port: u32,
|
||||
add_x_forwarded_headers: Option<bool>,
|
||||
}
|
||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
struct BindParams {
|
||||
kind: BindKind,
|
||||
id: String,
|
||||
internal_port: u32,
|
||||
scheme: String,
|
||||
preferred_external_port: u32,
|
||||
add_ssl: Option<AddSslOptions>,
|
||||
secure: Option<BindOptionsSecure>,
|
||||
kind: HostKind,
|
||||
id: HostId,
|
||||
internal_port: u16,
|
||||
#[serde(flatten)]
|
||||
options: BindOptions,
|
||||
}
|
||||
async fn bind(_: AnyContext, BindParams { .. }: BindParams) -> Result<Value, Error> {
|
||||
todo!()
|
||||
@@ -918,19 +887,14 @@ async fn set_main_status(context: EffectContext, params: SetMainStatus) -> Resul
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
struct SetHealth {
|
||||
#[ts(type = "string")]
|
||||
name: HealthCheckId,
|
||||
status: HealthCheckString,
|
||||
message: Option<String>,
|
||||
id: HealthCheckId,
|
||||
#[serde(flatten)]
|
||||
result: HealthCheckResult,
|
||||
}
|
||||
|
||||
async fn set_health(
|
||||
context: EffectContext,
|
||||
SetHealth {
|
||||
name,
|
||||
status,
|
||||
message,
|
||||
}: SetHealth,
|
||||
SetHealth { id, result }: SetHealth,
|
||||
) -> Result<Value, Error> {
|
||||
let context = context.deref()?;
|
||||
|
||||
@@ -939,43 +903,22 @@ async fn set_health(
|
||||
.ctx
|
||||
.db
|
||||
.mutate(move |db| {
|
||||
let mut main = db
|
||||
.as_public()
|
||||
.as_package_data()
|
||||
.as_idx(package_id)
|
||||
.or_not_found(package_id)?
|
||||
.as_status()
|
||||
.as_main()
|
||||
.de()?;
|
||||
match &mut main {
|
||||
&mut MainStatus::Running { ref mut health, .. }
|
||||
| &mut MainStatus::BackingUp { ref mut health, .. } => {
|
||||
health.remove(&name);
|
||||
|
||||
health.insert(
|
||||
name,
|
||||
match status {
|
||||
HealthCheckString::Disabled => HealthCheckResult::Disabled,
|
||||
HealthCheckString::Passing => HealthCheckResult::Success,
|
||||
HealthCheckString::Starting => HealthCheckResult::Starting,
|
||||
HealthCheckString::Warning => HealthCheckResult::Loading {
|
||||
message: message.unwrap_or_default(),
|
||||
},
|
||||
HealthCheckString::Failure => HealthCheckResult::Failure {
|
||||
error: message.unwrap_or_default(),
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
_ => return Ok(()),
|
||||
};
|
||||
db.as_public_mut()
|
||||
.as_package_data_mut()
|
||||
.as_idx_mut(package_id)
|
||||
.or_not_found(package_id)?
|
||||
.as_status_mut()
|
||||
.as_main_mut()
|
||||
.ser(&main)
|
||||
.mutate(|main| {
|
||||
match main {
|
||||
&mut MainStatus::Running { ref mut health, .. }
|
||||
| &mut MainStatus::BackingUp { ref mut health, .. } => {
|
||||
health.insert(id, result);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
})
|
||||
.await?;
|
||||
Ok(json!(()))
|
||||
@@ -1100,7 +1043,7 @@ enum DependencyRequirement {
|
||||
#[ts(type = "string")]
|
||||
version_spec: VersionRange,
|
||||
#[ts(type = "string")]
|
||||
registry: Url,
|
||||
registry_url: Url,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
Exists {
|
||||
@@ -1109,7 +1052,7 @@ enum DependencyRequirement {
|
||||
#[ts(type = "string")]
|
||||
version_spec: VersionRange,
|
||||
#[ts(type = "string")]
|
||||
registry: Url,
|
||||
registry_url: Url,
|
||||
},
|
||||
}
|
||||
// filebrowser:exists,bitcoind:running:foo+bar+baz
|
||||
@@ -1119,7 +1062,7 @@ impl FromStr for DependencyRequirement {
|
||||
match s.split_once(':') {
|
||||
Some((id, "e")) | Some((id, "exists")) => Ok(Self::Exists {
|
||||
id: id.parse()?,
|
||||
registry: "".parse()?, // TODO
|
||||
registry_url: "".parse()?, // TODO
|
||||
version_spec: "*".parse()?, // TODO
|
||||
}),
|
||||
Some((id, rest)) => {
|
||||
@@ -1143,14 +1086,14 @@ impl FromStr for DependencyRequirement {
|
||||
Ok(Self::Running {
|
||||
id: id.parse()?,
|
||||
health_checks,
|
||||
registry: "".parse()?, // TODO
|
||||
registry_url: "".parse()?, // TODO
|
||||
version_spec: "*".parse()?, // TODO
|
||||
})
|
||||
}
|
||||
None => Ok(Self::Running {
|
||||
id: s.parse()?,
|
||||
health_checks: BTreeSet::new(),
|
||||
registry: "".parse()?, // TODO
|
||||
registry_url: "".parse()?, // TODO
|
||||
version_spec: "*".parse()?, // TODO
|
||||
}),
|
||||
}
|
||||
@@ -1186,13 +1129,13 @@ async fn set_dependencies(
|
||||
.map(|dependency| match dependency {
|
||||
DependencyRequirement::Exists {
|
||||
id,
|
||||
registry,
|
||||
registry_url,
|
||||
version_spec,
|
||||
} => (
|
||||
id,
|
||||
CurrentDependencyInfo {
|
||||
kind: CurrentDependencyKind::Exists,
|
||||
registry,
|
||||
registry_url,
|
||||
version_spec,
|
||||
icon: todo!(),
|
||||
title: todo!(),
|
||||
@@ -1201,13 +1144,13 @@ async fn set_dependencies(
|
||||
DependencyRequirement::Running {
|
||||
id,
|
||||
health_checks,
|
||||
registry,
|
||||
registry_url,
|
||||
version_spec,
|
||||
} => (
|
||||
id,
|
||||
CurrentDependencyInfo {
|
||||
kind: CurrentDependencyKind::Running { health_checks },
|
||||
registry,
|
||||
registry_url,
|
||||
version_spec,
|
||||
icon: todo!(),
|
||||
title: todo!(),
|
||||
|
||||
@@ -172,6 +172,8 @@ impl ServiceMap {
|
||||
icon,
|
||||
last_backup: None,
|
||||
current_dependencies: Default::default(),
|
||||
actions: Default::default(),
|
||||
service_interfaces: Default::default(),
|
||||
hosts: Default::default(),
|
||||
store_exposed_dependents: Default::default(),
|
||||
},
|
||||
|
||||
@@ -2,35 +2,35 @@ pub use models::HealthCheckId;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ts_rs::TS;
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct HealthCheckResult {
|
||||
pub name: String,
|
||||
#[serde(flatten)]
|
||||
pub kind: HealthCheckResultKind,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(tag = "result")]
|
||||
pub enum HealthCheckResult {
|
||||
Success,
|
||||
pub enum HealthCheckResultKind {
|
||||
Success { message: String },
|
||||
Disabled,
|
||||
Starting,
|
||||
Loading { message: String },
|
||||
Failure { error: String },
|
||||
Failure { message: String },
|
||||
}
|
||||
impl std::fmt::Display for HealthCheckResult {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
HealthCheckResult::Success => write!(f, "Succeeded"),
|
||||
HealthCheckResult::Disabled => write!(f, "Disabled"),
|
||||
HealthCheckResult::Starting => write!(f, "Starting"),
|
||||
HealthCheckResult::Loading { message } => write!(f, "Loading ({})", message),
|
||||
HealthCheckResult::Failure { error } => write!(f, "Failed ({})", error),
|
||||
let name = &self.name;
|
||||
match &self.kind {
|
||||
HealthCheckResultKind::Success { message } => {
|
||||
write!(f, "{name}: Succeeded ({message})")
|
||||
}
|
||||
HealthCheckResultKind::Disabled => write!(f, "{name}: Disabled"),
|
||||
HealthCheckResultKind::Starting => write!(f, "{name}: Starting"),
|
||||
HealthCheckResultKind::Loading { message } => write!(f, "{name}: Loading ({message})"),
|
||||
HealthCheckResultKind::Failure { message } => write!(f, "{name}: Failed ({message})"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, ts_rs::TS)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[ts(export)]
|
||||
pub enum HealthCheckString {
|
||||
Passing,
|
||||
Disabled,
|
||||
Starting,
|
||||
Warning,
|
||||
Failure,
|
||||
}
|
||||
|
||||
@@ -6,13 +6,13 @@ export class Dependency {
|
||||
| {
|
||||
type: "running"
|
||||
versionSpec: Checker
|
||||
url: string
|
||||
registryUrl: string
|
||||
healthChecks: string[]
|
||||
}
|
||||
| {
|
||||
type: "exists"
|
||||
versionSpec: Checker
|
||||
url: string
|
||||
registryUrl: string
|
||||
},
|
||||
) {}
|
||||
}
|
||||
|
||||
@@ -1,71 +1,58 @@
|
||||
import { object, string } from "ts-matches"
|
||||
import { Effects } from "../types"
|
||||
import { Origin } from "./Origin"
|
||||
import { AddSslOptions } from "../../../core/startos/bindings/AddSslOptions"
|
||||
import { Security } from "../../../core/startos/bindings/Security"
|
||||
import { BindOptions } from "../../../core/startos/bindings/BindOptions"
|
||||
import { AlpnInfo } from "../../../core/startos/bindings/AlpnInfo"
|
||||
|
||||
export { AddSslOptions, Security, BindOptions }
|
||||
|
||||
const knownProtocols = {
|
||||
http: {
|
||||
secure: false,
|
||||
ssl: false,
|
||||
secure: null,
|
||||
defaultPort: 80,
|
||||
withSsl: "https",
|
||||
alpn: { specified: ["http/1.1"] } as AlpnInfo,
|
||||
},
|
||||
https: {
|
||||
secure: true,
|
||||
ssl: true,
|
||||
secure: { ssl: true },
|
||||
defaultPort: 443,
|
||||
},
|
||||
ws: {
|
||||
secure: false,
|
||||
ssl: false,
|
||||
secure: null,
|
||||
defaultPort: 80,
|
||||
withSsl: "wss",
|
||||
alpn: { specified: ["http/1.1"] } as AlpnInfo,
|
||||
},
|
||||
wss: {
|
||||
secure: true,
|
||||
ssl: true,
|
||||
secure: { ssl: true },
|
||||
defaultPort: 443,
|
||||
},
|
||||
ssh: {
|
||||
secure: true,
|
||||
ssl: false,
|
||||
secure: { ssl: false },
|
||||
defaultPort: 22,
|
||||
},
|
||||
bitcoin: {
|
||||
secure: true,
|
||||
ssl: false,
|
||||
secure: { ssl: false },
|
||||
defaultPort: 8333,
|
||||
},
|
||||
lightning: {
|
||||
secure: true,
|
||||
ssl: true,
|
||||
secure: { ssl: true },
|
||||
defaultPort: 9735,
|
||||
},
|
||||
grpc: {
|
||||
secure: true,
|
||||
ssl: true,
|
||||
secure: { ssl: true },
|
||||
defaultPort: 50051,
|
||||
},
|
||||
dns: {
|
||||
secure: true,
|
||||
ssl: false,
|
||||
secure: { ssl: false },
|
||||
defaultPort: 53,
|
||||
},
|
||||
} as const
|
||||
|
||||
export type Scheme = string | null
|
||||
|
||||
type AddSslOptions = {
|
||||
scheme: Scheme
|
||||
preferredExternalPort: number
|
||||
addXForwardedHeaders: boolean | null /** default: false */
|
||||
}
|
||||
type Security = { ssl: boolean }
|
||||
export type BindOptions = {
|
||||
scheme: Scheme
|
||||
preferredExternalPort: number
|
||||
addSsl: AddSslOptions | null
|
||||
secure: Security | null
|
||||
}
|
||||
type KnownProtocols = typeof knownProtocols
|
||||
type ProtocolsWithSslVariants = {
|
||||
[K in keyof KnownProtocols]: KnownProtocols[K] extends {
|
||||
@@ -177,9 +164,10 @@ export class Host {
|
||||
if ("noAddSsl" in options && options.noAddSsl) return null
|
||||
if ("withSsl" in protoInfo && protoInfo.withSsl)
|
||||
return {
|
||||
addXForwardedHeaders: null,
|
||||
// addXForwardedHeaders: null,
|
||||
preferredExternalPort: knownProtocols[protoInfo.withSsl].defaultPort,
|
||||
scheme: protoInfo.withSsl,
|
||||
alpn: protoInfo.alpn,
|
||||
...("addSsl" in options ? options.addSsl : null),
|
||||
}
|
||||
return null
|
||||
|
||||
@@ -9,7 +9,6 @@ import { ParamsMaybePackageId } from "../../../core/startos/bindings/ParamsMaybe
|
||||
import { SetConfigured } from "../../../core/startos/bindings/SetConfigured"
|
||||
import { SetHealth } from "../../../core/startos/bindings/SetHealth"
|
||||
import { ExposeForDependentsParams } from "../../../core/startos/bindings/ExposeForDependentsParams"
|
||||
import { ExposeUiParams } from "../../../core/startos/bindings/ExposeUiParams"
|
||||
import { GetSslCertificateParams } from "../../../core/startos/bindings/GetSslCertificateParams"
|
||||
import { GetSslKeyParams } from "../../../core/startos/bindings/GetSslKeyParams"
|
||||
import { GetServiceInterfaceParams } from "../../../core/startos/bindings/GetServiceInterfaceParams"
|
||||
@@ -24,7 +23,6 @@ import { ExportActionParams } from "../../../core/startos/bindings/ExportActionP
|
||||
import { RemoveActionParams } from "../../../core/startos/bindings/RemoveActionParams"
|
||||
import { ReverseProxyParams } from "../../../core/startos/bindings/ReverseProxyParams"
|
||||
import { MountParams } from "../../../core/startos/bindings/MountParams"
|
||||
import { ExposedUI } from "../../../core/startos/bindings/ExposedUI"
|
||||
function typeEquality<ExpectedType>(_a: ExpectedType) {}
|
||||
describe("startosTypeValidation ", () => {
|
||||
test(`checking the params match`, () => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export * as configTypes from "./config/configTypes"
|
||||
import { AddSslOptions } from "../../core/startos/bindings/AddSslOptions"
|
||||
import { HealthCheckId } from "../../core/startos/bindings/HealthCheckId"
|
||||
import { HealthCheckResult } from "../../core/startos/bindings/HealthCheckResult"
|
||||
import { MainEffects, ServiceInterfaceType, Signals } from "./StartSdk"
|
||||
import { InputSpec } from "./config/configTypes"
|
||||
import { DependenciesReceipt } from "./config/setupConfig"
|
||||
@@ -324,16 +325,13 @@ export type Effects = {
|
||||
/** Removes all network bindings */
|
||||
clearBindings(): Promise<void>
|
||||
/** Creates a host connected to the specified port with the provided options */
|
||||
bind(options: {
|
||||
kind: "static" | "single" | "multi"
|
||||
id: string
|
||||
internalPort: number
|
||||
|
||||
scheme: Scheme
|
||||
preferredExternalPort: number
|
||||
addSsl: AddSslOptions | null
|
||||
secure: { ssl: boolean } | null
|
||||
}): Promise<void>
|
||||
bind(
|
||||
options: {
|
||||
kind: "static" | "single" | "multi"
|
||||
id: string
|
||||
internalPort: number
|
||||
} & BindOptions,
|
||||
): Promise<void>
|
||||
/** Retrieves the current hostname(s) associated with a host id */
|
||||
// getHostInfo(options: {
|
||||
// kind: "static" | "single"
|
||||
@@ -479,11 +477,11 @@ export type Effects = {
|
||||
algorithm: "ecdsa" | "ed25519" | null
|
||||
}) => Promise<string>
|
||||
|
||||
setHealth(o: {
|
||||
name: string
|
||||
status: HealthStatus
|
||||
message: string | null
|
||||
}): Promise<void>
|
||||
setHealth(
|
||||
o: HealthCheckResult & {
|
||||
id: HealthCheckId
|
||||
},
|
||||
): Promise<void>
|
||||
|
||||
/** Set the dependencies of what the service needs, usually ran during the set config as a best practice */
|
||||
setDependencies(options: {
|
||||
@@ -590,7 +588,7 @@ export type KnownError =
|
||||
export type Dependency = {
|
||||
id: PackageId
|
||||
versionSpec: string
|
||||
url: string
|
||||
registryUrl: string
|
||||
} & ({ kind: "exists" } | { kind: "running"; healthChecks: string[] })
|
||||
export type Dependencies = Array<Dependency>
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Url } from '@start9labs/shared'
|
||||
import { Manifest } from '../../../../core/startos/bindings/Manifest'
|
||||
|
||||
export type StoreURL = string
|
||||
export type StoreName = string
|
||||
@@ -41,35 +42,6 @@ export interface DependencyMetadata {
|
||||
hidden: boolean
|
||||
}
|
||||
|
||||
export interface Manifest {
|
||||
id: string
|
||||
title: string
|
||||
version: string
|
||||
gitHash?: string
|
||||
description: {
|
||||
short: string
|
||||
long: string
|
||||
}
|
||||
replaces?: string[]
|
||||
releaseNotes: string
|
||||
license: string // name of license
|
||||
wrapperRepo: Url
|
||||
upstreamRepo: Url
|
||||
supportSite: Url
|
||||
marketingSite: Url
|
||||
donationUrl: Url | null
|
||||
alerts: {
|
||||
install: string | null
|
||||
uninstall: string | null
|
||||
restore: string | null
|
||||
start: string | null
|
||||
stop: string | null
|
||||
}
|
||||
dependencies: Record<string, Dependency>
|
||||
osVersion: string
|
||||
hasConfig: boolean
|
||||
}
|
||||
|
||||
export interface Dependency {
|
||||
description: string | null
|
||||
optional: boolean
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
} from 'rxjs'
|
||||
import { AbstractMarketplaceService } from '@start9labs/marketplace'
|
||||
import { MarketplaceService } from 'src/app/services/marketplace.service'
|
||||
import { DataModel, PackageState } from 'src/app/services/patch-db/data-model'
|
||||
import { DataModel } from 'src/app/services/patch-db/data-model'
|
||||
import { SplitPaneTracker } from 'src/app/services/split-pane.service'
|
||||
import { Emver, THEME } from '@start9labs/shared'
|
||||
import { ConnectionService } from 'src/app/services/connection.service'
|
||||
@@ -77,12 +77,10 @@ export class MenuComponent {
|
||||
filter(([prev, curr]) =>
|
||||
Object.values(prev).some(
|
||||
p =>
|
||||
[
|
||||
PackageState.Installing,
|
||||
PackageState.Updating,
|
||||
PackageState.Restoring,
|
||||
].includes(p.stateInfo.state) &&
|
||||
[PackageState.Installed, PackageState.Removing].includes(
|
||||
['installing', 'updating', 'restoring'].includes(
|
||||
p.stateInfo.state,
|
||||
) &&
|
||||
['installed', 'removing'].includes(
|
||||
curr[getManifest(p).id].stateInfo.state,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Component } from '@angular/core'
|
||||
import { ModalController } from '@ionic/angular'
|
||||
import { map, take } from 'rxjs/operators'
|
||||
import { DataModel, PackageState } from 'src/app/services/patch-db/data-model'
|
||||
import { DataModel } from 'src/app/services/patch-db/data-model'
|
||||
import { PatchDB } from 'patch-db-client'
|
||||
import { firstValueFrom } from 'rxjs'
|
||||
import { getManifest } from 'src/app/util/get-package-data'
|
||||
@@ -38,7 +38,7 @@ export class BackupSelectPage {
|
||||
id,
|
||||
title,
|
||||
icon: pkg.icon,
|
||||
disabled: pkg.stateInfo.state !== PackageState.Installed,
|
||||
disabled: pkg.stateInfo.state !== 'installed',
|
||||
checked: false,
|
||||
}
|
||||
})
|
||||
|
||||
@@ -11,8 +11,6 @@ import { PatchDB } from 'patch-db-client'
|
||||
import {
|
||||
DataModel,
|
||||
PackageDataEntry,
|
||||
PackageMainStatus,
|
||||
Status,
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
import { GenericFormPage } from 'src/app/modals/generic-form/generic-form.page'
|
||||
import { isEmptyObject, ErrorToastService, getPkgId } from '@start9labs/shared'
|
||||
@@ -20,6 +18,7 @@ import { ActionSuccessPage } from 'src/app/modals/action-success/action-success.
|
||||
import { hasCurrentDeps } from 'src/app/util/has-deps'
|
||||
import { getAllPackages, getManifest } from 'src/app/util/get-package-data'
|
||||
import { ActionMetadata } from '@start9labs/start-sdk/cjs/sdk/lib/types'
|
||||
import { Status } from '../../../../../../../../core/startos/bindings/Status'
|
||||
|
||||
@Component({
|
||||
selector: 'app-actions',
|
||||
|
||||
@@ -8,9 +8,8 @@ import { PatchDB } from 'patch-db-client'
|
||||
import { QRComponent } from 'src/app/components/qr/qr.component'
|
||||
import { map } from 'rxjs'
|
||||
import { types as T } from '@start9labs/start-sdk'
|
||||
|
||||
type ServiceInterface = T.ServiceInterface
|
||||
type ServiceInterfaceWithHostInfo = T.ServiceInterfaceWithHostInfo
|
||||
import { ServiceInterface } from '../../../../../../../../core/startos/bindings/ServiceInterface'
|
||||
import { ServiceInterfaceWithHostInfo } from '../../../../../../../../core/startos/bindings/ServiceInterfaceWithHostInfo'
|
||||
|
||||
type MappedInterface = ServiceInterface & {
|
||||
addresses: MappedAddress[]
|
||||
@@ -109,12 +108,10 @@ function getAddresses(
|
||||
const username = addressInfo.username ? addressInfo.username + '@' : ''
|
||||
const suffix = addressInfo.suffix || ''
|
||||
|
||||
const hostnames =
|
||||
host.kind === 'multi'
|
||||
? host.hostnames
|
||||
: host.hostname
|
||||
const hostnames = host.kind === 'multi' ? host.hostnames : [] // TODO: non-multi
|
||||
/* host.hostname
|
||||
? [host.hostname]
|
||||
: []
|
||||
: [] */
|
||||
|
||||
const addresses: MappedAddress[] = []
|
||||
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
|
||||
import {
|
||||
MainStatus,
|
||||
PackageDataEntry,
|
||||
PackageMainStatus,
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
|
||||
import { PkgInfo } from 'src/app/util/get-package-info'
|
||||
import { UiLauncherService } from 'src/app/services/ui-launcher.service'
|
||||
import { MainStatus } from '../../../../../../../../../core/startos/bindings/MainStatus'
|
||||
|
||||
@Component({
|
||||
selector: 'app-list-pkg',
|
||||
@@ -21,13 +18,13 @@ export class AppListPkgComponent {
|
||||
get pkgMainStatus(): MainStatus {
|
||||
return (
|
||||
this.pkg.entry.status.main || {
|
||||
status: PackageMainStatus.Stopped,
|
||||
status: 'stopped',
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
get sigtermTimeout(): string | null {
|
||||
return this.pkgMainStatus.status === PackageMainStatus.Stopping
|
||||
return this.pkgMainStatus.status === 'stopping'
|
||||
? this.pkgMainStatus.timeout
|
||||
: null
|
||||
}
|
||||
|
||||
@@ -11,10 +11,7 @@ import {
|
||||
import { PackageProperties } from 'src/app/util/properties.util'
|
||||
import { QRComponent } from 'src/app/components/qr/qr.component'
|
||||
import { PatchDB } from 'patch-db-client'
|
||||
import {
|
||||
DataModel,
|
||||
PackageMainStatus,
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
import { DataModel } from 'src/app/services/patch-db/data-model'
|
||||
import {
|
||||
ErrorToastService,
|
||||
getPkgId,
|
||||
@@ -42,7 +39,7 @@ export class AppPropertiesPage {
|
||||
|
||||
stopped$ = this.patch
|
||||
.watch$('packageData', this.pkgId, 'status', 'main', 'status')
|
||||
.pipe(map(status => status === PackageMainStatus.Stopped))
|
||||
.pipe(map(status => status === 'stopped'))
|
||||
|
||||
@ViewChild(IonBackButtonDelegate, { static: false })
|
||||
backButton?: IonBackButtonDelegate
|
||||
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
isRestoring,
|
||||
isUpdating,
|
||||
} from 'src/app/util/get-package-data'
|
||||
import { Manifest } from '@start9labs/marketplace'
|
||||
import { Manifest } from '../../../../../../../../core/startos/bindings/Manifest'
|
||||
|
||||
export interface DependencyInfo {
|
||||
id: string
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ModalController, ToastController } from '@ionic/angular'
|
||||
import { copyToClipboard, MarkdownComponent } from '@start9labs/shared'
|
||||
import { from } from 'rxjs'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { Manifest } from '@start9labs/marketplace'
|
||||
import { Manifest } from '../../../../../../../../../../core/startos/bindings/Manifest'
|
||||
|
||||
@Component({
|
||||
selector: 'app-show-additional',
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
|
||||
import { ConnectionService } from 'src/app/services/connection.service'
|
||||
import {
|
||||
HealthCheckResult,
|
||||
HealthResult,
|
||||
MainStatus,
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
import { Manifest } from '@start9labs/marketplace'
|
||||
import { HealthCheckResult } from '../../../../../../../../../../core/startos/bindings/HealthCheckResult'
|
||||
|
||||
@Component({
|
||||
selector: 'app-show-health-checks',
|
||||
@@ -21,12 +16,12 @@ export class AppShowHealthChecksComponent {
|
||||
|
||||
constructor(private readonly connectionService: ConnectionService) {}
|
||||
|
||||
isLoading(result: HealthResult): boolean {
|
||||
return result === HealthResult.Starting || result === HealthResult.Loading
|
||||
isLoading(result: HealthCheckResult['result']): boolean {
|
||||
return result === 'starting' || result === 'loading'
|
||||
}
|
||||
|
||||
isReady(result: HealthResult): boolean {
|
||||
return result !== HealthResult.Failure && result !== HealthResult.Loading
|
||||
isReady(result: HealthCheckResult['result']): boolean {
|
||||
return result !== 'failure' && result !== 'loading'
|
||||
}
|
||||
|
||||
asIsOrder() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
|
||||
import { FullProgress } from 'src/app/services/patch-db/data-model'
|
||||
import { FullProgress } from '../../../../../../../../../../core/startos/bindings/FullProgress'
|
||||
|
||||
@Component({
|
||||
selector: 'app-show-progress',
|
||||
|
||||
@@ -8,8 +8,6 @@ import {
|
||||
import {
|
||||
DataModel,
|
||||
PackageDataEntry,
|
||||
PackageMainStatus,
|
||||
Status,
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
import { ErrorToastService } from '@start9labs/shared'
|
||||
import { AlertController, LoadingController } from '@ionic/angular'
|
||||
@@ -22,8 +20,9 @@ import {
|
||||
getManifest,
|
||||
getAllPackages,
|
||||
} from 'src/app/util/get-package-data'
|
||||
import { Manifest } from '@start9labs/marketplace'
|
||||
import { PatchDB } from 'patch-db-client'
|
||||
import { Status } from '../../../../../../../../../../core/startos/bindings/Status'
|
||||
import { Manifest } from '../../../../../../../../../../core/startos/bindings/Manifest'
|
||||
|
||||
@Component({
|
||||
selector: 'app-show-status',
|
||||
@@ -84,7 +83,7 @@ export class AppShowStatusComponent {
|
||||
}
|
||||
|
||||
get sigtermTimeout(): string | null {
|
||||
return this.pkgStatus?.main.status === PackageMainStatus.Stopping
|
||||
return this.pkgStatus?.main.status === 'stopping'
|
||||
? this.pkgStatus.main.timeout
|
||||
: null
|
||||
}
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core'
|
||||
import { HealthResult } from 'src/app/services/patch-db/data-model'
|
||||
import { HealthCheckResult } from '../../../../../../../../../core/startos/bindings/HealthCheckResult'
|
||||
|
||||
@Pipe({
|
||||
name: 'healthColor',
|
||||
})
|
||||
export class HealthColorPipe implements PipeTransform {
|
||||
transform(val: HealthResult): string {
|
||||
transform(val: HealthCheckResult['result']): string {
|
||||
switch (val) {
|
||||
case HealthResult.Success:
|
||||
case 'success':
|
||||
return 'success'
|
||||
case HealthResult.Failure:
|
||||
case 'failure':
|
||||
return 'warning'
|
||||
case HealthResult.Disabled:
|
||||
case 'disabled':
|
||||
return 'dark'
|
||||
case HealthResult.Starting:
|
||||
case HealthResult.Loading:
|
||||
case 'starting':
|
||||
case 'loading':
|
||||
return 'primary'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import { ModalService } from 'src/app/services/modal.service'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { from, map, Observable } from 'rxjs'
|
||||
import { PatchDB } from 'patch-db-client'
|
||||
import { Manifest } from '@start9labs/marketplace'
|
||||
import { Manifest } from '../../../../../../../../../core/startos/bindings/Manifest'
|
||||
|
||||
export interface Button {
|
||||
title: string
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core'
|
||||
import {
|
||||
DataModel,
|
||||
HealthCheckResult,
|
||||
PackageMainStatus,
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
import { DataModel } from 'src/app/services/patch-db/data-model'
|
||||
import { isEmptyObject } from '@start9labs/shared'
|
||||
import { map, startWith } from 'rxjs/operators'
|
||||
import { PatchDB } from 'patch-db-client'
|
||||
import { Observable } from 'rxjs'
|
||||
import { Manifest } from '@start9labs/marketplace'
|
||||
import { HealthCheckResult } from '../../../../../../../../../core/startos/bindings/HealthCheckResult'
|
||||
import { Manifest } from '../../../../../../../../../core/startos/bindings/Manifest'
|
||||
|
||||
@Pipe({
|
||||
name: 'toHealthChecks',
|
||||
@@ -21,8 +18,7 @@ export class ToHealthChecksPipe implements PipeTransform {
|
||||
): Observable<Record<string, HealthCheckResult | null> | null> {
|
||||
return this.patch.watch$('packageData', manifest.id, 'status', 'main').pipe(
|
||||
map(main => {
|
||||
return main.status === PackageMainStatus.Running &&
|
||||
!isEmptyObject(main.health)
|
||||
return main.status === 'running' && !isEmptyObject(main.health)
|
||||
? main.health
|
||||
: null
|
||||
}),
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
import { AlertController, LoadingController } from '@ionic/angular'
|
||||
import {
|
||||
AbstractMarketplaceService,
|
||||
Manifest,
|
||||
MarketplacePkg,
|
||||
} from '@start9labs/marketplace'
|
||||
import {
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
>
|
||||
<!-- active -->
|
||||
<ion-note
|
||||
*ngIf="pkgStatus === 'backing-up'; else queued"
|
||||
*ngIf="pkgStatus === 'backingUp'; else queued"
|
||||
class="inline"
|
||||
slot="end"
|
||||
>
|
||||
|
||||
@@ -6,11 +6,9 @@ import {
|
||||
} from '@angular/core'
|
||||
import { PatchDB } from 'patch-db-client'
|
||||
import { take } from 'rxjs/operators'
|
||||
import {
|
||||
DataModel,
|
||||
PackageMainStatus,
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
import { DataModel } from 'src/app/services/patch-db/data-model'
|
||||
import { Observable } from 'rxjs'
|
||||
import { MainStatus } from '../../../../../../../../../core/startos/bindings/MainStatus'
|
||||
|
||||
@Component({
|
||||
selector: 'backing-up',
|
||||
@@ -32,7 +30,7 @@ export class BackingUpComponent {
|
||||
name: 'pkgMainStatus',
|
||||
})
|
||||
export class PkgMainStatusPipe implements PipeTransform {
|
||||
transform(pkgId: string): Observable<PackageMainStatus> {
|
||||
transform(pkgId: string): Observable<MainStatus['status']> {
|
||||
return this.patch.watch$('packageData', pkgId, 'status', 'main', 'status')
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { ConfigService } from 'src/app/services/config.service'
|
||||
import cbor from 'cbor'
|
||||
import { ErrorToastService } from '@start9labs/shared'
|
||||
import { Manifest } from '@start9labs/marketplace'
|
||||
import { Manifest } from '../../../../../../../../core/startos/bindings/Manifest'
|
||||
|
||||
interface Positions {
|
||||
[key: string]: [bigint, bigint] // [position, length]
|
||||
|
||||
@@ -10,7 +10,6 @@ import { MarketplaceService } from 'src/app/services/marketplace.service'
|
||||
import {
|
||||
AbstractMarketplaceService,
|
||||
Marketplace,
|
||||
Manifest,
|
||||
MarketplacePkg,
|
||||
StoreIdentity,
|
||||
} from '@start9labs/marketplace'
|
||||
@@ -25,6 +24,7 @@ import {
|
||||
isUpdating,
|
||||
} from 'src/app/util/get-package-data'
|
||||
import { dryUpdate } from 'src/app/util/dry-update'
|
||||
import { Manifest } from '../../../../../../../core/startos/bindings/Manifest'
|
||||
|
||||
interface UpdatesData {
|
||||
hosts: StoreIdentity[]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core'
|
||||
import { Progress } from 'src/app/services/patch-db/data-model'
|
||||
import { Progress } from '../../../../../../../core/startos/bindings/Progress'
|
||||
|
||||
@Pipe({
|
||||
name: 'installingProgressString',
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core'
|
||||
import {
|
||||
PackageMainStatus,
|
||||
PackageState,
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
import { ConfigService } from '../../services/config.service'
|
||||
import { PackageState } from '../../../../../../../core/startos/bindings/PackageState'
|
||||
import { MainStatus } from '../../../../../../../core/startos/bindings/MainStatus'
|
||||
|
||||
@Pipe({
|
||||
name: 'isLaunchable',
|
||||
@@ -11,7 +9,10 @@ import { ConfigService } from '../../services/config.service'
|
||||
export class LaunchablePipe implements PipeTransform {
|
||||
constructor(private configService: ConfigService) {}
|
||||
|
||||
transform(state: PackageState, status: PackageMainStatus): boolean {
|
||||
transform(
|
||||
state: PackageState['state'],
|
||||
status: MainStatus['status'],
|
||||
): boolean {
|
||||
return this.configService.isLaunchable(state, status)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Pipe, PipeTransform } from '@angular/core'
|
||||
import { PackageDataEntry } from '../../services/patch-db/data-model'
|
||||
import { hasUi } from '../../services/config.service'
|
||||
import { getManifest } from 'src/app/util/get-package-data'
|
||||
import { Manifest } from '@start9labs/marketplace'
|
||||
import { Manifest } from '../../../../../../../core/startos/bindings/Manifest'
|
||||
|
||||
@Pipe({
|
||||
name: 'hasUi',
|
||||
|
||||
@@ -1,21 +1,16 @@
|
||||
import {
|
||||
InstalledState,
|
||||
PackageDataEntry,
|
||||
PackageMainStatus,
|
||||
PackageState,
|
||||
ServerStatusInfo,
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
import { Metric, NotificationLevel, RR, ServerNotifications } from './api.types'
|
||||
import { BTC_ICON, LND_ICON, PROXY_ICON } from './api-icons'
|
||||
import {
|
||||
DependencyMetadata,
|
||||
Manifest,
|
||||
MarketplacePkg,
|
||||
} from '@start9labs/marketplace'
|
||||
import { DependencyMetadata, MarketplacePkg } from '@start9labs/marketplace'
|
||||
import { Log } from '@start9labs/shared'
|
||||
import { ServerStatus } from '../../../../../../../core/startos/bindings/ServerStatus'
|
||||
import { Manifest } from '../../../../../../../core/startos/bindings/Manifest'
|
||||
|
||||
export module Mock {
|
||||
export const ServerUpdated: ServerStatusInfo = {
|
||||
export const ServerUpdated: ServerStatus = {
|
||||
backupProgress: null,
|
||||
updateProgress: null,
|
||||
updated: true,
|
||||
@@ -75,16 +70,26 @@ export module Mock {
|
||||
osVersion: '0.2.12',
|
||||
dependencies: {},
|
||||
hasConfig: true,
|
||||
images: ['main'],
|
||||
assets: [],
|
||||
volumes: ['main'],
|
||||
hardwareRequirements: {
|
||||
device: {},
|
||||
arch: null,
|
||||
ram: null,
|
||||
},
|
||||
}
|
||||
|
||||
export const MockManifestLnd: Manifest = {
|
||||
id: 'lnd',
|
||||
title: 'Lightning Network Daemon',
|
||||
version: '0.11.1',
|
||||
gitHash: 'abcdefgh',
|
||||
description: {
|
||||
short: 'A bolt spec compliant client.',
|
||||
long: 'More info about LND. More info about LND. More info about LND.',
|
||||
},
|
||||
replaces: ['banks', 'governments'],
|
||||
releaseNotes: 'Dual funded channels!',
|
||||
license: 'MIT',
|
||||
wrapperRepo: 'https://github.com/start9labs/lnd-wrapper',
|
||||
@@ -113,6 +118,14 @@ export module Mock {
|
||||
},
|
||||
},
|
||||
hasConfig: true,
|
||||
images: ['main'],
|
||||
assets: [],
|
||||
volumes: ['main'],
|
||||
hardwareRequirements: {
|
||||
device: {},
|
||||
arch: null,
|
||||
ram: null,
|
||||
},
|
||||
}
|
||||
|
||||
export const MockManifestBitcoinProxy: Manifest = {
|
||||
@@ -145,7 +158,16 @@ export module Mock {
|
||||
optional: false,
|
||||
},
|
||||
},
|
||||
replaces: [],
|
||||
hasConfig: false,
|
||||
images: ['main'],
|
||||
assets: [],
|
||||
volumes: ['main'],
|
||||
hardwareRequirements: {
|
||||
device: {},
|
||||
arch: null,
|
||||
ram: null,
|
||||
},
|
||||
}
|
||||
|
||||
export const BitcoinDep: DependencyMetadata = {
|
||||
@@ -1376,7 +1398,7 @@ export module Mock {
|
||||
|
||||
export const bitcoind: PackageDataEntry<InstalledState> = {
|
||||
stateInfo: {
|
||||
state: PackageState.Installed,
|
||||
state: 'installed',
|
||||
manifest: MockManifestBitcoind,
|
||||
},
|
||||
icon: '/assets/img/service-icons/bitcoind.svg',
|
||||
@@ -1384,7 +1406,7 @@ export module Mock {
|
||||
status: {
|
||||
configured: true,
|
||||
main: {
|
||||
status: PackageMainStatus.Running,
|
||||
status: 'running',
|
||||
started: new Date().toISOString(),
|
||||
health: {},
|
||||
},
|
||||
@@ -1408,9 +1430,10 @@ export module Mock {
|
||||
scheme: 'http',
|
||||
preferredExternalPort: 80,
|
||||
addSsl: {
|
||||
addXForwardedHeaders: false,
|
||||
// addXForwardedHeaders: false,
|
||||
preferredExternalPort: 443,
|
||||
scheme: 'https',
|
||||
alpn: { specified: ['http/1.1', 'h2'] },
|
||||
},
|
||||
secure: null,
|
||||
},
|
||||
@@ -1480,9 +1503,10 @@ export module Mock {
|
||||
scheme: 'http',
|
||||
preferredExternalPort: 80,
|
||||
addSsl: {
|
||||
addXForwardedHeaders: false,
|
||||
// addXForwardedHeaders: false,
|
||||
preferredExternalPort: 443,
|
||||
scheme: 'https',
|
||||
alpn: { specified: ['http/1.1'] },
|
||||
},
|
||||
secure: null,
|
||||
},
|
||||
@@ -1608,13 +1632,15 @@ export module Mock {
|
||||
},
|
||||
},
|
||||
currentDependencies: {},
|
||||
hosts: {},
|
||||
storeExposedDependents: [],
|
||||
marketplaceUrl: 'https://registry.start9.com/',
|
||||
developerKey: 'developer-key',
|
||||
}
|
||||
|
||||
export const bitcoinProxy: PackageDataEntry<InstalledState> = {
|
||||
stateInfo: {
|
||||
state: PackageState.Installed,
|
||||
state: 'installed',
|
||||
manifest: MockManifestBitcoinProxy,
|
||||
},
|
||||
icon: '/assets/img/service-icons/btc-rpc-proxy.png',
|
||||
@@ -1622,7 +1648,7 @@ export module Mock {
|
||||
status: {
|
||||
configured: false,
|
||||
main: {
|
||||
status: PackageMainStatus.Stopped,
|
||||
status: 'stopped',
|
||||
},
|
||||
dependencyConfigErrors: {},
|
||||
},
|
||||
@@ -1643,9 +1669,10 @@ export module Mock {
|
||||
scheme: 'http',
|
||||
preferredExternalPort: 80,
|
||||
addSsl: {
|
||||
addXForwardedHeaders: false,
|
||||
// addXForwardedHeaders: false,
|
||||
preferredExternalPort: 443,
|
||||
scheme: 'https',
|
||||
alpn: { specified: ['http/1.1', 'h2'] },
|
||||
},
|
||||
secure: {
|
||||
ssl: true,
|
||||
@@ -1745,13 +1772,15 @@ export module Mock {
|
||||
healthChecks: [],
|
||||
},
|
||||
},
|
||||
hosts: {},
|
||||
storeExposedDependents: [],
|
||||
marketplaceUrl: 'https://registry.start9.com/',
|
||||
developerKey: 'developer-key',
|
||||
}
|
||||
|
||||
export const lnd: PackageDataEntry<InstalledState> = {
|
||||
stateInfo: {
|
||||
state: PackageState.Installed,
|
||||
state: 'installed',
|
||||
manifest: MockManifestLnd,
|
||||
},
|
||||
icon: '/assets/img/service-icons/lnd.png',
|
||||
@@ -1759,7 +1788,7 @@ export module Mock {
|
||||
status: {
|
||||
configured: true,
|
||||
main: {
|
||||
status: PackageMainStatus.Stopped,
|
||||
status: 'stopped',
|
||||
},
|
||||
dependencyConfigErrors: {
|
||||
'btc-rpc-proxy': 'Username not found',
|
||||
@@ -1993,9 +2022,10 @@ export module Mock {
|
||||
kind: 'exists',
|
||||
registryUrl: 'https://community-registry.start9.com',
|
||||
versionSpec: '>2.0.0', // @TODO
|
||||
healthChecks: [],
|
||||
},
|
||||
},
|
||||
hosts: {},
|
||||
storeExposedDependents: [],
|
||||
marketplaceUrl: 'https://registry.start9.com/',
|
||||
developerKey: 'developer-key',
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { Dump, Revision } from 'patch-db-client'
|
||||
import { Manifest, MarketplacePkg, StoreInfo } from '@start9labs/marketplace'
|
||||
import { MarketplacePkg, StoreInfo } from '@start9labs/marketplace'
|
||||
import { PackagePropertiesVersioned } from 'src/app/util/properties.util'
|
||||
import { ConfigSpec } from 'src/app/pkg-config/config-types'
|
||||
import {
|
||||
DataModel,
|
||||
HealthCheckResult,
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
import { DataModel } from 'src/app/services/patch-db/data-model'
|
||||
import { StartOSDiskInfo, LogsRes, ServerLogsReq } from '@start9labs/shared'
|
||||
import { HealthCheckResult } from '../../../../../../../core/startos/bindings/HealthCheckResult'
|
||||
import { Manifest } from '../../../../../../../core/startos/bindings/Manifest'
|
||||
|
||||
export module RR {
|
||||
// DB
|
||||
|
||||
@@ -10,12 +10,8 @@ import {
|
||||
} from 'patch-db-client'
|
||||
import {
|
||||
DataModel,
|
||||
FullProgress,
|
||||
InstallingState,
|
||||
PackageDataEntry,
|
||||
PackageMainStatus,
|
||||
PackageState,
|
||||
ServerStatus,
|
||||
StateInfo,
|
||||
UpdatingState,
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
@@ -41,6 +37,8 @@ import { WebSocketSubjectConfig } from 'rxjs/webSocket'
|
||||
import { AuthService } from '../auth.service'
|
||||
import { ConnectionService } from '../connection.service'
|
||||
import { StoreInfo } from '@start9labs/marketplace'
|
||||
import { FullProgress } from '../../../../../../../core/startos/bindings/FullProgress'
|
||||
import { ServerStatus } from '../../../../../../../core/startos/bindings/ServerStatus'
|
||||
|
||||
const PROGRESS: FullProgress = {
|
||||
overall: {
|
||||
@@ -576,7 +574,7 @@ export class MockApiService extends ApiService {
|
||||
{
|
||||
op: PatchOp.REPLACE,
|
||||
path: appPath,
|
||||
value: PackageMainStatus.BackingUp,
|
||||
value: 'backingUp',
|
||||
},
|
||||
]
|
||||
this.mockRevision(appPatch)
|
||||
@@ -586,7 +584,7 @@ export class MockApiService extends ApiService {
|
||||
this.mockRevision([
|
||||
{
|
||||
...appPatch[0],
|
||||
value: PackageMainStatus.Stopped,
|
||||
value: 'stopped',
|
||||
},
|
||||
])
|
||||
this.mockRevision([
|
||||
@@ -692,7 +690,7 @@ export class MockApiService extends ApiService {
|
||||
// state: PackageState.Installing,
|
||||
|
||||
// if updating
|
||||
state: PackageState.Updating,
|
||||
state: 'updating',
|
||||
manifest: mockPatchData.packageData[params.id].stateInfo.manifest!,
|
||||
|
||||
// both
|
||||
@@ -757,7 +755,7 @@ export class MockApiService extends ApiService {
|
||||
value: {
|
||||
...Mock.LocalPkgs[id],
|
||||
stateInfo: {
|
||||
state: PackageState.Restoring,
|
||||
state: 'restoring',
|
||||
installingInfo: {
|
||||
newManifest: Mock.LocalPkgs[id].stateInfo.manifest!,
|
||||
progress: PROGRESS,
|
||||
@@ -789,7 +787,7 @@ export class MockApiService extends ApiService {
|
||||
{
|
||||
op: PatchOp.REPLACE,
|
||||
path: path + '/status',
|
||||
value: PackageMainStatus.Running,
|
||||
value: 'running',
|
||||
},
|
||||
{
|
||||
op: PatchOp.REPLACE,
|
||||
@@ -849,7 +847,7 @@ export class MockApiService extends ApiService {
|
||||
{
|
||||
op: PatchOp.REPLACE,
|
||||
path: path + '/status',
|
||||
value: PackageMainStatus.Starting,
|
||||
value: 'starting',
|
||||
},
|
||||
]
|
||||
|
||||
@@ -870,7 +868,7 @@ export class MockApiService extends ApiService {
|
||||
{
|
||||
op: PatchOp.REPLACE,
|
||||
path: path + '/status',
|
||||
value: PackageMainStatus.Starting,
|
||||
value: 'starting',
|
||||
},
|
||||
{
|
||||
op: PatchOp.ADD,
|
||||
@@ -886,7 +884,7 @@ export class MockApiService extends ApiService {
|
||||
{
|
||||
op: PatchOp.REPLACE,
|
||||
path: path + '/status',
|
||||
value: PackageMainStatus.Running,
|
||||
value: 'running',
|
||||
},
|
||||
{
|
||||
op: PatchOp.REMOVE,
|
||||
@@ -923,7 +921,7 @@ export class MockApiService extends ApiService {
|
||||
{
|
||||
op: PatchOp.REPLACE,
|
||||
path: path + '/status',
|
||||
value: PackageMainStatus.Restarting,
|
||||
value: 'restarting',
|
||||
},
|
||||
{
|
||||
op: PatchOp.REPLACE,
|
||||
@@ -947,7 +945,7 @@ export class MockApiService extends ApiService {
|
||||
op: PatchOp.REPLACE,
|
||||
path: path,
|
||||
value: {
|
||||
status: PackageMainStatus.Stopped,
|
||||
status: 'stopped',
|
||||
},
|
||||
},
|
||||
]
|
||||
@@ -959,7 +957,7 @@ export class MockApiService extends ApiService {
|
||||
op: PatchOp.REPLACE,
|
||||
path: path,
|
||||
value: {
|
||||
status: PackageMainStatus.Stopping,
|
||||
status: 'stopping',
|
||||
timeout: '35s',
|
||||
},
|
||||
},
|
||||
@@ -989,7 +987,7 @@ export class MockApiService extends ApiService {
|
||||
{
|
||||
op: PatchOp.REPLACE,
|
||||
path: `/packageData/${params.id}/stateInfo/state`,
|
||||
value: PackageState.Removing,
|
||||
value: 'removing',
|
||||
},
|
||||
]
|
||||
|
||||
@@ -1105,7 +1103,7 @@ export class MockApiService extends ApiService {
|
||||
op: PatchOp.REPLACE,
|
||||
path: `/packageData/${id}/stateInfo`,
|
||||
value: {
|
||||
state: PackageState.Installed,
|
||||
state: 'installed',
|
||||
manifest: Mock.LocalPkgs[id].stateInfo.manifest,
|
||||
},
|
||||
},
|
||||
@@ -1149,11 +1147,11 @@ export class MockApiService extends ApiService {
|
||||
this.mockRevision(patch2)
|
||||
|
||||
setTimeout(async () => {
|
||||
const patch3: Operation<ServerStatus>[] = [
|
||||
const patch3: Operation<boolean>[] = [
|
||||
{
|
||||
op: PatchOp.REPLACE,
|
||||
path: '/serverInfo/status',
|
||||
value: ServerStatus.Updated,
|
||||
path: '/serverInfo/statusInfo/updated',
|
||||
value: true,
|
||||
},
|
||||
{
|
||||
op: PatchOp.REMOVE,
|
||||
@@ -1167,7 +1165,7 @@ export class MockApiService extends ApiService {
|
||||
{
|
||||
op: PatchOp.REPLACE,
|
||||
path: '/serverInfo/status',
|
||||
value: ServerStatus.Running,
|
||||
value: 'running',
|
||||
},
|
||||
]
|
||||
this.mockRevision(patch4)
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
import {
|
||||
DataModel,
|
||||
HealthResult,
|
||||
PackageMainStatus,
|
||||
PackageState,
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
import { DataModel } from 'src/app/services/patch-db/data-model'
|
||||
import { Mock } from './api.fixures'
|
||||
import { BUILT_IN_WIDGETS } from '../../pages/widgets/built-in/widgets'
|
||||
|
||||
@@ -39,6 +34,8 @@ export const mockPatchData: DataModel = {
|
||||
ackInstructions: {},
|
||||
},
|
||||
serverInfo: {
|
||||
arch: 'x86_64',
|
||||
onionAddress: 'myveryownspecialtoraddress',
|
||||
id: 'abcdefgh',
|
||||
version: '0.3.5.1',
|
||||
lastBackup: new Date(new Date().valueOf() - 604800001).toISOString(),
|
||||
@@ -47,11 +44,15 @@ export const mockPatchData: DataModel = {
|
||||
ipInfo: {
|
||||
eth0: {
|
||||
ipv4: '10.0.0.1',
|
||||
ipv4Range: '10.0.0.1/24',
|
||||
ipv6: null,
|
||||
ipv6Range: null,
|
||||
},
|
||||
wlan0: {
|
||||
ipv4: '10.0.90.12',
|
||||
ipv4Range: '10.0.90.12/24',
|
||||
ipv6: 'FE80:CD00:0000:0CDE:1257:0000:211E:729CD',
|
||||
ipv6Range: 'FE80:CD00:0000:0CDE:1257:0000:211E:729CD/64',
|
||||
},
|
||||
},
|
||||
lastWifiRegion: null,
|
||||
@@ -72,11 +73,18 @@ export const mockPatchData: DataModel = {
|
||||
caFingerprint: 'SHA-256: 63 2B 11 99 44 40 17 DF 37 FC C3 DF 0F 3D 15',
|
||||
ntpSynced: false,
|
||||
platform: 'x86_64-nonfree',
|
||||
zram: true,
|
||||
governor: 'performance',
|
||||
wifi: {
|
||||
ssids: [],
|
||||
selected: null,
|
||||
connected: null,
|
||||
},
|
||||
},
|
||||
packageData: {
|
||||
bitcoind: {
|
||||
stateInfo: {
|
||||
state: PackageState.Installed,
|
||||
state: 'installed',
|
||||
manifest: {
|
||||
...Mock.MockManifestBitcoind,
|
||||
version: '0.20.0',
|
||||
@@ -87,31 +95,31 @@ export const mockPatchData: DataModel = {
|
||||
status: {
|
||||
configured: true,
|
||||
main: {
|
||||
status: PackageMainStatus.Running,
|
||||
status: 'running',
|
||||
started: '2021-06-14T20:49:17.774Z',
|
||||
health: {
|
||||
'ephemeral-health-check': {
|
||||
name: 'Ephemeral Health Check',
|
||||
result: HealthResult.Starting,
|
||||
result: 'starting',
|
||||
},
|
||||
'chain-state': {
|
||||
name: 'Chain State',
|
||||
result: HealthResult.Loading,
|
||||
result: 'loading',
|
||||
message: 'Bitcoin is syncing from genesis',
|
||||
},
|
||||
'p2p-interface': {
|
||||
name: 'P2P',
|
||||
result: HealthResult.Success,
|
||||
result: 'success',
|
||||
message: 'Health check successful',
|
||||
},
|
||||
'rpc-interface': {
|
||||
name: 'RPC',
|
||||
result: HealthResult.Failure,
|
||||
result: 'failure',
|
||||
message: 'RPC interface unreachable.',
|
||||
},
|
||||
'unnecessary-health-check': {
|
||||
name: 'Unnecessary Health Check',
|
||||
result: HealthResult.Disabled,
|
||||
result: 'disabled',
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -135,9 +143,10 @@ export const mockPatchData: DataModel = {
|
||||
scheme: 'http',
|
||||
preferredExternalPort: 80,
|
||||
addSsl: {
|
||||
addXForwardedHeaders: false,
|
||||
// addXForwardedHeaders: false,
|
||||
preferredExternalPort: 443,
|
||||
scheme: 'https',
|
||||
alpn: { specified: ['http/1.1', 'h2'] },
|
||||
},
|
||||
secure: null,
|
||||
},
|
||||
@@ -207,9 +216,10 @@ export const mockPatchData: DataModel = {
|
||||
scheme: 'http',
|
||||
preferredExternalPort: 80,
|
||||
addSsl: {
|
||||
addXForwardedHeaders: false,
|
||||
// addXForwardedHeaders: false,
|
||||
preferredExternalPort: 443,
|
||||
scheme: 'https',
|
||||
alpn: { specified: ['http/1.1'] },
|
||||
},
|
||||
secure: null,
|
||||
},
|
||||
@@ -335,12 +345,14 @@ export const mockPatchData: DataModel = {
|
||||
},
|
||||
},
|
||||
currentDependencies: {},
|
||||
hosts: {},
|
||||
storeExposedDependents: [],
|
||||
marketplaceUrl: 'https://registry.start9.com/',
|
||||
developerKey: 'developer-key',
|
||||
},
|
||||
lnd: {
|
||||
stateInfo: {
|
||||
state: PackageState.Installed,
|
||||
state: 'installed',
|
||||
manifest: {
|
||||
...Mock.MockManifestLnd,
|
||||
version: '0.11.0',
|
||||
@@ -351,7 +363,7 @@ export const mockPatchData: DataModel = {
|
||||
status: {
|
||||
configured: true,
|
||||
main: {
|
||||
status: PackageMainStatus.Stopped,
|
||||
status: 'stopped',
|
||||
},
|
||||
dependencyConfigErrors: {
|
||||
'btc-rpc-proxy': 'This is a config unsatisfied error',
|
||||
@@ -586,6 +598,8 @@ export const mockPatchData: DataModel = {
|
||||
healthChecks: [],
|
||||
},
|
||||
},
|
||||
hosts: {},
|
||||
storeExposedDependents: [],
|
||||
marketplaceUrl: 'https://registry.start9.com/',
|
||||
developerKey: 'developer-key',
|
||||
},
|
||||
|
||||
@@ -2,14 +2,12 @@ import { DOCUMENT } from '@angular/common'
|
||||
import { Inject, Injectable } from '@angular/core'
|
||||
import { WorkspaceConfig } from '@start9labs/shared'
|
||||
import { types } from '@start9labs/start-sdk'
|
||||
import {
|
||||
PackageDataEntry,
|
||||
PackageMainStatus,
|
||||
PackageState,
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
|
||||
type HostnameInfoIp = types.HostnameInfoIp
|
||||
type HostnameInfoOnion = types.HostnameInfoOnion
|
||||
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
|
||||
import { PackageState } from '../../../../../../core/startos/bindings/PackageState'
|
||||
import { MainStatus } from '../../../../../../core/startos/bindings/MainStatus'
|
||||
import { ExportedOnionHostname } from '../../../../../../core/startos/bindings/ExportedOnionHostname'
|
||||
import { ExportedIpHostname } from '../../../../../../core/startos/bindings/ExportedIpHostname'
|
||||
import { ExportedHostnameInfo } from '../../../../../../core/startos/bindings/ExportedHostnameInfo'
|
||||
|
||||
const {
|
||||
gitHash,
|
||||
@@ -56,10 +54,11 @@ export class ConfigService {
|
||||
return window.isSecureContext || this.isTor()
|
||||
}
|
||||
|
||||
isLaunchable(state: PackageState, status: PackageMainStatus): boolean {
|
||||
return (
|
||||
state === PackageState.Installed && status === PackageMainStatus.Running
|
||||
)
|
||||
isLaunchable(
|
||||
state: PackageState['state'],
|
||||
status: MainStatus['status'],
|
||||
): boolean {
|
||||
return state === 'installed' && status === 'running'
|
||||
}
|
||||
|
||||
/** ${scheme}://${username}@${host}:${externalPort}${suffix} */
|
||||
@@ -76,31 +75,28 @@ export class ConfigService {
|
||||
const url = new URL(`${scheme}://${username}placeholder${suffix}`)
|
||||
|
||||
if (host.kind === 'multi') {
|
||||
const onionHostname = host.hostnames.find(
|
||||
(h: any) => h.kind === 'onion',
|
||||
) as HostnameInfoOnion
|
||||
const onionHostname = host.hostnames.find(h => h.kind === 'onion')
|
||||
?.hostname as ExportedOnionHostname
|
||||
|
||||
if (this.isTor() && onionHostname) {
|
||||
url.hostname = onionHostname.hostname.value
|
||||
url.hostname = onionHostname.value
|
||||
} else {
|
||||
const ipHostname = host.hostnames.find(
|
||||
(h: any) => h.kind === 'ip',
|
||||
) as HostnameInfoIp
|
||||
const ipHostname = host.hostnames.find(h => h.kind === 'ip')
|
||||
?.hostname as ExportedIpHostname
|
||||
|
||||
if (!ipHostname) return ''
|
||||
|
||||
url.hostname = this.hostname
|
||||
url.port = String(
|
||||
ipHostname.hostname.sslPort || ipHostname.hostname.port,
|
||||
)
|
||||
url.port = String(ipHostname.sslPort || ipHostname.port)
|
||||
}
|
||||
} else {
|
||||
const hostname = host.hostname
|
||||
throw new Error('unimplemented')
|
||||
const hostname = {} as ExportedHostnameInfo // host.hostname
|
||||
|
||||
if (!hostname) return ''
|
||||
|
||||
if (this.isTor() && hostname.kind === 'onion') {
|
||||
url.hostname = hostname.hostname.value
|
||||
url.hostname = (hostname.hostname as ExportedOnionHostname).value
|
||||
} else {
|
||||
url.hostname = this.hostname
|
||||
url.port = String(hostname.hostname.sslPort || hostname.hostname.port)
|
||||
|
||||
@@ -4,11 +4,8 @@ import { distinctUntilChanged, map, shareReplay } from 'rxjs/operators'
|
||||
import { PatchDB } from 'patch-db-client'
|
||||
import {
|
||||
DataModel,
|
||||
HealthResult,
|
||||
InstalledState,
|
||||
PackageDataEntry,
|
||||
PackageMainStatus,
|
||||
PackageState,
|
||||
} from './patch-db/data-model'
|
||||
import * as deepEqual from 'fast-deep-equal'
|
||||
import { isInstalled } from '../util/get-package-data'
|
||||
@@ -79,7 +76,7 @@ export class DepErrorService {
|
||||
const dep = pkgs[depId]
|
||||
|
||||
// not installed
|
||||
if (!dep || dep.stateInfo.state !== PackageState.Installed) {
|
||||
if (!dep || dep.stateInfo.state !== 'installed') {
|
||||
return {
|
||||
type: DependencyErrorType.NotInstalled,
|
||||
}
|
||||
@@ -107,19 +104,18 @@ export class DepErrorService {
|
||||
const depStatus = dep.status.main.status
|
||||
|
||||
// not running
|
||||
if (
|
||||
depStatus !== PackageMainStatus.Running &&
|
||||
depStatus !== PackageMainStatus.Starting
|
||||
) {
|
||||
if (depStatus !== 'running' && depStatus !== 'starting') {
|
||||
return {
|
||||
type: DependencyErrorType.NotRunning,
|
||||
}
|
||||
}
|
||||
|
||||
const currentDep = pkg.currentDependencies[depId]
|
||||
|
||||
// health check failure
|
||||
if (depStatus === PackageMainStatus.Running) {
|
||||
for (let id of pkg.currentDependencies[depId].healthChecks) {
|
||||
if (dep.status.main.health[id]?.result !== HealthResult.Success) {
|
||||
if (depStatus === 'running' && currentDep.kind === 'running') {
|
||||
for (let id of currentDep.healthChecks) {
|
||||
if (dep.status.main.health[id]?.result !== 'success') {
|
||||
return {
|
||||
type: DependencyErrorType.HealthChecksFailed,
|
||||
}
|
||||
|
||||
@@ -19,7 +19,11 @@ import {
|
||||
} from 'rxjs'
|
||||
import { RR } from 'src/app/services/api/api.types'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { DataModel, UIStore } from 'src/app/services/patch-db/data-model'
|
||||
import {
|
||||
DataModel,
|
||||
UIMarketplaceData,
|
||||
UIStore,
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
import { PatchDB } from 'patch-db-client'
|
||||
import {
|
||||
catchError,
|
||||
@@ -41,7 +45,7 @@ export class MarketplaceService implements AbstractMarketplaceService {
|
||||
private readonly knownHosts$: Observable<StoreIdentity[]> = this.patch
|
||||
.watch$('ui', 'marketplace', 'knownHosts')
|
||||
.pipe(
|
||||
map(hosts => {
|
||||
map((hosts: UIMarketplaceData['knownHosts']) => {
|
||||
const { start9, community } = this.config.marketplace
|
||||
let arr = [
|
||||
toStoreIdentity(start9, hosts[start9]),
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import { Url } from '@start9labs/shared'
|
||||
import { Manifest } from '@start9labs/marketplace'
|
||||
import { types } from '@start9labs/start-sdk'
|
||||
import { ActionMetadata } from '@start9labs/start-sdk/cjs/sdk/lib/types'
|
||||
import { Public } from '../../../../../../../core/startos/bindings/Public'
|
||||
import { PackageDataEntry as PDE } from '../../../../../../../core/startos/bindings/PackageDataEntry'
|
||||
import { FullProgress } from '../../../../../../../core/startos/bindings/FullProgress'
|
||||
import { Manifest } from '../../../../../../../core/startos/bindings/Manifest'
|
||||
type ServiceInterfaceWithHostInfo = types.ServiceInterfaceWithHostInfo
|
||||
|
||||
export interface DataModel {
|
||||
serverInfo: ServerInfo
|
||||
packageData: { [id: string]: PackageDataEntry }
|
||||
export type DataModel = Public & {
|
||||
ui: UIData
|
||||
packageData: Record<string, PackageDataEntry>
|
||||
}
|
||||
|
||||
export interface UIData {
|
||||
@@ -50,197 +52,31 @@ export interface UIStore {
|
||||
name?: string
|
||||
}
|
||||
|
||||
export interface ServerInfo {
|
||||
id: string
|
||||
version: string
|
||||
lastBackup: string | null
|
||||
lanAddress: Url
|
||||
torAddress: Url
|
||||
ipInfo: IpInfo
|
||||
lastWifiRegion: string | null
|
||||
unreadNotificationCount: number
|
||||
statusInfo: ServerStatusInfo
|
||||
eosVersionCompat: string
|
||||
passwordHash: string
|
||||
hostname: string
|
||||
pubkey: string
|
||||
caFingerprint: string
|
||||
ntpSynced: boolean
|
||||
platform: string
|
||||
}
|
||||
|
||||
export interface IpInfo {
|
||||
[iface: string]: {
|
||||
ipv4: string | null
|
||||
ipv6: string | null
|
||||
}
|
||||
}
|
||||
|
||||
export interface ServerStatusInfo {
|
||||
backupProgress: null | {
|
||||
[packageId: string]: {
|
||||
complete: boolean
|
||||
}
|
||||
}
|
||||
updated: boolean
|
||||
updateProgress: { size: number | null; downloaded: number } | null
|
||||
restarting: boolean
|
||||
shuttingDown: boolean
|
||||
}
|
||||
|
||||
export enum ServerStatus {
|
||||
Running = 'running',
|
||||
Updated = 'updated',
|
||||
BackingUp = 'backing-up',
|
||||
}
|
||||
|
||||
export type PackageDataEntry<T extends StateInfo = StateInfo> = {
|
||||
export type PackageDataEntry<T extends StateInfo = StateInfo> = PDE & {
|
||||
stateInfo: T
|
||||
icon: Url
|
||||
status: Status
|
||||
actions: Record<string, ActionMetadata>
|
||||
lastBackup: string | null
|
||||
currentDependencies: Record<string, CurrentDependencyInfo>
|
||||
serviceInterfaces: Record<string, ServiceInterfaceWithHostInfo>
|
||||
marketplaceUrl: string | null
|
||||
developerKey: string
|
||||
}
|
||||
|
||||
export type StateInfo = InstalledState | InstallingState | UpdatingState
|
||||
|
||||
export type InstalledState = {
|
||||
state: PackageState.Installed | PackageState.Removing
|
||||
state: 'installed' | 'removing'
|
||||
manifest: Manifest
|
||||
installingInfo?: undefined
|
||||
}
|
||||
|
||||
export type InstallingState = {
|
||||
state: PackageState.Installing | PackageState.Restoring
|
||||
state: 'installing' | 'restoring'
|
||||
installingInfo: InstallingInfo
|
||||
manifest?: undefined
|
||||
}
|
||||
|
||||
export type UpdatingState = {
|
||||
state: PackageState.Updating
|
||||
state: 'updating'
|
||||
installingInfo: InstallingInfo
|
||||
manifest: Manifest
|
||||
}
|
||||
|
||||
export enum PackageState {
|
||||
Installing = 'installing',
|
||||
Installed = 'installed',
|
||||
Updating = 'updating',
|
||||
Removing = 'removing',
|
||||
Restoring = 'restoring',
|
||||
}
|
||||
|
||||
export interface CurrentDependencyInfo {
|
||||
title: string
|
||||
icon: string
|
||||
kind: 'exists' | 'running'
|
||||
registryUrl: string
|
||||
versionSpec: string
|
||||
healthChecks: string[] // array of health check IDs
|
||||
}
|
||||
|
||||
export interface Status {
|
||||
configured: boolean
|
||||
main: MainStatus
|
||||
dependencyConfigErrors: { [id: string]: string | null }
|
||||
}
|
||||
|
||||
export type MainStatus =
|
||||
| MainStatusStopped
|
||||
| MainStatusStopping
|
||||
| MainStatusStarting
|
||||
| MainStatusRunning
|
||||
| MainStatusBackingUp
|
||||
| MainStatusRestarting
|
||||
|
||||
export interface MainStatusStopped {
|
||||
status: PackageMainStatus.Stopped
|
||||
}
|
||||
|
||||
export interface MainStatusStopping {
|
||||
status: PackageMainStatus.Stopping
|
||||
timeout: string
|
||||
}
|
||||
|
||||
export interface MainStatusStarting {
|
||||
status: PackageMainStatus.Starting
|
||||
restarting: boolean
|
||||
}
|
||||
|
||||
export interface MainStatusRunning {
|
||||
status: PackageMainStatus.Running
|
||||
started: string // UTC date string
|
||||
health: Record<string, HealthCheckResult>
|
||||
}
|
||||
|
||||
export interface MainStatusBackingUp {
|
||||
status: PackageMainStatus.BackingUp
|
||||
started: string | null // UTC date string
|
||||
}
|
||||
|
||||
export interface MainStatusRestarting {
|
||||
status: PackageMainStatus.Restarting
|
||||
}
|
||||
|
||||
export enum PackageMainStatus {
|
||||
Starting = 'starting',
|
||||
Running = 'running',
|
||||
Stopping = 'stopping',
|
||||
Stopped = 'stopped',
|
||||
BackingUp = 'backing-up',
|
||||
Restarting = 'restarting',
|
||||
}
|
||||
|
||||
export type HealthCheckResult = { name: string } & (
|
||||
| HealthCheckResultStarting
|
||||
| HealthCheckResultLoading
|
||||
| HealthCheckResultDisabled
|
||||
| HealthCheckResultSuccess
|
||||
| HealthCheckResultFailure
|
||||
)
|
||||
|
||||
export enum HealthResult {
|
||||
Starting = 'starting',
|
||||
Loading = 'loading',
|
||||
Disabled = 'disabled',
|
||||
Success = 'success',
|
||||
Failure = 'failure',
|
||||
}
|
||||
|
||||
export interface HealthCheckResultStarting {
|
||||
result: HealthResult.Starting
|
||||
}
|
||||
|
||||
export interface HealthCheckResultDisabled {
|
||||
result: HealthResult.Disabled
|
||||
}
|
||||
|
||||
export interface HealthCheckResultSuccess {
|
||||
result: HealthResult.Success
|
||||
message: string
|
||||
}
|
||||
|
||||
export interface HealthCheckResultLoading {
|
||||
result: HealthResult.Loading
|
||||
message: string
|
||||
}
|
||||
|
||||
export interface HealthCheckResultFailure {
|
||||
result: HealthResult.Failure
|
||||
message: string
|
||||
}
|
||||
|
||||
export type InstallingInfo = {
|
||||
progress: FullProgress
|
||||
newManifest: Manifest
|
||||
}
|
||||
|
||||
export type FullProgress = {
|
||||
overall: Progress
|
||||
phases: { name: string; progress: Progress }[]
|
||||
}
|
||||
export type Progress = boolean | { done: number; total: number | null } // false means indeterminate. true means complete
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
import { isEmptyObject } from '@start9labs/shared'
|
||||
import {
|
||||
MainStatusStarting,
|
||||
PackageDataEntry,
|
||||
PackageMainStatus,
|
||||
PackageState,
|
||||
Status,
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
|
||||
import { PkgDependencyErrors } from './dep-error.service'
|
||||
import { Status } from '../../../../../../core/startos/bindings/Status'
|
||||
|
||||
export interface PackageStatus {
|
||||
primary: PrimaryStatus
|
||||
@@ -22,7 +17,7 @@ export function renderPkgStatus(
|
||||
let dependency: DependencyStatus | null = null
|
||||
let health: HealthStatus | null = null
|
||||
|
||||
if (pkg.stateInfo.state === PackageState.Installed) {
|
||||
if (pkg.stateInfo.state === 'installed') {
|
||||
primary = getPrimaryStatus(pkg.status)
|
||||
dependency = getDependencyStatus(depErrors)
|
||||
health = getHealthStatus(pkg.status)
|
||||
@@ -36,7 +31,7 @@ export function renderPkgStatus(
|
||||
function getPrimaryStatus(status: Status): PrimaryStatus {
|
||||
if (!status.configured) {
|
||||
return PrimaryStatus.NeedsConfig
|
||||
} else if ((status.main as MainStatusStarting).restarting) {
|
||||
} else if (status.main.status === 'restarting') {
|
||||
return PrimaryStatus.Restarting
|
||||
} else {
|
||||
return status.main.status as any as PrimaryStatus
|
||||
@@ -50,7 +45,7 @@ function getDependencyStatus(depErrors: PkgDependencyErrors): DependencyStatus {
|
||||
}
|
||||
|
||||
function getHealthStatus(status: Status): HealthStatus | null {
|
||||
if (status.main.status !== PackageMainStatus.Running || !status.main.health) {
|
||||
if (status.main.status !== 'running' || !status.main.health) {
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
@@ -4,11 +4,10 @@ import {
|
||||
InstalledState,
|
||||
InstallingState,
|
||||
PackageDataEntry,
|
||||
PackageState,
|
||||
UpdatingState,
|
||||
} from 'src/app/services/patch-db/data-model'
|
||||
import { firstValueFrom } from 'rxjs'
|
||||
import { Manifest } from '@start9labs/marketplace'
|
||||
import { Manifest } from '../../../../../../core/startos/bindings/Manifest'
|
||||
|
||||
export async function getPackage(
|
||||
patch: PatchDB<DataModel>,
|
||||
@@ -32,29 +31,29 @@ export function getManifest(pkg: PackageDataEntry): Manifest {
|
||||
export function isInstalled(
|
||||
pkg: PackageDataEntry,
|
||||
): pkg is PackageDataEntry<InstalledState> {
|
||||
return pkg.stateInfo.state === PackageState.Installed
|
||||
return pkg.stateInfo.state === 'installed'
|
||||
}
|
||||
|
||||
export function isRemoving(
|
||||
pkg: PackageDataEntry,
|
||||
): pkg is PackageDataEntry<InstalledState> {
|
||||
return pkg.stateInfo.state === PackageState.Removing
|
||||
return pkg.stateInfo.state === 'removing'
|
||||
}
|
||||
|
||||
export function isInstalling(
|
||||
pkg: PackageDataEntry,
|
||||
): pkg is PackageDataEntry<InstallingState> {
|
||||
return pkg.stateInfo.state === PackageState.Installing
|
||||
return pkg.stateInfo.state === 'installing'
|
||||
}
|
||||
|
||||
export function isRestoring(
|
||||
pkg: PackageDataEntry,
|
||||
): pkg is PackageDataEntry<InstallingState> {
|
||||
return pkg.stateInfo.state === PackageState.Restoring
|
||||
return pkg.stateInfo.state === 'restoring'
|
||||
}
|
||||
|
||||
export function isUpdating(
|
||||
pkg: PackageDataEntry,
|
||||
): pkg is PackageDataEntry<UpdatingState> {
|
||||
return pkg.stateInfo.state === PackageState.Updating
|
||||
return pkg.stateInfo.state === 'updating'
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { PatchDB } from 'patch-db-client'
|
||||
import { DataModel, ServerInfo } from 'src/app/services/patch-db/data-model'
|
||||
import { DataModel } from 'src/app/services/patch-db/data-model'
|
||||
import { firstValueFrom } from 'rxjs'
|
||||
import { ServerInfo } from '../../../../../../core/startos/bindings/ServerInfo'
|
||||
|
||||
export async function getServerInfo(
|
||||
patch: PatchDB<DataModel>,
|
||||
|
||||
Reference in New Issue
Block a user