rename frontend to web

This commit is contained in:
Matt Hill
2023-11-13 15:59:16 -07:00
parent 09303ab2fb
commit 862ca375ee
869 changed files with 0 additions and 66 deletions

View File

@@ -0,0 +1,382 @@
import { InputSpec } from '@start9labs/start-sdk/lib/config/configTypes'
import { Url } from '@start9labs/shared'
import { Manifest } from '@start9labs/marketplace'
import { BackupJob } from '../api/api.types'
import { customSmtp } from '@start9labs/start-sdk/lib/config/configConstants'
import { NetworkInterfaceType } from '@start9labs/start-sdk/lib/util/utils'
import { DependencyInfo } from 'src/app/apps/portal/routes/service/types/dependency-info'
import { PackageStatus } from '../pkg-status-rendering.service'
export interface DataModel {
'server-info': ServerInfo
'package-data': { [id: string]: PackageDataEntry }
ui: UIData
}
export interface UIData {
name: string | null
'ack-welcome': string // emver
marketplace: UIMarketplaceData
gaming: {
snake: {
'high-score': number
}
}
'ack-instructions': Record<string, boolean>
theme: string
widgets: readonly Widget[]
desktop: readonly string[]
}
export interface Widget {
id: string
meta: {
name: string
width: number
height: number
mobileWidth: number
mobileHeight: number
}
url?: string
settings?: string
}
export interface UIMarketplaceData {
'selected-url': string
'known-hosts': {
'https://registry.start9.com/': UIStore
'https://community-registry.start9.com/': UIStore
[url: string]: UIStore
}
}
export interface UIStore {
name?: string
}
export interface ServerInfo {
id: string
version: string
country: string
ui: AddressInfo
network: NetworkInfo
'last-backup': string | null
'unread-notification-count': number
'status-info': ServerStatusInfo
'eos-version-compat': string
pubkey: string
'ca-fingerprint': string
'ntp-synced': boolean
zram: boolean
smtp: typeof customSmtp.validator._TYPE
'password-hash': string
platform: string
}
export type NetworkInfo = {
wifi: WiFiInfo
start9ToSubdomain: Omit<Domain, 'provider'> | null
domains: Domain[]
wanConfig: {
upnp: boolean
forwards: PortForward[]
}
proxies: Proxy[]
outboundProxy: OsOutboundProxy
primaryProxies: {
inbound: string | null
outbound: string | null
}
}
export type DomainInfo = {
domain: string
subdomain: string | null
}
export type InboundProxy = { proxyId: string } | 'primary' | null
export type OsOutboundProxy = InboundProxy
export type ServiceOutboundProxy = OsOutboundProxy | 'mirror'
export type PortForward = {
assigned: number
override: number | null
target: number
error: string | null
}
export type WiFiInfo = {
enabled: boolean
lastRegion: string | null
}
export type Domain = {
value: string
createdAt: string
provider: string
networkStrategy: NetworkStrategy
usedBy: {
service: { id: string | null; title: string } // null means startos
interfaces: { id: string | null; title: string }[] // null means startos
}[]
}
export type NetworkStrategy =
| { proxyId: string | null } // null means system primary
| { ipStrategy: 'ipv4' | 'ipv6' | 'dualstack' }
export type Proxy = {
id: string
name: string
createdAt: string
type: 'outbound' | 'inbound-outbound' | 'vlan' | { error: string }
endpoint: string
// below is overlay only
usedBy: {
services: { id: string | null; title: string }[] // implies outbound - null means startos
domains: string[] // implies inbound
}
primaryInbound: boolean
primaryOutbound: boolean
}
export interface IpInfo {
[iface: string]: {
wireless: boolean
ipv4: string | null
ipv6: string | null
}
}
export interface ServerStatusInfo {
'current-backup': null | {
job: BackupJob
'backup-progress': {
[packageId: string]: {
complete: boolean
}
}
}
updated: boolean
'update-progress': { size: number | null; downloaded: number } | null
restarting: boolean
'shutting-down': boolean
}
export enum ServerStatus {
Running = 'running',
Updated = 'updated',
BackingUp = 'backing-up',
}
export interface PackageDataEntry {
state: PackageState
manifest: Manifest
icon: string
installed?: InstalledPackageInfo // when: installed
actions?: Record<string, Action> // when: installed
'install-progress'?: InstallProgress // when: installing, updating, restoring
}
export type PackagePlus = {
pkg: PackageDataEntry
status: PackageStatus
dependencies: DependencyInfo[]
}
// export type PackageDataEntry =
// | PackageDataEntryInstalled
// | PackageDataEntryNeedsUpdate
// | PackageDataEntryRemoving
// | PackageDataEntryRestoring
// | PackageDataEntryUpdating
// | PackageDataEntryInstalling
// export type PackageDataEntryBase = {
// manifest: Manifest
// icon: Url
// }
// export interface PackageDataEntryInstalled extends PackageDataEntryBase {
// state: PackageState.Installed
// installed: InstalledPackageInfo
// actions: Record<string, Action>
// }
// export interface PackageDataEntryNeedsUpdate extends PackageDataEntryBase {
// state: PackageState.NeedsUpdate
// }
// export interface PackageDataEntryRemoving extends PackageDataEntryBase {
// state: PackageState.Removing
// }
// export interface PackageDataEntryRestoring extends PackageDataEntryBase {
// state: PackageState.Restoring
// 'install-progress': InstallProgress
// }
// export interface PackageDataEntryUpdating extends PackageDataEntryBase {
// state: PackageState.Updating
// 'install-progress': InstallProgress
// }
// export interface PackageDataEntryInstalling extends PackageDataEntryBase {
// state: PackageState.Installing
// 'install-progress': InstallProgress
// }
export enum PackageState {
Installing = 'installing',
Installed = 'installed',
Updating = 'updating',
Removing = 'removing',
Restoring = 'restoring',
NeedsUpdate = 'needs-update',
}
export interface InstalledPackageInfo {
status: Status
'last-backup': string | null
'installed-at': string
'current-dependencies': Record<string, CurrentDependencyInfo>
'current-dependents': Record<string, CurrentDependencyInfo>
'dependency-info': Record<string, { title: string; icon: Url }>
interfaceInfo: Record<string, InterfaceInfo>
'marketplace-url': string | null
'developer-key': string
'has-config': boolean
outboundProxy: ServiceOutboundProxy
}
export interface CurrentDependencyInfo {
'health-checks': string[] // array of health check IDs
}
export interface InterfaceInfo {
name: string
description: string
type: NetworkInterfaceType
addressInfo: AddressInfo
}
export interface AddressInfo {
ipInfo: IpInfo
lanHostname: string
torHostname: string
domainInfo: DomainInfo | null
}
export interface Action {
name: string
description: string
warning: string | null
disabled: string | null
'input-spec': InputSpec | null
group: string | null
}
export interface Status {
configured: boolean
main: MainStatus
'dependency-config-errors': { [id: string]: string | null }
}
export type MainStatus =
| MainStatusStopped
| MainStatusStopping
| MainStatusStarting
| MainStatusRunning
| MainStatusBackingUp
| MainStatusRestarting
| MainStatusConfiguring
export interface MainStatusStopped {
status: PackageMainStatus.Stopped
}
export interface MainStatusStopping {
status: PackageMainStatus.Stopping
}
export interface MainStatusStarting {
status: PackageMainStatus.Starting
}
export interface MainStatusRunning {
status: PackageMainStatus.Running
started: string // UTC date string
health: { [id: string]: HealthCheckResult }
}
export interface MainStatusBackingUp {
status: PackageMainStatus.BackingUp
}
export interface MainStatusRestarting {
status: PackageMainStatus.Restarting
}
export interface MainStatusConfiguring {
status: PackageMainStatus.Configuring
}
export enum PackageMainStatus {
Starting = 'starting',
Running = 'running',
Stopping = 'stopping',
Stopped = 'stopped',
BackingUp = 'backing-up',
Restarting = 'restarting',
Configuring = 'configuring',
}
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
reason: string
}
export interface HealthCheckResultSuccess {
result: HealthResult.Success
message: string
}
export interface HealthCheckResultLoading {
result: HealthResult.Loading
message: string
}
export interface HealthCheckResultFailure {
result: HealthResult.Failure
error: string
}
export interface InstallProgress {
readonly size: number | null
readonly downloaded: number
readonly 'download-complete': boolean
readonly validated: number
readonly 'validation-complete': boolean
readonly unpacked: number
readonly 'unpack-complete': boolean
}

