address comments and more

This commit is contained in:
Matt Hill
2024-08-15 08:05:37 -06:00
parent a730543c76
commit 015131f198
24 changed files with 316 additions and 396 deletions

View File

@@ -3,12 +3,7 @@ import {
PackageDataEntry,
ServerStatusInfo,
} from 'src/app/services/patch-db/data-model'
import {
Metrics,
NotificationLevel,
RR,
ServerNotifications,
} from './api.types'
import { RR, ServerMetrics, ServerNotifications } from './api.types'
import { BTC_ICON, LND_ICON, PROXY_ICON, REGISTRY_ICON } from './api-icons'
import { Log } from '@start9labs/shared'
import { configBuilderToSpec } from 'src/app/utils/configBuilderToSpec'
@@ -748,7 +743,7 @@ export module Mock {
packageId: null,
createdAt: '2019-12-26T14:20:30.872Z',
code: 1,
level: NotificationLevel.Success,
level: 'success',
title: 'Backup Complete',
message: 'StartOS and services have been successfully backed up.',
data: {
@@ -769,7 +764,7 @@ export module Mock {
packageId: null,
createdAt: '2019-12-26T14:20:30.872Z',
code: 2,
level: NotificationLevel.Warning,
level: 'warning',
title: 'SSH Key Added',
message: 'A new SSH key was added. If you did not do this, shit is bad.',
data: null,
@@ -780,7 +775,7 @@ export module Mock {
packageId: null,
createdAt: '2019-12-26T14:20:30.872Z',
code: 3,
level: NotificationLevel.Info,
level: 'info',
title: 'SSH Key Removed',
message: 'A SSH key was removed.',
data: null,
@@ -791,7 +786,7 @@ export module Mock {
packageId: 'bitcoind',
createdAt: '2019-12-26T14:20:30.872Z',
code: 4,
level: NotificationLevel.Error,
level: 'error',
title: 'Service Crashed',
message: new Array(3)
.fill(
@@ -806,7 +801,7 @@ export module Mock {
},
]
export function getMetrics(): Metrics {
export function getMetrics(): ServerMetrics {
return {
general: {
temperature: {
@@ -1020,8 +1015,16 @@ export module Mock {
path: '/Desktop/embassy-backups',
username: 'TestUser',
mountable: false,
// @TODO Matt Provide mock for startOs
startOs: {},
startOs: {
abcdefgh: {
hostname: 'adjective-noun.local',
version: '0.3.6',
timestamp: new Date().toISOString(),
passwordHash:
'$argon2d$v=19$m=1024,t=1,p=1$YXNkZmFzZGZhc2RmYXNkZg$Ceev1I901G6UwU+hY0sHrFZ56D+o+LNJ',
wrappedKey: '',
},
},
},
{
id: 'ftcvewdnkemfksdm',
@@ -1054,8 +1057,16 @@ export module Mock {
vendor: 'SSK',
mountable: true,
path: '/HomeFolder/Documents',
// @TODO Matt Provide mock for startOs
startOs: {},
startOs: {
'different-server': {
hostname: 'different-server.local',
version: '0.3.6',
timestamp: new Date().toISOString(),
passwordHash:
'$argon2d$v=19$m=1024,t=1,p=1$YXNkZmFzZGZhc2RmYXNkZg$Ceev1I901G6UwU+hY0sHrFZ56D+o+LNJ',
wrappedKey: '',
},
},
},
],
}

View File

@@ -61,7 +61,7 @@ export module RR {
// init
export type InitGetProgressRes = {
export type InitFollowProgressRes = {
progress: T.FullProgress
guid: string
}
@@ -88,10 +88,10 @@ export module RR {
guid: string
}
export type GetServerMetricsReq = {} // server.metrics
export type GetServerMetricsRes = {
export type FollowServerMetricsReq = {} // server.metrics.follow
export type FollowServerMetricsRes = {
guid: string
metrics: Metrics
metrics: ServerMetrics
}
export type UpdateServerReq = { registry: string } // server.update
@@ -339,9 +339,11 @@ export module RR {
export type FollowPackageLogsReq = FollowServerLogsReq & { id: string } // package.logs.follow
export type FollowPackageLogsRes = FollowServerLogsRes
export type GetPackageMetricsReq = { id: string } // package.metrics
// @TODO Matt create package metrics type
export type GetPackageMetricsRes = any
export type FollowPackageMetricsReq = { id: string } // package.metrics.follow
export type FollowPackageMetricsRes = {
guid: string
metrics: AppMetrics
}
export type InstallPackageReq = T.InstallParams
export type InstallPackageRes = null
@@ -415,25 +417,6 @@ export module RR {
} // package.proxy.set-outbound
export type SetServiceOutboundProxyRes = null
// marketplace
export type GetMarketplaceInfoReq = { serverId: string }
// @TODO Matt fix type
export type GetMarketplaceInfoRes = any
export type GetMarketplaceEosReq = { serverId: string }
// @TODO Matt fix type
export type GetMarketplaceEosRes = any
export type GetMarketplacePackagesReq = {
ids?: { id: string; version: string }[]
// iff !ids
category?: string
query?: string
page?: number
perPage?: number
}
// registry
/** these are returned in ASCENDING order. the newest available version will be the LAST in the object */
@@ -443,34 +426,34 @@ export module RR {
export type CheckOSUpdateRes = OSUpdate
}
export interface OSUpdate {
export type OSUpdate = {
version: string
headline: string
releaseNotes: { [version: string]: string }
}
export interface Breakages {
export type Breakages = {
[id: string]: TaggedDependencyError
}
export interface TaggedDependencyError {
export type TaggedDependencyError = {
dependency: string
error: DependencyError
}
export interface ActionResponse {
export type ActionResponse = {
message: string
value: string | null
copyable: boolean
qr: boolean
}
interface MetricData {
type MetricData = {
value: string
unit: string
}
export interface Metrics {
export type ServerMetrics = {
general: {
temperature: MetricData | null
}
@@ -498,14 +481,28 @@ export interface Metrics {
}
}
export interface Session {
export type AppMetrics = {
memory: {
percentageUsed: MetricData
used: MetricData
}
cpu: {
percentageUsed: MetricData
}
disk: {
percentageUsed: MetricData
used: MetricData
}
}
export type Session = {
loggedIn: string
lastActive: string
userAgent: string
metadata: SessionMetadata
}
export interface SessionMetadata {
export type SessionMetadata = {
platforms: PlatformType[]
}
@@ -565,7 +562,7 @@ export interface CloudBackupTarget extends BaseBackupTarget {
provider: 'dropbox' | 'google-drive'
}
export interface BackupRun {
export type BackupRun = {
id: string
startedAt: string
completedAt: string
@@ -574,7 +571,7 @@ export interface BackupRun {
report: BackupReport
}
export interface BackupJob {
export type BackupJob = {
id: string
name: string
target: BackupTarget
@@ -582,7 +579,7 @@ export interface BackupJob {
packageIds: string[]
}
export interface BackupInfo {
export type BackupInfo = {
version: string
timestamp: string
packageBackups: {
@@ -590,18 +587,18 @@ export interface BackupInfo {
}
}
export interface PackageBackupInfo {
export type PackageBackupInfo = {
title: string
version: string
osVersion: string
timestamp: string
}
export interface ServerSpecs {
export type ServerSpecs = {
[key: string]: string | number
}
export interface SSHKey {
export type SSHKey = {
createdAt: string
alg: string
hostname: string
@@ -610,32 +607,25 @@ export interface SSHKey {
export type ServerNotifications = ServerNotification<number>[]
export interface ServerNotification<T extends number> {
export type ServerNotification<T extends number> = {
id: number
packageId: string | null
createdAt: string
code: T
level: NotificationLevel
level: 'success' | 'info' | 'warning' | 'error'
title: string
message: string
data: NotificationData<T>
read: boolean
}
export enum NotificationLevel {
Success = 'success',
Info = 'info',
Warning = 'warning',
Error = 'error',
}
export type NotificationData<T> = T extends 0
? null
: T extends 1
? BackupReport
: any
export interface BackupReport {
export type BackupReport = {
server: {
attempted: boolean
error: string | null
@@ -647,7 +637,7 @@ export interface BackupReport {
}
}
export interface AvailableWifi {
export type AvailableWifi = {
ssid: string
strength: number
security: string[]
@@ -682,29 +672,29 @@ export type DependencyError =
| DependencyErrorHealthChecksFailed
| DependencyErrorTransitive
export interface DependencyErrorNotInstalled {
export type DependencyErrorNotInstalled = {
type: 'notInstalled'
}
export interface DependencyErrorNotRunning {
export type DependencyErrorNotRunning = {
type: 'notRunning'
}
export interface DependencyErrorIncorrectVersion {
export type DependencyErrorIncorrectVersion = {
type: 'incorrectVersion'
expected: string // version range
received: string // version
}
export interface DependencyErrorConfigUnsatisfied {
export type DependencyErrorConfigUnsatisfied = {
type: 'configUnsatisfied'
}
export interface DependencyErrorHealthChecksFailed {
export type DependencyErrorHealthChecksFailed = {
type: 'healthChecksFailed'
check: T.HealthCheckResult
}
export interface DependencyErrorTransitive {
export type DependencyErrorTransitive = {
type: 'transitive'
}

View File

@@ -3,11 +3,10 @@ import {
GetPackagesRes,
MarketplacePkg,
} from '@start9labs/marketplace'
import { Log, RPCOptions } from '@start9labs/shared'
import { RPCOptions } from '@start9labs/shared'
import { T } from '@start9labs/start-sdk'
import { Observable } from 'rxjs'
import { WebSocketSubjectConfig } from 'rxjs/webSocket'
import { BackupTargetType, Metrics, RR } from './api.types'
import { BackupTargetType, RR } from './api.types'
export abstract class ApiService {
// http
@@ -32,7 +31,7 @@ export abstract class ApiService {
abstract openWebsocket$<T>(
guid: string,
config: RR.WebsocketConfig<T>,
config?: RR.WebsocketConfig<T>,
): Observable<T>
// state
@@ -78,20 +77,13 @@ export abstract class ApiService {
// init
abstract initGetProgress(): Promise<RR.InitGetProgressRes>
abstract initFollowProgress(): Promise<RR.InitFollowProgressRes>
abstract initFollowLogs(
params: RR.FollowServerLogsReq,
): Promise<RR.FollowServerLogsRes>
// server
abstract openLogsWebsocket$(
config: WebSocketSubjectConfig<Log>,
): Observable<Log>
abstract openMetricsWebsocket$(
config: WebSocketSubjectConfig<Metrics>,
): Observable<Metrics>
abstract getSystemTime(
params: RR.GetSystemTimeReq,
@@ -119,9 +111,9 @@ export abstract class ApiService {
params: RR.FollowServerLogsReq,
): Promise<RR.FollowServerLogsRes>
abstract getServerMetrics(
params: RR.GetServerMetricsReq,
): Promise<RR.GetServerMetricsRes>
abstract followServerMetrics(
params: RR.FollowServerMetricsReq,
): Promise<RR.FollowServerMetricsRes>
abstract updateServer(url?: string): Promise<RR.UpdateServerRes>

View File

@@ -3,16 +3,15 @@ import {
HttpOptions,
HttpService,
isRpcError,
Log,
Method,
RpcError,
RPCOptions,
} from '@start9labs/shared'
import { PATCH_CACHE } from 'src/app/services/patch-db/patch-db-source'
import { ApiService } from './embassy-api.service'
import { BackupTargetType, Metrics, RR } from './api.types'
import { BackupTargetType, RR } from './api.types'
import { ConfigService } from '../config.service'
import { webSocket, WebSocketSubjectConfig } from 'rxjs/webSocket'
import { webSocket } from 'rxjs/webSocket'
import { Observable, filter, firstValueFrom } from 'rxjs'
import { AuthService } from '../auth.service'
import { DOCUMENT } from '@angular/common'
@@ -93,20 +92,10 @@ export class LiveApiService extends ApiService {
}
// websocket
// @TODO Matt which of these 2 APIs should we use?
private openWebsocket<T>(config: WebSocketSubjectConfig<T>): Observable<T> {
const { location } = this.document.defaultView!
const protocol = location.protocol === 'http:' ? 'ws' : 'wss'
const host = location.host
config.url = `${protocol}://${host}/ws${config.url}`
return webSocket(config)
}
openWebsocket$<T>(
guid: string,
config: RR.WebsocketConfig<T>,
config: RR.WebsocketConfig<T> = {},
): Observable<T> {
const { location } = this.document.defaultView!
const protocol = location.protocol === 'http:' ? 'ws' : 'wss'
@@ -210,7 +199,7 @@ export class LiveApiService extends ApiService {
// init
async initGetProgress(): Promise<RR.InitGetProgressRes> {
async initFollowProgress(): Promise<RR.InitFollowProgressRes> {
return this.rpcRequest({ method: 'init.subscribe', params: {} })
}
@@ -221,15 +210,6 @@ export class LiveApiService extends ApiService {
}
// server
openLogsWebsocket$(config: WebSocketSubjectConfig<Log>): Observable<Log> {
return this.openWebsocket(config)
}
openMetricsWebsocket$(
config: WebSocketSubjectConfig<Metrics>,
): Observable<Metrics> {
return this.openWebsocket(config)
}
async getSystemTime(
params: RR.GetSystemTimeReq,
@@ -271,9 +251,9 @@ export class LiveApiService extends ApiService {
return this.rpcRequest({ method: 'net.tor.logs.follow', params })
}
async getServerMetrics(
params: RR.GetServerMetricsReq,
): Promise<RR.GetServerMetricsRes> {
async followServerMetrics(
params: RR.FollowServerMetricsReq,
): Promise<RR.FollowServerMetricsRes> {
return this.rpcRequest({ method: 'server.metrics', params })
}

View File

@@ -15,7 +15,7 @@ import {
StateInfo,
UpdatingState,
} from 'src/app/services/patch-db/data-model'
import { BackupTargetType, Metrics, RR } from './api.types'
import { BackupTargetType, RR } from './api.types'
import { Mock } from './api.fixures'
import {
from,
@@ -35,7 +35,6 @@ import {
GetPackagesRes,
MarketplacePkg,
} from '@start9labs/marketplace'
import { WebSocketSubjectConfig } from 'rxjs/webSocket'
import markdown from 'raw-loader!../../../../../shared/assets/markdown/md-sample.md'
const PROGRESS: T.FullProgress = {
@@ -84,8 +83,8 @@ export class MockApiService extends ApiService {
async uploadPackage(guid: string, body: Blob): Promise<string> {
await pauseFor(2000)
// @TODO Matt what should this return?
return ''
// @TODO Aiden confirm this is correct
return 'success'
}
async uploadFile(body: Blob): Promise<string> {
@@ -258,7 +257,7 @@ export class MockApiService extends ApiService {
// init
async initGetProgress(): Promise<RR.InitGetProgressRes> {
async initFollowProgress(): Promise<RR.InitFollowProgressRes> {
await pauseFor(250)
return {
progress: PROGRESS,
@@ -276,30 +275,6 @@ export class MockApiService extends ApiService {
// server
openLogsWebsocket$(config: WebSocketSubjectConfig<Log>): Observable<Log> {
return interval(50).pipe(
map((_, index) => {
// mock fire open observer
if (index === 0) config.openObserver?.next(new Event(''))
if (index === 100) throw new Error('HAAHHA')
return Mock.ServerLogs[0]
}),
)
}
openMetricsWebsocket$(
config: WebSocketSubjectConfig<Metrics>,
): Observable<Metrics> {
return interval(2000).pipe(
map((_, index) => {
// mock fire open observer
if (index === 0) config.openObserver?.next(new Event(''))
if (index === 4) throw new Error('HAHAHA')
return Mock.getMetrics()
}),
)
}
async getSystemTime(
params: RR.GetSystemTimeReq,
): Promise<RR.GetSystemTimeRes> {
@@ -386,9 +361,9 @@ export class MockApiService extends ApiService {
return logs
}
async getServerMetrics(
params: RR.GetServerMetricsReq,
): Promise<RR.GetServerMetricsRes> {
async followServerMetrics(
params: RR.FollowServerMetricsReq,
): Promise<RR.FollowServerMetricsRes> {
await pauseFor(2000)
return {
guid: 'iqudh37um-i38u3-34-a51b-jkhd783ein',

View File

@@ -130,8 +130,7 @@ export const mockPatchData: DataModel = {
password: '',
},
platform: 'x86_64-nonfree',
// @TODO Matt zram needs to be added?
// zram: true,
zram: true,
governor: 'performance',
passwordHash:
'$argon2d$v=19$m=1024,t=1,p=1$YXNkZmFzZGZhc2RmYXNkZg$Ceev1I901G6UwU+hY0sHrFZ56D+o+LNJ',

View File

@@ -2,7 +2,6 @@ import { inject, Injectable } from '@angular/core'
import { ErrorService } from '@start9labs/shared'
import { TuiDialogService } from '@taiga-ui/core'
import {
NotificationLevel,
ServerNotification,
ServerNotifications,
} from 'src/app/services/api/api.types'
@@ -63,13 +62,13 @@ export class NotificationService {
getColor(notification: ServerNotification<number>): string {
switch (notification.level) {
case NotificationLevel.Info:
case 'info':
return 'var(--tui-status-info)'
case NotificationLevel.Success:
case 'success':
return 'var(--tui-status-positive)'
case NotificationLevel.Warning:
case 'warning':
return 'var(--tui-status-warning)'
case NotificationLevel.Error:
case 'error':
return 'var(--tui-status-negative)'
default:
return ''
@@ -78,12 +77,12 @@ export class NotificationService {
getIcon(notification: ServerNotification<number>): string {
switch (notification.level) {
case NotificationLevel.Info:
case 'info':
return '@tui.info'
case NotificationLevel.Success:
case 'success':
return '@tui.circle-check'
case NotificationLevel.Warning:
case NotificationLevel.Error:
case 'warning':
case 'error':
return '@tui.circle-alert'
default:
return ''

View File

@@ -56,6 +56,7 @@ export type ServerInfo = {
platform: string
arch: string
governor: string | null
zram: boolean
}
export type NetworkInfo = {