From 7013364ae8e4225a1ff2b1bada5f50d47c813b6d Mon Sep 17 00:00:00 2001 From: Matt Hill Date: Fri, 18 Jun 2021 15:54:45 -0600 Subject: [PATCH] update readme, fix startup sequence, integrate live backend --- ui/README.md | 48 +++++++++++++++- ui/src/app/app.component.html | 5 +- .../install-wizard/prebaked-wizards.ts | 6 +- .../patch-db/local-storage-bootstrap.ts | 15 +---- .../models/patch-db/patch-db-model.factory.ts | 4 +- ui/src/app/models/patch-db/patch-db-model.ts | 56 +++++++++++-------- .../apps-routes/app-config/app-config.page.ts | 4 +- .../app-installed-list.page.html | 4 +- .../app-installed-list.page.ts | 1 + .../app-installed-show.page.ts | 6 +- ui/src/app/services/api/api-types.ts | 15 ++--- ui/src/app/services/api/api.service.ts | 10 ++-- ui/src/app/services/api/mock-api.service.ts | 20 ++----- ui/src/app/services/config.service.ts | 2 - ui/ui-config.json | 1 - 15 files changed, 111 insertions(+), 86 deletions(-) diff --git a/ui/README.md b/ui/README.md index 8aa3c45c8..834d9b4bc 100644 --- a/ui/README.md +++ b/ui/README.md @@ -2,14 +2,58 @@ ## Setup Instructions -**Make sure you have git, node, and npm installed** +**Make sure you have git, node, npm, and rust installed** `npm i -g @ionic/cli` +`git clone https://github.com/Start9Labs/patch-db.git` + +`git clone https://github.com/Start9Labs/ws-example.git` + `git clone https://github.com/Start9Labs/embassy-os.git` -`cd embassy-os/ui` +`git clone https://github.com/Start9Labs/rpc-toolkit.git` + +`git clone https://github.com/dr-bonez/yajrc` + +Then open `patch-db`, `ws-example`, and `embassy-os`, in separate tabs. + +### patch-db + +**Sync submodules** + +`git submodule update --init --recursive` + +### ws-example + +**Start the server** + +`cargo run -- -vvv -c example-config.toml` + +### embassy-os + +`cd ui/` `npm i` +In `ui-config.json`, edit the "mocks" section to look like the following: + +``` +"mocks": { + "enabled": true, + "connection": "ws", + "rpcPort": "5959", + "wsPort": "5960", + "maskAs": "tor", + "skipStartupAlerts": true +} +``` +Valid values for "connection" are `ws` and `poll`. + +Valid values for "maskAs" are `tor` and `lan`. + +You can also enable or disable startup alerts. + +**Start the client** + `ionic serve` diff --git a/ui/src/app/app.component.html b/ui/src/app/app.component.html index 5eee4fa14..34a3c379c 100644 --- a/ui/src/app/app.component.html +++ b/ui/src/app/app.component.html @@ -1,8 +1,5 @@ - - - - + diff --git a/ui/src/app/components/install-wizard/prebaked-wizards.ts b/ui/src/app/components/install-wizard/prebaked-wizards.ts index ca63b0ff9..2eb3a3e60 100644 --- a/ui/src/app/components/install-wizard/prebaked-wizards.ts +++ b/ui/src/app/components/install-wizard/prebaked-wizards.ts @@ -92,7 +92,7 @@ export class WizardBaker { action, verb: 'updating', title, - fetchBreakages: () => this.apiService.dryUpdatePackage({ id, version }).then( ({ breakages }) => breakages ), + fetchBreakages: () => this.apiService.dryUpdatePackage({ id, version }).then(breakages => breakages), }, }, bottomBar: { @@ -192,7 +192,7 @@ export class WizardBaker { action, verb: 'downgrading', title, - fetchBreakages: () => this.apiService.dryUpdatePackage({ id, version }).then( ({ breakages }) => breakages ), + fetchBreakages: () => this.apiService.dryUpdatePackage({ id, version }).then(breakages => breakages), }, }, bottomBar: { @@ -248,7 +248,7 @@ export class WizardBaker { action, verb: 'uninstalling', title, - fetchBreakages: () => this.apiService.dryRemovePackage({ id }).then( ({ breakages }) => breakages ), + fetchBreakages: () => this.apiService.dryRemovePackage({ id }).then(breakages => breakages ), }, }, bottomBar: { cancel: { whileLoading: { }, afterLoading: { text: 'Cancel' } }, next: 'Uninstall' }, diff --git a/ui/src/app/models/patch-db/local-storage-bootstrap.ts b/ui/src/app/models/patch-db/local-storage-bootstrap.ts index 8f0f4ac40..5cddf1a86 100644 --- a/ui/src/app/models/patch-db/local-storage-bootstrap.ts +++ b/ui/src/app/models/patch-db/local-storage-bootstrap.ts @@ -2,7 +2,6 @@ import { Bootstrapper, DBCache } from 'patch-db-client' import { DataModel } from './data-model' import { Injectable } from '@angular/core' import { Storage } from '@ionic/storage' -import { ApiService } from 'src/app/services/api/api.service' @Injectable({ providedIn: 'root', @@ -12,22 +11,14 @@ export class LocalStorageBootstrap implements Bootstrapper { constructor ( private readonly storage: Storage, - private readonly apiService: ApiService, ) { } async init (): Promise> { - let cache = await this.storage.get(LocalStorageBootstrap.CONTENT_KEY) as DBCache - if (!cache || cache.sequence === 0) { - console.log('No cached data, getting dump from server') - const { id, value } = await this.apiService.getDump() - cache.sequence = id - cache.data = value - await this.update(cache) - } - return cache + const cache: DBCache = await this.storage.get(LocalStorageBootstrap.CONTENT_KEY) + return cache || { sequence: 0, data: { } } } async update (cache: DBCache): Promise { - return this.storage.set(LocalStorageBootstrap.CONTENT_KEY, cache) + await this.storage.set(LocalStorageBootstrap.CONTENT_KEY, cache) } } diff --git a/ui/src/app/models/patch-db/patch-db-model.factory.ts b/ui/src/app/models/patch-db/patch-db-model.factory.ts index c24a166f4..949392f93 100644 --- a/ui/src/app/models/patch-db/patch-db-model.factory.ts +++ b/ui/src/app/models/patch-db/patch-db-model.factory.ts @@ -11,7 +11,7 @@ export function PatchDbModelFactory ( http: ApiService, ): PatchDbModel { - const { mocks, patchDb: { poll, timeoutForMissingRevision }, isConsulate } = config + const { mocks, patchDb: { poll }, isConsulate } = config let source: Source @@ -31,5 +31,5 @@ export function PatchDbModelFactory ( } } - return new PatchDbModel({ sources: [source, http], bootstrapper, http, timeoutForMissingRevision }) + return new PatchDbModel(bootstrapper, source) } \ No newline at end of file diff --git a/ui/src/app/models/patch-db/patch-db-model.ts b/ui/src/app/models/patch-db/patch-db-model.ts index f94967f07..317010661 100644 --- a/ui/src/app/models/patch-db/patch-db-model.ts +++ b/ui/src/app/models/patch-db/patch-db-model.ts @@ -1,49 +1,61 @@ import { Inject, Injectable, InjectionToken } from '@angular/core' -import { PatchDB, PatchDbConfig, Store } from 'patch-db-client' +import { Bootstrapper, PatchDB, Source, Store } from 'patch-db-client' import { Observable, of, Subscription } from 'rxjs' -import { catchError, finalize } from 'rxjs/operators' +import { catchError, debounceTime } from 'rxjs/operators' import { DataModel } from './data-model' -export const PATCH_CONFIG = new InjectionToken>('app.config') +export const BOOTSTRAPPER = new InjectionToken>('app.config') +export const PATCH_SOURCE = new InjectionToken>('app.config') @Injectable({ providedIn: 'root', }) export class PatchDbModel { - private patchDb: PatchDB - private syncSub: Subscription - initialized = false + patchDb: PatchDB + private patchSub: Subscription constructor ( - @Inject(PATCH_CONFIG) private readonly conf: PatchDbConfig, + @Inject(BOOTSTRAPPER) private readonly bootstrapper: Bootstrapper, + @Inject(PATCH_SOURCE) private readonly source: Source, ) { } async init (): Promise { - if (this.patchDb) return console.warn('Cannot re-init patchDbModel') + const cache = await this.bootstrapper.init() + this.patchDb = new PatchDB(this.source, cache) + } + + start (): void { + // make sure everything is stopped before initializing + this.stop() try { - this.patchDb = await PatchDB.init(this.conf) - this.initialized = true + this.patchSub = this.patchDb.sync$() + .pipe(debounceTime(500)) + .subscribe({ + next: cache => { + console.log('saving cache: ', cache.sequence) + this.bootstrapper.update(cache) + }, + error: e => { + console.error('Critical, patch-db-sync sub error', e) + this.start() + }, + complete: () => { + console.error('Critical, patch-db-sync sub complete') + }, + }) } catch (e) { console.log('Failed to initialize PatchDB', e) } } - start (): void { - if (this.syncSub) this.stop() - this.syncSub = this.patchDb.sync$().subscribe({ - error: e => console.error('Critical, patch-db-sync sub error', e), - complete: () => console.error('Critical, patch-db-sync sub complete'), - }) - } - stop (): void { - if (this.syncSub) { - this.syncSub.unsubscribe() - this.syncSub = undefined + if (this.patchSub) { + this.patchSub.unsubscribe() + this.patchSub = undefined } } - watch$: Store['watch$'] = (...args: (string | number)[]): Observable => { + watch$: Store < DataModel > ['watch$'] = (...args: (string | number)[]): Observable => { // console.log('WATCHING') return this.patchDb.store.watch$(...(args as [])).pipe( catchError(e => { diff --git a/ui/src/app/pages/apps-routes/app-config/app-config.page.ts b/ui/src/app/pages/apps-routes/app-config/app-config.page.ts index ebcaab3eb..05f7a68da 100644 --- a/ui/src/app/pages/apps-routes/app-config/app-config.page.ts +++ b/ui/src/app/pages/apps-routes/app-config/app-config.page.ts @@ -183,9 +183,9 @@ export class AppConfigPage { spinner: 'lines', cssClass: 'loader', }).displayDuringAsync(async () => { - const { breakages } = await this.apiService.drySetPackageConfig({ id: pkg.manifest.id, config: this.config }) + const breakages = await this.apiService.drySetPackageConfig({ id: pkg.manifest.id, config: this.config }) - if (breakages.length) { + if (!isEmptyObject(breakages.length)) { const { cancelled } = await wizardModal( this.modalController, this.wizardBaker.configure({ diff --git a/ui/src/app/pages/apps-routes/app-installed-list/app-installed-list.page.html b/ui/src/app/pages/apps-routes/app-installed-list/app-installed-list.page.html index 5ff999afc..db9619b7e 100644 --- a/ui/src/app/pages/apps-routes/app-installed-list/app-installed-list.page.html +++ b/ui/src/app/pages/apps-routes/app-installed-list/app-installed-list.page.html @@ -8,7 +8,7 @@ - +
@@ -23,7 +23,7 @@ - +
diff --git a/ui/src/app/pages/apps-routes/app-installed-list/app-installed-list.page.ts b/ui/src/app/pages/apps-routes/app-installed-list/app-installed-list.page.ts index 991e3740c..0c9261512 100644 --- a/ui/src/app/pages/apps-routes/app-installed-list/app-installed-list.page.ts +++ b/ui/src/app/pages/apps-routes/app-installed-list/app-installed-list.page.ts @@ -10,6 +10,7 @@ import { PackageDataEntry } from 'src/app/models/patch-db/data-model' styleUrls: ['./app-installed-list.page.scss'], }) export class AppInstalledListPage { + pkgs: PackageDataEntry[] = [] constructor ( private readonly config: ConfigService, diff --git a/ui/src/app/pages/apps-routes/app-installed-show/app-installed-show.page.ts b/ui/src/app/pages/apps-routes/app-installed-show/app-installed-show.page.ts index 554e9e12d..5eb140294 100644 --- a/ui/src/app/pages/apps-routes/app-installed-show/app-installed-show.page.ts +++ b/ui/src/app/pages/apps-routes/app-installed-show/app-installed-show.page.ts @@ -2,7 +2,7 @@ import { Component, ViewChild } from '@angular/core' import { AlertController, NavController, ModalController, IonContent, PopoverController } from '@ionic/angular' import { ApiService } from 'src/app/services/api/api.service' import { ActivatedRoute, NavigationExtras } from '@angular/router' -import { chill, pauseFor } from 'src/app/util/misc.util' +import { chill, isEmptyObject, pauseFor } from 'src/app/util/misc.util' import { LoaderService } from 'src/app/services/loader.service' import { Observable, of, Subscription } from 'rxjs' import { wizardModal } from 'src/app/components/install-wizard/install-wizard.component' @@ -73,9 +73,9 @@ export class AppInstalledShowPage { spinner: 'lines', cssClass: 'loader', }).displayDuringAsync(async () => { - const { breakages } = await this.apiService.dryStopPackage({ id }) + const breakages = await this.apiService.dryStopPackage({ id }) - if (breakages.length) { + if (isEmptyObject(breakages.length)) { const { cancelled } = await wizardModal( this.modalCtrl, this.wizardBaker.stop({ diff --git a/ui/src/app/services/api/api-types.ts b/ui/src/app/services/api/api-types.ts index 440919c85..65d8f13df 100644 --- a/ui/src/app/services/api/api-types.ts +++ b/ui/src/app/services/api/api-types.ts @@ -1,4 +1,4 @@ -import { Dump, Operation, Revision } from 'patch-db-client' +import { Dump, Revision } from 'patch-db-client' import { PackagePropertiesVersioned } from 'src/app/util/properties.util' import { ConfigSpec } from 'src/app/pkg-config/config-types' import { DataModel, DependencyError, Manifest, URL } from 'src/app/models/patch-db/data-model' @@ -113,13 +113,13 @@ export module RR { export type InstallPackageRes = WithRevision export type DryUpdatePackageReq = { id: string, version: string } // package.update.dry - export type DryUpdatePackageRes = BreakageRes + export type DryUpdatePackageRes = Breakages export type GetPackageConfigReq = { id: string } // package.config.get export type GetPackageConfigRes = { spec: ConfigSpec, config: object } export type DrySetPackageConfigReq = { id: string, config: object } // package.config.set.dry - export type DrySetPackageConfigRes = BreakageRes + export type DrySetPackageConfigRes = Breakages export type SetPackageConfigReq = WithExpire // package.config.set export type SetPackageConfigRes = WithRevision @@ -134,13 +134,13 @@ export module RR { export type StartPackageRes = WithRevision export type DryStopPackageReq = StopPackageReq // package.stop.dry - export type DryStopPackageRes = BreakageRes + export type DryStopPackageRes = Breakages export type StopPackageReq = WithExpire<{ id: string }> // package.stop export type StopPackageRes = WithRevision export type DryRemovePackageReq = RemovePackageReq // package.remove.dry - export type DryRemovePackageRes = BreakageRes + export type DryRemovePackageRes = Breakages export type RemovePackageReq = WithExpire<{ id: string }> // package.remove export type RemovePackageRes = WithRevision @@ -198,11 +198,6 @@ export interface AvailableShow { } } -export interface BreakageRes { - patch: Operation[], - breakages: Breakages -} - export interface Breakages { [id: string]: TaggedDependencyError } diff --git a/ui/src/app/services/api/api.service.ts b/ui/src/app/services/api/api.service.ts index c017afae7..c63484ff3 100644 --- a/ui/src/app/services/api/api.service.ts +++ b/ui/src/app/services/api/api.service.ts @@ -178,11 +178,11 @@ export abstract class ApiService implements Source, Http { // state change you'd like to enact prior to request and expired when request terminates. private syncResponse Promise<{ response: T, revision?: Revision }>> (f: F, temp?: Operation): (...args: Parameters) => Promise { return (...a) => { - let expireId = undefined - if (temp) { - expireId = uuid.v4() - this.sync.next({ patch: [temp], expiredBy: expireId }) - } + // let expireId = undefined + // if (temp) { + // expireId = uuid.v4() + // this.sync.next({ patch: [temp], expiredBy: expireId }) + // } return f(a).then(({ response, revision }) => { if (revision) this.sync.next(revision) diff --git a/ui/src/app/services/api/mock-api.service.ts b/ui/src/app/services/api/mock-api.service.ts index 4c3e788c6..faa471e86 100644 --- a/ui/src/app/services/api/mock-api.service.ts +++ b/ui/src/app/services/api/mock-api.service.ts @@ -331,10 +331,7 @@ export class MockApiService extends ApiService { async dryUpdatePackage (params: RR.DryUpdatePackageReq): Promise { await pauseFor(2000) - return { - patch: [], - breakages: { }, - } + return { } } async getPackageConfig (params: RR.GetPackageConfigReq): Promise { @@ -344,10 +341,7 @@ export class MockApiService extends ApiService { async drySetPackageConfig (params: RR.DrySetPackageConfigReq): Promise { await pauseFor(2000) - return { - patch: [], - breakages: { }, - } + return { } } async setPackageConfigRaw (params: RR.SetPackageConfigReq): Promise { @@ -421,10 +415,7 @@ export class MockApiService extends ApiService { async dryStopPackage (params: RR.DryStopPackageReq): Promise { await pauseFor(2000) - return { - patch: [], - breakages: { }, - } + return { } } async stopPackageRaw (params: RR.StopPackageReq): Promise { @@ -447,10 +438,7 @@ export class MockApiService extends ApiService { async dryRemovePackage (params: RR.DryRemovePackageReq): Promise { await pauseFor(2000) - return { - patch: [], - breakages: { }, - } + return { } } async removePackageRaw (params: RR.RemovePackageReq): Promise { diff --git a/ui/src/app/services/config.service.ts b/ui/src/app/services/config.service.ts index 2808c5da2..ba0817e73 100644 --- a/ui/src/app/services/config.service.ts +++ b/ui/src/app/services/config.service.ts @@ -8,8 +8,6 @@ type UiConfig = { poll: { cooldown: number /* in ms */ } - // Wait this long (ms) before asking BE for a dump when out of order messages are received - timeoutForMissingRevision: number } api: { url: string diff --git a/ui/ui-config.json b/ui/ui-config.json index ceab7143b..7f06abd3a 100644 --- a/ui/ui-config.json +++ b/ui/ui-config.json @@ -1,6 +1,5 @@ { "patchDb": { - "timeoutForMissingRevision": 5000, "poll": { "cooldown": 10000 }