View File

@@ -0,0 +1,25 @@
import { Bootstrapper, DBCache } from 'patch-db-client'
import { DataModel } from 'src/app/services/patch-db/data-model'
import { Injectable } from '@angular/core'
import { StorageService } from '../storage.service'
@Injectable({
providedIn: 'root',
})
export class LocalStorageBootstrap implements Bootstrapper<DataModel> {
static CONTENT_KEY = 'patch-db-cache'
constructor(private readonly storage: StorageService) {}
init(): DBCache<DataModel> {
const cache = this.storage.get<DBCache<DataModel>>(
LocalStorageBootstrap.CONTENT_KEY,
)
return cache || { sequence: 0, data: {} as DataModel }
}
update(cache: DBCache<DataModel>): void {
this.storage.set(LocalStorageBootstrap.CONTENT_KEY, cache)
}
}

View File

@@ -0,0 +1,61 @@
import { InjectionToken, Injector } from '@angular/core'
import { Update } from 'patch-db-client'
import {
bufferTime,
catchError,
filter,
switchMap,
take,
tap,
defer,
EMPTY,
from,
interval,
Observable,
} from 'rxjs'
import { DataModel } from './data-model'
import { AuthService } from '../auth.service'
import { ConnectionService } from '../connection.service'
import { ApiService } from '../api/embassy-api.service'
import { ConfigService } from '../config.service'
export const PATCH_SOURCE = new InjectionToken<Observable<Update<DataModel>[]>>(
'',
)
export function sourceFactory(
injector: Injector,
): Observable<Update<DataModel>[]> {
// defer() needed to avoid circular dependency with ApiService, since PatchDB is needed there
return defer(() => {
const api = injector.get(ApiService)
const authService = injector.get(AuthService)
const connectionService = injector.get(ConnectionService)
const configService = injector.get(ConfigService)
const isTor = configService.isTor()
const timeout = isTor ? 16000 : 4000
const websocket$ = api.openPatchWebsocket$().pipe(
bufferTime(250),
filter(updates => !!updates.length),
catchError((_, watch$) => {
connectionService.websocketConnected$.next(false)
return interval(timeout).pipe(
switchMap(() =>
from(api.echo({ message: 'ping', timeout })).pipe(
catchError(() => EMPTY),
),
),
take(1),
switchMap(() => watch$),
)
}),
tap(() => connectionService.websocketConnected$.next(true)),
)
return authService.isVerified$.pipe(
switchMap(verified => (verified ? websocket$ : EMPTY)),
)
})
}

View File

@@ -0,0 +1,20 @@
import { PatchDB } from 'patch-db-client'
import { Injector, NgModule } from '@angular/core'
import { PATCH_SOURCE, sourceFactory } from './patch-db.factory'
// This module is purely for providers organization purposes
@NgModule({
providers: [
{
provide: PATCH_SOURCE,
deps: [Injector],
useFactory: sourceFactory,
},
{
provide: PatchDB,
deps: [PATCH_SOURCE],
useClass: PatchDB,
},
],
})
export class PatchDbModule {}