refine startup alerts, reversions in mocks

This commit is contained in:
Matt Hill
2021-07-16 17:58:53 -06:00
committed by Aiden McClelland
parent 8cfd98bbd0
commit e8bf254b91
18 changed files with 473 additions and 314 deletions

4
ui/package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "embassy-ui", "name": "embassy-ui",
"version": "0.2.14", "version": "0.3.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "embassy-ui", "name": "embassy-ui",
"version": "0.2.14", "version": "0.3.0",
"dependencies": { "dependencies": {
"@angular/common": "^11.0.0", "@angular/common": "^11.0.0",
"@angular/core": "^11.0.0", "@angular/core": "^11.0.0",

View File

@@ -1,6 +1,6 @@
{ {
"name": "embassy-ui", "name": "embassy-ui",
"version": "0.2.14", "version": "0.3.0",
"description": "GUI for EmbassyOS", "description": "GUI for EmbassyOS",
"author": "Start9 Labs", "author": "Start9 Labs",
"homepage": "https://github.com/Start9Labs/embassy-ui", "homepage": "https://github.com/Start9Labs/embassy-ui",

View File

@@ -3,7 +3,7 @@ import { Storage } from '@ionic/storage'
import { AuthService, AuthState } from './services/auth.service' import { AuthService, AuthState } from './services/auth.service'
import { ApiService } from './services/api/embassy/embassy-api.service' import { ApiService } from './services/api/embassy/embassy-api.service'
import { Router, RoutesRecognized } from '@angular/router' import { Router, RoutesRecognized } from '@angular/router'
import { debounceTime, distinctUntilChanged, filter, finalize, takeWhile } from 'rxjs/operators' import { debounceTime, distinctUntilChanged, filter, finalize, skip, take, takeWhile } from 'rxjs/operators'
import { AlertController, IonicSafeString, ToastController } from '@ionic/angular' import { AlertController, IonicSafeString, ToastController } from '@ionic/angular'
import { LoaderService } from './services/loader.service' import { LoaderService } from './services/loader.service'
import { Emver } from './services/emver.service' import { Emver } from './services/emver.service'
@@ -14,6 +14,8 @@ import { HttpService } from './services/http.service'
import { ServerStatus } from './services/patch-db/data-model' import { ServerStatus } from './services/patch-db/data-model'
import { ConnectionFailure, ConnectionService } from './services/connection.service' import { ConnectionFailure, ConnectionService } from './services/connection.service'
import { StartupAlertsService } from './services/startup-alerts.service' import { StartupAlertsService } from './services/startup-alerts.service'
import { ConfigService } from './services/config.service'
import { isEmptyObject } from './util/misc.util'
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
@@ -63,6 +65,7 @@ export class AppComponent {
private readonly startupAlertsService: StartupAlertsService, private readonly startupAlertsService: StartupAlertsService,
private readonly toastCtrl: ToastController, private readonly toastCtrl: ToastController,
private readonly patch: PatchDbService, private readonly patch: PatchDbService,
private readonly config: ConfigService,
readonly splitPane: SplitPaneTracker, readonly splitPane: SplitPaneTracker,
) { ) {
// set dark theme // set dark theme
@@ -83,23 +86,33 @@ export class AppComponent {
.subscribe(auth => { .subscribe(auth => {
// VERIFIED // VERIFIED
if (auth === AuthState.VERIFIED) { if (auth === AuthState.VERIFIED) {
this.http.authReqEnabled = true
this.showMenu = true
this.patch.start() this.patch.start()
this.connectionService.start()
// watch connection to display connectivity issues this.patch.watch$()
this.watchConnection(auth) .pipe(
// watch router to highlight selected menu item filter(data => !isEmptyObject(data)),
this.watchRouter(auth) take(1),
// watch status to display/hide maintenance page )
this.watchStatus(auth) .subscribe(_ => {
// watch unread notification count to display toast this.showMenu = true
this.watchNotifications(auth) this.router.navigate([''], { replaceUrl: true })
// run startup alerts this.connectionService.start()
this.startupAlertsService.runChecks() // watch connection to display connectivity issues
this.watchConnection(auth)
// watch router to highlight selected menu item
this.watchRouter(auth)
// watch status to display/hide maintenance page
this.watchStatus(auth)
// watch version to refresh browser window
this.watchVersion(auth)
// watch unread notification count to display toast
this.watchNotifications(auth)
// run startup alerts
this.startupAlertsService.runChecks()
})
// UNVERIFIED // UNVERIFIED
} else if (auth === AuthState.UNVERIFIED) { } else if (auth === AuthState.UNVERIFIED) {
this.http.authReqEnabled = false
this.showMenu = false this.showMenu = false
this.connectionService.stop() this.connectionService.stop()
this.patch.stop() this.patch.stop()
@@ -178,16 +191,30 @@ export class AppComponent {
) )
.subscribe(status => { .subscribe(status => {
const maintenance = '/maintenance' const maintenance = '/maintenance'
const url = this.router.url const route = this.router.url
if (status === ServerStatus.Running && url.startsWith(maintenance)) { console.log('STATUS', status, 'URL', route)
if (status === ServerStatus.Running && route.startsWith(maintenance)) {
this.router.navigate([''], { replaceUrl: true }) this.router.navigate([''], { replaceUrl: true })
} }
if ([ServerStatus.Updating, ServerStatus.BackingUp].includes(status) && !url.startsWith(maintenance)) { if ([ServerStatus.Updating, ServerStatus.BackingUp].includes(status) && !route.startsWith(maintenance)) {
this.showMenu = false
this.router.navigate([maintenance], { replaceUrl: true }) this.router.navigate([maintenance], { replaceUrl: true })
} }
}) })
} }
private watchVersion (auth: AuthState): void {
this.patch.watch$('server-info', 'version')
.pipe(
takeWhile(() => auth === AuthState.VERIFIED),
)
.subscribe(version => {
if (this.emver.compare(this.config.version, version) !== 0) {
this.presentAlertRefreshNeeded()
}
})
}
private watchNotifications (auth: AuthState): void { private watchNotifications (auth: AuthState): void {
let previous: number let previous: number
this.patch.watch$('server-info', 'unread-notification-count') this.patch.watch$('server-info', 'unread-notification-count')
@@ -202,7 +229,25 @@ export class AppComponent {
}) })
} }
async presentAlertRefreshNeeded () {
const alert = await this.alertCtrl.create({
backdropDismiss: false,
header: 'Refresh Needed',
message: 'Your EmbassyOS UI is out of date. Hard refresh the page to get the latest UI.',
buttons: [
{
text: 'Refresh Page',
handler: () => {
location.reload()
},
},
],
})
await alert.present()
}
async presentAlertLogout () { async presentAlertLogout () {
// @TODO warn user no way to recover Embassy if logout and forget password. Maybe require password to logout?
const alert = await this.alertCtrl.create({ const alert = await this.alertCtrl.create({
backdropDismiss: false, backdropDismiss: false,
header: 'Caution', header: 'Caution',

View File

@@ -1,6 +1,5 @@
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { CanActivate, Router, CanActivateChild } from '@angular/router' import { CanActivate, Router, CanActivateChild } from '@angular/router'
import { tap } from 'rxjs/operators'
import { ServerStatus } from '../services/patch-db/data-model' import { ServerStatus } from '../services/patch-db/data-model'
import { PatchDbService } from '../services/patch-db/patch-db.service' import { PatchDbService } from '../services/patch-db/patch-db.service'

View File

@@ -14,8 +14,8 @@ export class UnmaintenanceGuard implements CanActivate {
private readonly router: Router, private readonly router: Router,
private readonly patch: PatchDbService, private readonly patch: PatchDbService,
) { ) {
this.patch.sequence$.subscribe(_ => { this.patch.watch$('server-info', 'status').subscribe(status => {
this.serverStatus = this.patch.data['server-info'].status this.serverStatus = status
}) })
} }

View File

@@ -1,7 +1,7 @@
<ion-header> <ion-header>
<ion-toolbar> <ion-toolbar>
<ion-title > <ion-title >
<ion-label style="font-size: 20px;" class="ion-text-wrap">Welcome to 0.2.14!</ion-label> <ion-label style="font-size: 20px;" class="ion-text-wrap">Welcome to {{ version }}!</ion-label>
</ion-title> </ion-title>
</ion-toolbar> </ion-toolbar>
</ion-header> </ion-header>
@@ -14,7 +14,7 @@
</div> </div>
<div class="close-button"> <div class="close-button">
<ion-button fill="outline" (click)="dismiss()"> <ion-button fill="outline" color="dark" (click)="dismiss()">
Begin Begin
</ion-button> </ion-button>
</div> </div>

View File

@@ -1,7 +1,6 @@
import { Component } from '@angular/core' import { Component } from '@angular/core'
import { NavController } from '@ionic/angular' import { LoadingController } from '@ionic/angular'
import { AuthService } from 'src/app/services/auth.service' import { AuthService } from 'src/app/services/auth.service'
import { LoaderService } from 'src/app/services/loader.service'
@Component({ @Component({
selector: 'login', selector: 'login',
@@ -12,15 +11,18 @@ export class LoginPage {
password = '' password = ''
unmasked = false unmasked = false
error = '' error = ''
loader: HTMLIonLoadingElement
constructor ( constructor (
private readonly authService: AuthService, private readonly authService: AuthService,
private readonly loader: LoaderService, private readonly loadingCtrl: LoadingController,
private readonly navCtrl: NavController,
) { } ) { }
ionViewDidEnter () { ngOnDestroy () {
this.error = '' if (this.loader) {
this.loader.dismiss()
this.loader = undefined
}
} }
toggleMask () { toggleMask () {
@@ -28,14 +30,21 @@ export class LoginPage {
} }
async submit () { async submit () {
this.error = ''
this.loader = await this.loadingCtrl.create({
message: 'Authenticating',
spinner: 'lines',
})
await this.loader.present()
try { try {
await this.loader.displayDuringP( await this.authService.login(this.password)
this.authService.login(this.password), this.loader.message = 'Loading Embassy Data'
)
this.password = '' this.password = ''
await this.navCtrl.navigateForward(['/'])
} catch (e) { } catch (e) {
this.error = e.message this.error = e.message
this.loader.dismiss()
} }
} }
} }

View File

@@ -1,10 +1,10 @@
<ion-content *ngIf="patch.data['serverInfo'].status as status"> <ion-content *ngIf="patch.data['server-info'].status as status">
<ion-grid style="height: 100%;"> <ion-grid style="height: 100%;">
<ion-row class="ion-align-items-center ion-text-center" style="height: 100%;"> <ion-row class="ion-align-items-center ion-text-center" style="height: 100%;">
<ion-col> <ion-col>
<ion-spinner name="lines" color="warning"></ion-spinner> <ion-spinner name="lines" color="warning"></ion-spinner>
<p *ngIf="status === ServerStatus.Updating">Updating Embassy</p> <p *ngIf="status === ServerStatus.Updating">Embassy is updating</p>
<p *ngIf="status === ServerStatus.BackingUp">Embassy is backing up</p> <p *ngIf="status === ServerStatus.BackingUp">Embassy is backing up</p>
</ion-col> </ion-col>
</ion-row> </ion-row>

View File

@@ -1,12 +1,15 @@
import { DependencyErrorType, DockerIoFormat, Manifest, PackageDataEntry, PackageMainStatus, PackageState, ServerStatus } from 'src/app/services/patch-db/data-model' import { DockerIoFormat, Manifest, PackageDataEntry, PackageMainStatus, PackageState } from 'src/app/services/patch-db/data-model'
import { MarketplacePkg, Metric, NotificationLevel, RR, ServerNotification, ServerNotifications } from './api.types' import { MarketplacePkg, Metric, NotificationLevel, RR, ServerNotifications } from './api.types'
export module Mock { export module Mock {
export const MarketplaceEos: RR.GetMarketplaceEOSRes = { export const MarketplaceEos: RR.GetMarketplaceEOSRes = {
version: '1.0.0', version: '0.3.1',
headline: 'Our biggest release ever.', headline: 'Our biggest release ever.',
'release-notes': { '1.0.0': 'Some **Markdown** release _notes_' }, 'release-notes': {
'0.3.1': 'Some **Markdown** release _notes_ for 0.3.1',
'0.3.0': 'Some **Markdown** release _notes_ from a prior version',
},
} }
export const ReleaseNotes: RR.GetReleaseNotesRes = { export const ReleaseNotes: RR.GetReleaseNotesRes = {
@@ -375,7 +378,7 @@ export module Mock {
}, },
} }
export const AvailableShow: { export const MarketplacePkgs: {
[id: string]: { [id: string]: {
[version: string]: MarketplacePkg [version: string]: MarketplacePkg
} }
@@ -513,108 +516,7 @@ export module Mock {
}, },
} }
export const AvailableList: RR.GetMarketplacePackagesRes = Object.values(Mock.AvailableShow).map(service => service['latest']) export const MarketplacePkgsList: RR.GetMarketplacePackagesRes = Object.values(Mock.MarketplacePkgs).map(service => service['latest'])
export const bitcoind: PackageDataEntry = {
state: PackageState.Installed,
'static-files': {
license: 'licenseUrl', // /public/package-data/bitcoind/0.21.1/LICENSE.md,
icon: 'assets/img/service-icons/bitcoind.png',
instructions: 'instructionsUrl', // /public/package-data/bitcoind/0.21.1/INSTRUCTIONS.md
},
manifest: {
...MockManifestBitcoind,
version: '0.20.0',
},
installed: {
status: {
configured: true,
main: {
status: PackageMainStatus.Running,
started: new Date().toISOString(),
health: { },
},
'dependency-errors': { },
},
'interface-info': {
ip: '10.0.0.1',
addresses: {
ui: {
'tor-address': 'bitcoind-ui-address.onion',
'lan-address': 'bitcoind-ui-address.local',
},
rpc: {
'tor-address': 'bitcoind-rpc-address.onion',
'lan-address': 'bitcoind-rpc-address.local',
},
p2p: {
'tor-address': 'bitcoind-p2p-address.onion',
'lan-address': 'bitcoind-p2p-address.local',
},
},
},
'system-pointers': [],
'current-dependents': {
'lnd': {
pointers: [],
'health-checks': [],
},
},
'current-dependencies': { },
},
'install-progress': undefined,
}
export const lnd: PackageDataEntry = {
state: PackageState.Installed,
'static-files': {
license: 'licenseUrl', // /public/package-data/lnd/0.21.1/LICENSE.md,
icon: 'assets/img/service-icons/lnd.png',
instructions: 'instructionsUrl', // /public/package-data/lnd/0.21.1/INSTRUCTIONS.md
},
manifest: MockManifestLnd,
installed: {
status: {
configured: true,
main: {
status: PackageMainStatus.Stopped,
},
'dependency-errors': {
'bitcoin-proxy': {
type: DependencyErrorType.NotInstalled,
title: Mock.MockManifestBitcoinProxy.title,
icon: 'assets/img/service-icons/bitcoin-proxy.png',
},
},
},
'interface-info': {
ip: '10.0.0.1',
addresses: {
rpc: {
'tor-address': 'lnd-rpc-address.onion',
'lan-address': 'lnd-rpc-address.local',
},
grpc: {
'tor-address': 'lnd-grpc-address.onion',
'lan-address': 'lnd-grpc-address.local',
},
},
},
'system-pointers': [],
'current-dependents': { },
'current-dependencies': {
'bitcoind': {
pointers: [],
'health-checks': [],
},
'bitcoin-proxy': {
pointers: [],
'health-checks': [],
},
},
},
'install-progress': undefined,
}
export const bitcoinproxy: PackageDataEntry = { export const bitcoinproxy: PackageDataEntry = {
state: PackageState.Installed, state: PackageState.Installed,
@@ -660,68 +562,27 @@ export module Mock {
'install-progress': undefined, 'install-progress': undefined,
} }
export const DbDump: RR.GetDumpRes = { export const Notifications: ServerNotifications = [
id: 1, {
expireId: null, id: '123e4567-e89b-12d3-a456-426655440000',
value: { 'package-id': null,
'server-info': { 'created-at': '2019-12-26T14:20:30.872Z',
id: 'start9-abcdefgmm', code: 1,
version: '1.0.0', level: NotificationLevel.Success,
status: ServerStatus.Running, title: 'Backup Complete',
'lan-address': 'start9-abcdefgh.local', message: 'Embassy and services have been successfully backed up.',
'tor-address': 'myveryownspecialtoraddress.onion', data: {
wifi: { server: {
ssids: ['Goosers', 'Goosers5G'], attempted: true,
selected: 'Goosers5G',
connected: 'Goosers5G',
},
'package-marketplace': 'https://registry.start9.com',
'eos-marketplace': 'https://registry.start9.com',
'unread-notification-count': 4,
specs: {
CPU: 'Cortex-A72: 4 Cores @1500MHz',
Disk: '1TB SSD',
Memory: '8GB',
},
'connection-addresses': {
tor: [],
clearnet: [],
},
},
'package-data': {
'bitcoind': bitcoind,
'lnd': lnd,
},
ui: {
'welcome-ack': '1.0.0',
'auto-check-updates': true,
},
},
}
export const notification1: ServerNotification<1> = {
id: '123e4567-e89b-12d3-a456-426655440000',
'package-id': null,
'created-at': '2019-12-26T14:20:30.872Z',
code: 1,
level: NotificationLevel.Success,
title: 'Backup Complete',
message: 'Embassy and services have been successfully backed up.',
data: {
server: {
attempted: true,
error: null,
},
packages: {
'bitcoind': {
error: null, error: null,
}, },
packages: {
'bitcoind': {
error: null,
},
},
}, },
}, },
}
export const Notifications: ServerNotifications = [
notification1,
{ {
id: '123e4567-e89b-12d3-a456-426655440001', id: '123e4567-e89b-12d3-a456-426655440001',
'package-id': 'bitcoind', 'package-id': 'bitcoind',
@@ -1435,4 +1296,144 @@ export module Mock {
rpcallowip: [], rpcallowip: [],
rpcauth: ['matt: 8273gr8qwoidm1uid91jeh8y23gdio1kskmwejkdnm'], rpcauth: ['matt: 8273gr8qwoidm1uid91jeh8y23gdio1kskmwejkdnm'],
} }
// export const bitcoind: PackageDataEntry = {
// state: PackageState.Installed,
// 'static-files': {
// license: 'licenseUrl', // /public/package-data/bitcoind/0.21.1/LICENSE.md,
// icon: 'assets/img/service-icons/bitcoind.png',
// instructions: 'instructionsUrl', // /public/package-data/bitcoind/0.21.1/INSTRUCTIONS.md
// },
// manifest: {
// ...MockManifestBitcoind,
// version: '0.20.0',
// },
// installed: {
// status: {
// configured: true,
// main: {
// status: PackageMainStatus.Running,
// started: new Date().toISOString(),
// health: { },
// },
// 'dependency-errors': { },
// },
// 'interface-info': {
// ip: '10.0.0.1',
// addresses: {
// ui: {
// 'tor-address': 'bitcoind-ui-address.onion',
// 'lan-address': 'bitcoind-ui-address.local',
// },
// rpc: {
// 'tor-address': 'bitcoind-rpc-address.onion',
// 'lan-address': 'bitcoind-rpc-address.local',
// },
// p2p: {
// 'tor-address': 'bitcoind-p2p-address.onion',
// 'lan-address': 'bitcoind-p2p-address.local',
// },
// },
// },
// 'system-pointers': [],
// 'current-dependents': {
// 'lnd': {
// pointers: [],
// 'health-checks': [],
// },
// },
// 'current-dependencies': { },
// },
// 'install-progress': undefined,
// }
// export const lnd: PackageDataEntry = {
// state: PackageState.Installed,
// 'static-files': {
// license: 'licenseUrl', // /public/package-data/lnd/0.21.1/LICENSE.md,
// icon: 'assets/img/service-icons/lnd.png',
// instructions: 'instructionsUrl', // /public/package-data/lnd/0.21.1/INSTRUCTIONS.md
// },
// manifest: MockManifestLnd,
// installed: {
// status: {
// configured: true,
// main: {
// status: PackageMainStatus.Stopped,
// },
// 'dependency-errors': {
// 'bitcoin-proxy': {
// type: DependencyErrorType.NotInstalled,
// title: Mock.MockManifestBitcoinProxy.title,
// icon: 'assets/img/service-icons/bitcoin-proxy.png',
// },
// },
// },
// 'interface-info': {
// ip: '10.0.0.1',
// addresses: {
// rpc: {
// 'tor-address': 'lnd-rpc-address.onion',
// 'lan-address': 'lnd-rpc-address.local',
// },
// grpc: {
// 'tor-address': 'lnd-grpc-address.onion',
// 'lan-address': 'lnd-grpc-address.local',
// },
// },
// },
// 'system-pointers': [],
// 'current-dependents': { },
// 'current-dependencies': {
// 'bitcoind': {
// pointers: [],
// 'health-checks': [],
// },
// 'bitcoin-proxy': {
// pointers: [],
// 'health-checks': [],
// },
// },
// },
// 'install-progress': undefined,
// }
// export const DbDump: RR.GetDumpRes = {
// id: 1,
// expireId: null,
// value: {
// 'server-info': {
// id: 'start9-abcdefgmm',
// version: '1.0.0',
// status: ServerStatus.Running,
// 'lan-address': 'start9-abcdefgh.local',
// 'tor-address': 'myveryownspecialtoraddress.onion',
// wifi: {
// ssids: ['Goosers', 'Goosers5G'],
// selected: 'Goosers5G',
// connected: 'Goosers5G',
// },
// 'eos-marketplace': 'https://registry.start9.com',
// 'package-marketplace': 'https://registry.start9.com',
// 'unread-notification-count': 4,
// specs: {
// CPU: 'Cortex-A72: 4 Cores @1500MHz',
// Disk: '1TB SSD',
// Memory: '8GB',
// },
// 'connection-addresses': {
// tor: ['http://privacy34kn4ez3y3nijweec6w4g54i3g54sdv7r5mr6soma3w4begyd.onion'],
// clearnet: ['https://start9.com'],
// },
// },
// 'package-data': {
// 'bitcoind': bitcoind,
// 'lnd': lnd,
// },
// ui: {
// 'welcome-ack': '1.0.0',
// 'auto-check-updates': true,
// },
// },
// }
} }

View File

@@ -66,7 +66,7 @@ export abstract class ApiService implements Source<DataModel>, Http<DataModel> {
// )() // )()
// password // password
abstract updatePassword (params: RR.UpdatePasswordReq): Promise<RR.UpdatePasswordRes> // abstract updatePassword (params: RR.UpdatePasswordReq): Promise<RR.UpdatePasswordRes>
// notification // notification

View File

@@ -83,9 +83,9 @@ export class LiveApiService extends ApiService {
// } // }
// password // password
async updatePassword (params: RR.UpdatePasswordReq): Promise<RR.UpdatePasswordRes> { // async updatePassword (params: RR.UpdatePasswordReq): Promise<RR.UpdatePasswordRes> {
return this.http.rpcRequest({ method: 'password.set', params }) // return this.http.rpcRequest({ method: 'password.set', params })
} // }
// notification // notification

View File

@@ -1,7 +1,7 @@
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { pauseFor } from '../../../util/misc.util' import { pauseFor } from '../../../util/misc.util'
import { ApiService } from './embassy-api.service' import { ApiService } from './embassy-api.service'
import { PatchOp } from 'patch-db-client' import { Operation, PatchOp } from 'patch-db-client'
import { PackageDataEntry, PackageMainStatus, PackageState, ServerStatus } from 'src/app/services/patch-db/data-model' import { PackageDataEntry, PackageMainStatus, PackageState, ServerStatus } from 'src/app/services/patch-db/data-model'
import { RR, WithRevision } from '../api.types' import { RR, WithRevision } from '../api.types'
import { parsePropertiesPermissive } from 'src/app/util/properties.util' import { parsePropertiesPermissive } from 'src/app/util/properties.util'
@@ -12,7 +12,7 @@ import { ConfigService } from '../../config.service'
@Injectable() @Injectable()
export class MockApiService extends ApiService { export class MockApiService extends ApiService {
welcomeAck = false private readonly revertTime = 4000
constructor ( constructor (
private readonly http: HttpService, private readonly http: HttpService,
@@ -32,7 +32,7 @@ export class MockApiService extends ApiService {
// ...Mock.DbDump, // ...Mock.DbDump,
// id: this.nextSequence(), // id: this.nextSequence(),
// } // }
return this.http.rpcRequest({ method: 'db.revisions', params: { since } }) return this.http.rpcRequest<RR.GetRevisionsRes>({ method: 'db.revisions', params: { since } })
} }
async getDump (): Promise<RR.GetDumpRes> { async getDump (): Promise<RR.GetDumpRes> {
@@ -41,7 +41,7 @@ export class MockApiService extends ApiService {
// ...Mock.DbDump, // ...Mock.DbDump,
// id: this.nextSequence(), // id: this.nextSequence(),
// } // }
return this.http.rpcRequest({ method: 'db.dump' }) return this.http.rpcRequest<RR.GetDumpRes>({ method: 'db.dump' })
} }
async setDbValueRaw (params: RR.SetDBValueReq): Promise<RR.SetDBValueRes> { async setDbValueRaw (params: RR.SetDBValueReq): Promise<RR.SetDBValueRes> {
@@ -60,7 +60,7 @@ export class MockApiService extends ApiService {
// expireId: null, // expireId: null,
// }, // },
// } // }
return this.http.rpcRequest({ method: 'db.put.ui', params }) return this.http.rpcRequest<WithRevision<null>>({ method: 'db.put.ui', params })
} }
// auth // auth
@@ -94,14 +94,41 @@ export class MockApiService extends ApiService {
async updateServerRaw (params: RR.UpdateServerReq): Promise<RR.UpdateServerRes> { async updateServerRaw (params: RR.UpdateServerReq): Promise<RR.UpdateServerRes> {
await pauseFor(2000) await pauseFor(2000)
const path = '/server-info/status'
const patch = [ const patch = [
{ {
op: PatchOp.REPLACE, op: PatchOp.REPLACE,
path: '/server-info/status', path,
value: ServerStatus.Updating, value: ServerStatus.Updating,
}, },
] ]
return this.http.rpcRequest({ method: 'db.patch', params: { patch } }) const res = await this.http.rpcRequest<WithRevision<null>>({ method: 'db.patch', params: { patch } })
setTimeout(() => {
const patch = [
{
op: PatchOp.REPLACE,
path,
value: ServerStatus.Running,
},
{
op: PatchOp.REPLACE,
path: '/server-info/version',
value: this.config.version + '.1',
},
]
this.http.rpcRequest<WithRevision<null>>({ method: 'db.patch', params: { patch } })
// quickly revert patch to proper version to prevent infinite refresh loop
const patch2 = [
{
op: PatchOp.REPLACE,
path: '/server-info/version',
value: this.config.version,
},
]
this.http.rpcRequest<WithRevision<null>>({ method: 'db.patch', params: { patch: patch2 } })
}, this.revertTime)
return res
} }
async restartServer (params: RR.RestartServerReq): Promise<RR.RestartServerRes> { async restartServer (params: RR.RestartServerReq): Promise<RR.RestartServerRes> {
@@ -135,7 +162,7 @@ export class MockApiService extends ApiService {
value: params.url, value: params.url,
}, },
] ]
return this.http.rpcRequest({ method: 'db.patch', params: { patch } }) return this.http.rpcRequest<WithRevision<null>>({ method: 'db.patch', params: { patch } })
} }
// async setPackageMarketplaceRaw (params: RR.SetPackageMarketplaceReq): Promise<RR.SetPackageMarketplaceRes> { // async setPackageMarketplaceRaw (params: RR.SetPackageMarketplaceReq): Promise<RR.SetPackageMarketplaceRes> {
@@ -147,14 +174,14 @@ export class MockApiService extends ApiService {
// value: params.url, // value: params.url,
// }, // },
// ] // ]
// return this.http.rpcRequest({ method: 'db.patch', params: { patch } }) // return this.http.rpcRequest<WithRevision<null>>({ method: 'db.patch', params: { patch } })
// } // }
// password // password
async updatePassword (params: RR.UpdatePasswordReq): Promise<RR.UpdatePasswordRes> { // async updatePassword (params: RR.UpdatePasswordReq): Promise<RR.UpdatePasswordRes> {
await pauseFor(2000) // await pauseFor(2000)
return null // return null
} // }
// notification // notification
@@ -167,7 +194,7 @@ export class MockApiService extends ApiService {
value: 0, value: 0,
}, },
] ]
const { revision } = await this.http.rpcRequest({ method: 'db.patch', params: { patch } }) as WithRevision<null> const { revision } = await this.http.rpcRequest<WithRevision<RR.GetNotificationsRes>>({ method: 'db.patch', params: { patch } }) as WithRevision<null>
return { return {
response: Mock.Notifications, response: Mock.Notifications,
revision, revision,
@@ -200,24 +227,28 @@ export class MockApiService extends ApiService {
value: params.ssid, value: params.ssid,
}, },
] ]
return this.http.rpcRequest({ method: 'db.patch', params: { patch } }) return this.http.rpcRequest<WithRevision<null>>({ method: 'db.patch', params: { patch } })
} }
async deleteWifiRaw (params: RR.DeleteWifiReq): Promise<RR.DeleteWifiRes> { async deleteWifiRaw (params: RR.DeleteWifiReq): Promise<RR.DeleteWifiRes> {
await pauseFor(2000) await pauseFor(2000)
const patch = [ const patch: Operation[] = [
{ {
op: PatchOp.REPLACE, op: PatchOp.REMOVE,
path: '/server-info/wifi/selected', path: `/server-info/wifi/ssids/${params.ssid}`,
value: null,
},
{
op: PatchOp.REPLACE,
path: '/server-info/wifi/connected',
value: null,
}, },
// {
// op: PatchOp.REPLACE,
// path: '/server-info/wifi/selected',
// value: null,
// },
// {
// op: PatchOp.REPLACE,
// path: '/server-info/wifi/connected',
// value: null,
// },
] ]
return this.http.rpcRequest({ method: 'db.patch', params: { patch } }) return this.http.rpcRequest<WithRevision<null>>({ method: 'db.patch', params: { patch } })
} }
// ssh // ssh
@@ -241,14 +272,26 @@ export class MockApiService extends ApiService {
async createBackupRaw (params: RR.CreateBackupReq): Promise<RR.CreateBackupRes> { async createBackupRaw (params: RR.CreateBackupReq): Promise<RR.CreateBackupRes> {
await pauseFor(2000) await pauseFor(2000)
const path = '/server-info/status'
const patch = [ const patch = [
{ {
op: PatchOp.REPLACE, op: PatchOp.REPLACE,
path: '/server-info/status', path,
value: ServerStatus.BackingUp, value: ServerStatus.BackingUp,
}, },
] ]
return this.http.rpcRequest({ method: 'db.patch', params: { patch } }) const res = await this.http.rpcRequest<WithRevision<null>>({ method: 'db.patch', params: { patch } })
setTimeout(() => {
const patch = [
{
op: PatchOp.REPLACE,
path,
value: ServerStatus.Running,
},
]
this.http.rpcRequest<WithRevision<null>>({ method: 'db.patch', params: { patch } })
}, this.revertTime)
return res
} }
async restoreBackupRaw (params: RR.RestoreBackupReq): Promise<RR.RestoreBackupRes> { async restoreBackupRaw (params: RR.RestoreBackupReq): Promise<RR.RestoreBackupRes> {
@@ -302,7 +345,7 @@ export class MockApiService extends ApiService {
value: pkg, value: pkg,
}, },
] ]
return this.http.rpcRequest({ method: 'db.patch', params: { patch } }) return this.http.rpcRequest<WithRevision<null>>({ method: 'db.patch', params: { patch } })
} }
async dryUpdatePackage (params: RR.DryUpdatePackageReq): Promise<RR.DryUpdatePackageRes> { async dryUpdatePackage (params: RR.DryUpdatePackageReq): Promise<RR.DryUpdatePackageRes> {
@@ -328,25 +371,32 @@ export class MockApiService extends ApiService {
path: `/package-data/${params.id}/installed/status/configured`, path: `/package-data/${params.id}/installed/status/configured`,
value: true, value: true,
}, },
{
op: PatchOp.REPLACE,
path: `/package-data/${params.id}/installed/status/main/status`,
value: PackageMainStatus.Running,
},
] ]
return this.http.rpcRequest({ method: 'db.patch', params: { patch } }) return this.http.rpcRequest<WithRevision<null>>({ method: 'db.patch', params: { patch } })
} }
async restorePackageRaw (params: RR.RestorePackageReq): Promise<RR.RestorePackageRes> { async restorePackageRaw (params: RR.RestorePackageReq): Promise<RR.RestorePackageRes> {
await pauseFor(2000) await pauseFor(2000)
const path = `/package-data/${params.id}/installed/status/main/status`
const patch = [ const patch = [
{ {
op: PatchOp.REPLACE, op: PatchOp.REPLACE,
path: `/package-data/${params.id}/installed/status/main/status`, path,
value: PackageMainStatus.Restoring, value: PackageMainStatus.Restoring,
}, },
] ]
return this.http.rpcRequest({ method: 'db.patch', params: { patch } }) const res = await this.http.rpcRequest<WithRevision<null>>({ method: 'db.patch', params: { patch } })
setTimeout(() => {
const patch = [
{
op: PatchOp.REPLACE,
path,
value: PackageMainStatus.Stopped,
},
]
this.http.rpcRequest<WithRevision<null>>({ method: 'db.patch', params: { patch } })
}, this.revertTime)
return res
} }
async executePackageAction (params: RR.ExecutePackageActionReq): Promise<RR.ExecutePackageActionRes> { async executePackageAction (params: RR.ExecutePackageActionReq): Promise<RR.ExecutePackageActionRes> {
@@ -361,14 +411,15 @@ export class MockApiService extends ApiService {
async startPackageRaw (params: RR.StartPackageReq): Promise<RR.StartPackageRes> { async startPackageRaw (params: RR.StartPackageReq): Promise<RR.StartPackageRes> {
await pauseFor(2000) await pauseFor(2000)
const path = `/package-data/${params.id}/installed/status/main/status`
const patch = [ const patch = [
{ {
op: PatchOp.REPLACE, op: PatchOp.REPLACE,
path: `/package-data/${params.id}/installed/status/main/status`, path,
value: PackageMainStatus.Running, value: PackageMainStatus.Running,
}, },
] ]
return this.http.rpcRequest({ method: 'db.patch', params: { patch } }) return this.http.rpcRequest<WithRevision<null>>({ method: 'db.patch', params: { patch } })
} }
async dryStopPackage (params: RR.DryStopPackageReq): Promise<RR.DryStopPackageRes> { async dryStopPackage (params: RR.DryStopPackageReq): Promise<RR.DryStopPackageRes> {
@@ -378,10 +429,11 @@ export class MockApiService extends ApiService {
async stopPackageRaw (params: RR.StopPackageReq): Promise<RR.StopPackageRes> { async stopPackageRaw (params: RR.StopPackageReq): Promise<RR.StopPackageRes> {
await pauseFor(2000) await pauseFor(2000)
const path = `/package-data/${params.id}/installed/status/main/status`
const patch = [ const patch = [
{ {
op: PatchOp.REPLACE, op: PatchOp.REPLACE,
path: `/package-data/${params.id}/installed/status/main/status`, path,
value: PackageMainStatus.Stopping, value: PackageMainStatus.Stopping,
}, },
] ]
@@ -390,12 +442,12 @@ export class MockApiService extends ApiService {
const patch = [ const patch = [
{ {
op: PatchOp.REPLACE, op: PatchOp.REPLACE,
path: `/package-data/${params.id}/installed/status/main/status`, path,
value: PackageMainStatus.Stopped, value: PackageMainStatus.Stopped,
}, },
] ]
this.http.rpcRequest<WithRevision<null>>({ method: 'db.patch', params: { patch } }) this.http.rpcRequest<WithRevision<null>>({ method: 'db.patch', params: { patch } })
}, 2000) }, this.revertTime)
return res return res
} }
@@ -414,7 +466,17 @@ export class MockApiService extends ApiService {
value: PackageState.Removing, value: PackageState.Removing,
}, },
] ]
return this.http.rpcRequest({ method: 'db.patch', params: { patch } }) const res = await this.http.rpcRequest<WithRevision<null>>({ method: 'db.patch', params: { patch } })
setTimeout(async () => {
const patch = [
{
op: PatchOp.REMOVE,
path: `/package-data/${params.id}`,
},
]
this.http.rpcRequest<WithRevision<null>>({ method: 'db.patch', params: { patch } })
}, this.revertTime)
return res
} }
async dryConfigureDependency (params: RR.DryConfigureDependencyReq): Promise<RR.DryConfigureDependencyRes> { async dryConfigureDependency (params: RR.DryConfigureDependencyReq): Promise<RR.DryConfigureDependencyRes> {

View File

@@ -1,5 +1,5 @@
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { HttpService } from '../../http.service' import { HttpService, Method } from '../../http.service'
import { RR } from '../api.types' import { RR } from '../api.types'
import { MarketplaceApiService } from './marketplace-api.service' import { MarketplaceApiService } from './marketplace-api.service'
import { PatchDbService } from '../../patch-db/patch-db.service' import { PatchDbService } from '../../patch-db/patch-db.service'
@@ -17,29 +17,55 @@ export class MarketplaceLiveApiService extends MarketplaceApiService {
} }
async getEos (params: RR.GetMarketplaceEOSReq): Promise<RR.GetMarketplaceEOSRes> { async getEos (params: RR.GetMarketplaceEOSReq): Promise<RR.GetMarketplaceEOSRes> {
return this.http.simpleGet<RR.GetMarketplaceEOSRes>(this.getMarketplaceURL('eos'), params) const url = this.getMarketplaceURL('eos')
return this.http.httpRequest<RR.GetMarketplaceEOSRes>({
method: Method.GET,
url: url + '/eos',
params,
withCredentials: false,
})
} }
async getMarketplaceData (params: RR.GetMarketplaceDataReq): Promise<RR.GetMarketplaceDataRes> { async getMarketplaceData (params: RR.GetMarketplaceDataReq): Promise<RR.GetMarketplaceDataRes> {
return this.http.simpleGet<RR.GetMarketplaceDataRes>(this.getMarketplaceURL('package'), params) const url = this.getMarketplaceURL('package')
return this.http.httpRequest<RR.GetMarketplaceDataRes>({
method: Method.GET,
url: url + '/data',
params,
withCredentials: false,
})
} }
async getMarketplacePkgs (params: RR.GetMarketplacePackagesReq): Promise<RR.GetMarketplacePackagesRes> { async getMarketplacePkgs (params: RR.GetMarketplacePackagesReq): Promise<RR.GetMarketplacePackagesRes> {
const url = this.getMarketplaceURL('package', params.ids?.length > 1) const url = this.getMarketplaceURL('package', params.ids?.length > 1)
const threadParams = { return this.http.httpRequest<RR.GetMarketplacePackagesRes>({
...params, method: Method.GET,
ids: JSON.stringify(params.ids), url: url + '/packages',
} params: {
...params,
return this.http.simpleGet<RR.GetMarketplacePackagesRes>(url, threadParams) ids: JSON.stringify(params.ids),
},
withCredentials: false,
})
} }
async getReleaseNotes (params: RR.GetReleaseNotesReq): Promise<RR.GetReleaseNotesRes> { async getReleaseNotes (params: RR.GetReleaseNotesReq): Promise<RR.GetReleaseNotesRes> {
return this.http.simpleGet<RR.GetReleaseNotesRes>(this.getMarketplaceURL('package'), params) const url = this.getMarketplaceURL('package')
return this.http.httpRequest<RR.GetReleaseNotesRes>({
method: Method.GET,
url: url + + '/release-notes',
params,
withCredentials: false,
})
} }
async getLatestVersion (params: RR.GetLatestVersionReq): Promise<RR.GetLatestVersionRes> { async getLatestVersion (params: RR.GetLatestVersionReq): Promise<RR.GetLatestVersionRes> {
const url = this.getMarketplaceURL('package', params.ids?.length > 1) const url = this.getMarketplaceURL('package', params.ids?.length > 1)
return this.http.simpleGet<RR.GetLatestVersionRes>(url, params) return this.http.httpRequest<RR.GetLatestVersionRes>({
method: Method.GET,
url: url + '/latest-version',
params,
withCredentials: false,
})
} }
} }

View File

@@ -2,7 +2,7 @@ import { Injectable } from '@angular/core'
import { pauseFor } from '../../../util/misc.util' import { pauseFor } from '../../../util/misc.util'
import { RR } from '../api.types' import { RR } from '../api.types'
import { Mock } from '../api.fixures' import { Mock } from '../api.fixures'
import { HttpService } from '../../http.service' import { HttpService, Method } from '../../http.service'
import { MarketplaceApiService } from './marketplace-api.service' import { MarketplaceApiService } from './marketplace-api.service'
import { PatchDbService } from '../../patch-db/patch-db.service' import { PatchDbService } from '../../patch-db/patch-db.service'
import { ConfigService } from '../../config.service' import { ConfigService } from '../../config.service'
@@ -20,53 +20,68 @@ export class MarketplaceMockApiService extends MarketplaceApiService {
// marketplace // marketplace
async getEos (params: RR.GetMarketplaceEOSReq): Promise<RR.GetMarketplaceEOSRes> { async getEos (params: RR.GetMarketplaceEOSReq): Promise<RR.GetMarketplaceEOSRes> {
let url = this.getMarketplaceURL('eos') const url = this.getMarketplaceURL('eos')
if (this.useLocal(url)) { if (this.useLocal(url)) {
await pauseFor(2000) await pauseFor(2000)
return Mock.MarketplaceEos return Mock.MarketplaceEos
} }
url = `${url}/sys/version/eos` return this.http.httpRequest<RR.GetMarketplaceEOSRes>({
return this.http.simpleGet<RR.GetMarketplaceEOSRes>(url) method: Method.GET,
url: `${url}/eos`,
params,
withCredentials: false,
})
} }
async getMarketplaceData (params: RR.GetMarketplaceDataReq): Promise<RR.GetMarketplaceDataRes> { async getMarketplaceData (params: RR.GetMarketplaceDataReq): Promise<RR.GetMarketplaceDataRes> {
let url = this.getMarketplaceURL('package') const url = this.getMarketplaceURL('package')
if (this.useLocal(url)) { if (this.useLocal(url)) {
await pauseFor(2000) await pauseFor(2000)
return { return {
categories: ['featured', 'bitcoin', 'lightning', 'data', 'messaging', 'social', 'alt coin'], categories: ['featured', 'bitcoin', 'lightning', 'data', 'messaging', 'social', 'alt coin'],
} }
} }
url = `${url}/data` return this.http.httpRequest<RR.GetMarketplaceDataRes>({
return this.http.simpleGet<RR.GetMarketplaceDataRes>(url) method: Method.GET,
url: `${url}/data`,
params,
withCredentials: false,
})
} }
async getMarketplacePkgs (params: RR.GetMarketplacePackagesReq): Promise<RR.GetMarketplacePackagesRes> { async getMarketplacePkgs (params: RR.GetMarketplacePackagesReq): Promise<RR.GetMarketplacePackagesRes> {
let url = this.getMarketplaceURL('package', params.ids?.length > 1) const url = this.getMarketplaceURL('package', params.ids?.length > 1)
const threadParams = {
...params,
ids: JSON.stringify(params.ids),
}
if (this.useLocal(url)) { if (this.useLocal(url)) {
await pauseFor(2000) await pauseFor(2000)
return Mock.AvailableList return Mock.MarketplacePkgsList
} }
url = `${url}/packages` return this.http.httpRequest<RR.GetMarketplacePackagesRes>({
return this.http.simpleGet<RR.GetMarketplacePackagesRes>(url, threadParams) method: Method.GET,
url: `${url}/packages`,
params: {
...params,
ids: JSON.stringify(params.ids),
},
withCredentials: false,
})
} }
async getReleaseNotes (params: RR.GetReleaseNotesReq): Promise<RR.GetReleaseNotesRes> { async getReleaseNotes (params: RR.GetReleaseNotesReq): Promise<RR.GetReleaseNotesRes> {
let url = this.getMarketplaceURL('package') const url = this.getMarketplaceURL('package')
if (this.useLocal(url)) { if (this.useLocal(url)) {
await pauseFor(2000) await pauseFor(2000)
return Mock.ReleaseNotes return Mock.ReleaseNotes
} }
url = `${url}/release-notes` return this.http.httpRequest<RR.GetReleaseNotesRes>({
return this.http.simpleGet<RR.GetReleaseNotesRes>(url, params) method: Method.GET,
url: `${url}/release-notes`,
params,
withCredentials: false,
})
} }
async getLatestVersion (params: RR.GetLatestVersionReq): Promise<RR.GetLatestVersionRes> { async getLatestVersion (params: RR.GetLatestVersionReq): Promise<RR.GetLatestVersionRes> {
let url = this.getMarketplaceURL('package', params.ids?.length > 1) const url = this.getMarketplaceURL('package', params.ids?.length > 1)
if (this.useLocal(url)) { if (this.useLocal(url)) {
await pauseFor(2000) await pauseFor(2000)
return params.ids.reduce((obj, id) => { return params.ids.reduce((obj, id) => {
@@ -74,8 +89,13 @@ export class MarketplaceMockApiService extends MarketplaceApiService {
return obj return obj
}, { }) }, { })
} }
url = `${url}/latest-version`
return this.http.simpleGet<RR.GetLatestVersionRes>(url) return this.http.httpRequest<RR.GetLatestVersionRes>({
method: Method.GET,
url: `${url}/latest-version`,
params,
withCredentials: false,
})
} }
private useLocal (url: string): boolean { private useLocal (url: string): boolean {

View File

@@ -32,7 +32,7 @@ export class ConnectionService {
combineLatest([this.networkState$.pipe(distinctUntilChanged()), this.patch.watchConnection$().pipe(distinctUntilChanged())]) combineLatest([this.networkState$.pipe(distinctUntilChanged()), this.patch.watchConnection$().pipe(distinctUntilChanged())])
.subscribe(async ([network, connectionStatus]) => { .subscribe(async ([network, connectionStatus]) => {
const addrs = this.patch.data['server-info']?.['connection-addresses'] const addrs = this.patch.data['server-info']['connection-addresses']
if (connectionStatus !== ConnectionStatus.Disconnected) { if (connectionStatus !== ConnectionStatus.Disconnected) {
this.connectionFailure$.next(ConnectionFailure.None) this.connectionFailure$.next(ConnectionFailure.None)
} else if (!network) { } else if (!network) {
@@ -42,12 +42,12 @@ export class ConnectionService {
} else { } else {
// diagnosing // diagnosing
this.connectionFailure$.next(ConnectionFailure.Diagnosing) this.connectionFailure$.next(ConnectionFailure.Diagnosing)
const torSuccess = await this.testAddrs(addrs?.tor || []) const torSuccess = await this.testAddrs(addrs.tor)
if (torSuccess) { if (torSuccess) {
// TOR SUCCESS, EMBASSY IS PROBLEM // TOR SUCCESS, EMBASSY IS PROBLEM
this.connectionFailure$.next(ConnectionFailure.Embassy) this.connectionFailure$.next(ConnectionFailure.Embassy)
} else { } else {
const clearnetSuccess = await this.testAddrs(addrs?.clearnet || []) const clearnetSuccess = await this.testAddrs(addrs.clearnet)
if (clearnetSuccess) { if (clearnetSuccess) {
// CLEARNET SUCCESS, TOR IS PROBLEM // CLEARNET SUCCESS, TOR IS PROBLEM
this.connectionFailure$.next(ConnectionFailure.Tor) this.connectionFailure$.next(ConnectionFailure.Tor)
@@ -76,6 +76,7 @@ export class ConnectionService {
await this.httpService.httpRequest({ await this.httpService.httpRequest({
method: Method.GET, method: Method.GET,
url: addr, url: addr,
withCredentials: false,
}) })
return true return true
} catch (e) { } catch (e) {

View File

@@ -10,7 +10,6 @@ import { Revision } from 'patch-db-client'
}) })
export class HttpService { export class HttpService {
private unauthorizedApiResponse$ = new Subject() private unauthorizedApiResponse$ = new Subject()
authReqEnabled: boolean = false
fullUrl: string fullUrl: string
constructor ( constructor (
@@ -44,22 +43,15 @@ export class HttpService {
if (isRpcSuccess(res)) return res.result if (isRpcSuccess(res)) return res.result
} }
async simpleGet<T> (url: string, params: { [param: string]: string | string[] } = { }): Promise<T> {
Object.keys(params).forEach(key => {
if (!params[key]) delete params[key]
})
return this.http.get<T>(url, { params }).toPromise()
}
async httpRequest<T> (httpOpts: HttpOptions): Promise<T> { async httpRequest<T> (httpOpts: HttpOptions): Promise<T> {
let { body, timeout, ...rest} = this.translateOptions(httpOpts) let { body, timeout, url, ...rest} = this.translateOptions(httpOpts)
let req: Observable<{ body: T }> let req: Observable<{ body: T }>
switch (httpOpts.method){ switch (httpOpts.method){
case Method.GET: req = this.http.get(this.fullUrl, rest) as any; break case Method.GET: req = this.http.get(url, rest) as any; break
case Method.POST: req = this.http.post(this.fullUrl, body, rest) as any; break case Method.POST: req = this.http.post(url, body, rest) as any; break
case Method.PUT: req = this.http.put(this.fullUrl, body, rest) as any; break case Method.PUT: req = this.http.put(url, body, rest) as any; break
case Method.PATCH: req = this.http.patch(this.fullUrl, body, rest) as any; break case Method.PATCH: req = this.http.patch(url, body, rest) as any; break
case Method.DELETE: req = this.http.delete(this.fullUrl, rest) as any; break case Method.DELETE: req = this.http.delete(url, rest) as any; break
} }
return (timeout ? withTimeout(req, timeout) : req) return (timeout ? withTimeout(req, timeout) : req)
@@ -68,16 +60,25 @@ export class HttpService {
.catch(e => { throw new HttpError(e) }) .catch(e => { throw new HttpError(e) })
} }
translateOptions (httpOpts: HttpOptions): HttpJsonOptions { private translateOptions (httpOpts: HttpOptions): HttpJsonOptions {
if (httpOpts.withCredentials !== false) {
httpOpts.withCredentials = this.config.mocks.enabled ? false : true
}
const urlIsRelative = !httpOpts.url || httpOpts.url.startsWith('/')
const url = urlIsRelative ?
this.fullUrl + httpOpts.url :
httpOpts.url
return { return {
observe: 'events', observe: 'events',
responseType: 'json', responseType: 'json',
reportProgress: false, reportProgress: false,
withCredentials: this.config.mocks.enabled ? false : true, withCredentials: httpOpts.withCredentials,
headers: httpOpts.headers, headers: httpOpts.headers,
params: httpOpts.params, params: httpOpts.params,
body: httpOpts.data || { }, body: httpOpts.data || { },
url: httpOpts.url, url,
timeout: httpOpts.readTimeout, timeout: httpOpts.readTimeout,
} }
} }

View File

@@ -20,7 +20,6 @@ export enum ConnectionStatus {
}) })
export class PatchDbService { export class PatchDbService {
connectionStatus$ = new BehaviorSubject(ConnectionStatus.Initializing) connectionStatus$ = new BehaviorSubject(ConnectionStatus.Initializing)
sequence$: Observable<number>
data: DataModel data: DataModel
private patchDb: PatchDB<DataModel> private patchDb: PatchDB<DataModel>
private patchSub: Subscription private patchSub: Subscription
@@ -33,10 +32,7 @@ export class PatchDbService {
async init (): Promise<void> { async init (): Promise<void> {
const cache = await this.bootstrapper.init() const cache = await this.bootstrapper.init()
console.log('CACHECACHE', cache)
this.patchDb = new PatchDB([this.source, this.http], this.http, cache) this.patchDb = new PatchDB([this.source, this.http], this.http, cache)
this.sequence$ = this.patchDb.store.sequence$.asObservable()
this.data = this.patchDb.store.cache.data this.data = this.patchDb.store.cache.data
} }

View File

@@ -28,8 +28,8 @@ export class StartupAlertsService {
private readonly wizardBaker: WizardBaker, private readonly wizardBaker: WizardBaker,
private readonly patch: PatchDbService, private readonly patch: PatchDbService,
) { ) {
const welcome: Check<boolean> = { const osWelcome: Check<boolean> = {
name: 'welcome', name: 'osWelcome',
shouldRun: () => this.shouldRunOsWelcome(), shouldRun: () => this.shouldRunOsWelcome(),
check: async () => true, check: async () => true,
display: () => this.displayOsWelcome(), display: () => this.displayOsWelcome(),
@@ -42,14 +42,14 @@ export class StartupAlertsService {
display: pkg => this.displayOsUpdateCheck(pkg), display: pkg => this.displayOsUpdateCheck(pkg),
hasRun: this.config.skipStartupAlerts, hasRun: this.config.skipStartupAlerts,
} }
const apps: Check<boolean> = { const pkgsUpdate: Check<boolean> = {
name: 'apps', name: 'pkgsUpdate',
shouldRun: () => this.shouldRunAppsCheck(), shouldRun: () => this.shouldRunAppsCheck(),
check: () => this.appsCheck(), check: () => this.appsCheck(),
display: () => this.displayAppsCheck(), display: () => this.displayAppsCheck(),
hasRun: this.config.skipStartupAlerts, hasRun: this.config.skipStartupAlerts,
} }
this.checks = [welcome, osUpdate, apps] this.checks = [osWelcome, osUpdate, pkgsUpdate]
} }
// This takes our three checks and filters down to those that should run. // This takes our three checks and filters down to those that should run.
@@ -79,8 +79,7 @@ export class StartupAlertsService {
} }
private shouldRunOsWelcome (): boolean { private shouldRunOsWelcome (): boolean {
const data = this.patch.data return this.patch.data.ui['welcome-ack'] !== this.config.version
return !data.ui['welcome-ack'] && data['server-info'].version === this.config.version
} }
private shouldRunOsUpdateCheck (): boolean { private shouldRunOsUpdateCheck (): boolean {
@@ -94,7 +93,7 @@ export class StartupAlertsService {
private async osUpdateCheck (): Promise<RR.GetMarketplaceEOSRes | undefined> { private async osUpdateCheck (): Promise<RR.GetMarketplaceEOSRes | undefined> {
const res = await this.marketplaceApi.getEos({ }) const res = await this.marketplaceApi.getEos({ })
if (this.emver.compare(this.patch.data['server-info'].version, res.version) === -1) { if (this.emver.compare(this.config.version, res.version) === -1) {
return res return res
} else { } else {
return undefined return undefined
@@ -113,7 +112,7 @@ export class StartupAlertsService {
component: OSWelcomePage, component: OSWelcomePage,
presentingElement: await this.modalCtrl.getTop(), presentingElement: await this.modalCtrl.getTop(),
componentProps: { componentProps: {
version: this.patch.data['server-info'].version, version: this.config.version,
}, },
}) })