mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 20:14:49 +00:00
Market over embassy (#404)
* marketplace proxy'd through embassy * http not rpc * fix up marketplace
This commit is contained in:
@@ -1,8 +1,4 @@
|
|||||||
{
|
{
|
||||||
"start9Marketplace": {
|
|
||||||
"clearnet": "",
|
|
||||||
"tor": ""
|
|
||||||
},
|
|
||||||
"patchDb": {
|
"patchDb": {
|
||||||
"poll": {
|
"poll": {
|
||||||
"cooldown": 10000
|
"cooldown": 10000
|
||||||
@@ -14,7 +10,6 @@
|
|||||||
},
|
},
|
||||||
"mocks": {
|
"mocks": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"marketplace": true,
|
|
||||||
"connection": "ws",
|
"connection": "ws",
|
||||||
"rpcPort": "5959",
|
"rpcPort": "5959",
|
||||||
"wsPort": "5960",
|
"wsPort": "5960",
|
||||||
|
|||||||
56
ui/package-lock.json
generated
56
ui/package-lock.json
generated
@@ -54,16 +54,16 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"rxjs": "6.6.7",
|
"rxjs": "^6.6.3",
|
||||||
"sorted-btree": "1.5.0",
|
"sorted-btree": "^1.5.0",
|
||||||
"uuid": "8.3.2"
|
"uuid": "^8.3.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "16.4.13",
|
"@types/node": "^15.0.0",
|
||||||
"@types/uuid": "8.3.1",
|
"@types/uuid": "^8.3.0",
|
||||||
"ts-node": "10.2.0",
|
"ts-node": "^9.1.1",
|
||||||
"tslint": "6.1.3",
|
"tslint": "^6.1.0",
|
||||||
"typescript": "4.3.5"
|
"typescript": "4.1.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@ampproject/remapping": {
|
"node_modules/@ampproject/remapping": {
|
||||||
@@ -16820,7 +16820,9 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.0.tgz",
|
||||||
"integrity": "sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q==",
|
"integrity": "sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {}
|
"requires": {
|
||||||
|
"ajv": "^8.0.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"core-js": {
|
"core-js": {
|
||||||
"version": "3.16.0",
|
"version": "3.16.0",
|
||||||
@@ -16898,7 +16900,9 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.0.tgz",
|
||||||
"integrity": "sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q==",
|
"integrity": "sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {}
|
"requires": {
|
||||||
|
"ajv": "^8.0.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"json-schema-traverse": {
|
"json-schema-traverse": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
@@ -16942,7 +16946,9 @@
|
|||||||
"integrity": "sha512-Brah4Uo5/U8v76c6euTwtjVFFaVishwnJrQBYpev1JRh4vjA1F4HY3UzQez41YUCszUCXKagG8v6eVRBHV1gkw==",
|
"integrity": "sha512-Brah4Uo5/U8v76c6euTwtjVFFaVishwnJrQBYpev1JRh4vjA1F4HY3UzQez41YUCszUCXKagG8v6eVRBHV1gkw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
"peer": true,
|
||||||
"requires": {}
|
"requires": {
|
||||||
|
"ajv": "^8.0.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"json-schema-traverse": {
|
"json-schema-traverse": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
@@ -16995,7 +17001,9 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.0.tgz",
|
||||||
"integrity": "sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q==",
|
"integrity": "sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {}
|
"requires": {
|
||||||
|
"ajv": "^8.0.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"json-schema-traverse": {
|
"json-schema-traverse": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
@@ -17073,7 +17081,9 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.0.tgz",
|
||||||
"integrity": "sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q==",
|
"integrity": "sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {}
|
"requires": {
|
||||||
|
"ajv": "^8.0.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"json-schema-traverse": {
|
"json-schema-traverse": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
@@ -18622,7 +18632,9 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.0.tgz",
|
||||||
"integrity": "sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q==",
|
"integrity": "sha512-USH2jBb+C/hIpwD2iRjp0pe0k+MvzG0mlSn/FIdCgQhUb9ALPRjt2KIQdfZDS9r0ZIeUAg7gOu9KL0PFqGqr5Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {}
|
"requires": {
|
||||||
|
"ajv": "^8.0.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"json-schema-traverse": {
|
"json-schema-traverse": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
@@ -24491,14 +24503,14 @@
|
|||||||
"patch-db-client": {
|
"patch-db-client": {
|
||||||
"version": "file:../../patch-db/client",
|
"version": "file:../../patch-db/client",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/node": "16.4.13",
|
"@types/node": "^15.0.0",
|
||||||
"@types/uuid": "8.3.1",
|
"@types/uuid": "^8.3.0",
|
||||||
"rxjs": "6.6.7",
|
"rxjs": "^6.6.3",
|
||||||
"sorted-btree": "1.5.0",
|
"sorted-btree": "^1.5.0",
|
||||||
"ts-node": "10.2.0",
|
"ts-node": "^9.1.1",
|
||||||
"tslint": "6.1.3",
|
"tslint": "^6.1.0",
|
||||||
"typescript": "4.3.5",
|
"typescript": "4.1.5",
|
||||||
"uuid": "8.3.2"
|
"uuid": "^8.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"path-dirname": {
|
"path-dirname": {
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ import { FormBuilder } from '@angular/forms'
|
|||||||
Storage,
|
Storage,
|
||||||
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
|
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
|
||||||
{ provide: ApiService , useFactory: ApiServiceFactory, deps: [ConfigService, HttpService] }, { provide: ApiService , useFactory: ApiServiceFactory, deps: [ConfigService, HttpService] },
|
{ provide: ApiService , useFactory: ApiServiceFactory, deps: [ConfigService, HttpService] }, { provide: ApiService , useFactory: ApiServiceFactory, deps: [ConfigService, HttpService] },
|
||||||
{ provide: MarketplaceApiService , useFactory: MarketplaceApiServiceFactory, deps: [ConfigService, HttpService, PatchDbService] },
|
{ provide: MarketplaceApiService , useFactory: MarketplaceApiServiceFactory, deps: [ConfigService, HttpService, PatchDbService, ApiService] },
|
||||||
{ provide: PatchDbService, useFactory: PatchDbServiceFactory, deps: [ConfigService, LocalStorageBootstrap, ApiService] },
|
{ provide: PatchDbService, useFactory: PatchDbServiceFactory, deps: [ConfigService, LocalStorageBootstrap, ApiService] },
|
||||||
],
|
],
|
||||||
bootstrap: [AppComponent],
|
bootstrap: [AppComponent],
|
||||||
|
|||||||
@@ -21,10 +21,6 @@
|
|||||||
<ion-label>Auto Check for Updates</ion-label>
|
<ion-label>Auto Check for Updates</ion-label>
|
||||||
<ion-note slot="end">{{ patch.data.ui['auto-check-updates'] ? 'Enabled' : 'Disabled' }}</ion-note>
|
<ion-note slot="end">{{ patch.data.ui['auto-check-updates'] ? 'Enabled' : 'Disabled' }}</ion-note>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-item button (click)="serverConfig.presentAlert('eos-marketplace', server['eos-marketplace'] === config.start9Marketplace.tor)">
|
|
||||||
<ion-label>Tor Only Marketplace</ion-label>
|
|
||||||
<ion-note slot="end">{{ server['eos-marketplace'] === config.start9Marketplace.tor ? 'Enabled' : 'Disabled' }}</ion-note>
|
|
||||||
</ion-item>
|
|
||||||
<!-- <ion-item button (click)="presentModalValueEdit('packageMarketplace', server['package-marketplace'])">
|
<!-- <ion-item button (click)="presentModalValueEdit('packageMarketplace', server['package-marketplace'])">
|
||||||
<ion-label>Package Marketplace</ion-label>
|
<ion-label>Package Marketplace</ion-label>
|
||||||
<ion-note slot="end">{{ server['package-marketplace'] }}</ion-note>
|
<ion-note slot="end">{{ server['package-marketplace'] }}</ion-note>
|
||||||
|
|||||||
@@ -1,481 +0,0 @@
|
|||||||
import { ValueSpec, ConfigSpec, UniqueBy, ValueSpecOf, ValueType, ValueSpecObject, ValueSpecUnion } from './config-types'
|
|
||||||
import { Annotations, getDefaultObject, getDefaultUnion, listInnerSpec, mapConfigSpec, Range } from './config-utilities'
|
|
||||||
import * as pointer from 'json-pointer'
|
|
||||||
import * as handlebars from 'handlebars'
|
|
||||||
|
|
||||||
export class ConfigCursor<T extends ValueType> {
|
|
||||||
private cachedSpec?: ValueSpecOf<T>
|
|
||||||
|
|
||||||
constructor (
|
|
||||||
private readonly rootSpec: ConfigSpec,
|
|
||||||
private readonly rootOldConfig: object,
|
|
||||||
private readonly rootMappedConfig: object = null,
|
|
||||||
private readonly rootConfig: object = null,
|
|
||||||
private readonly ptr: string = '',
|
|
||||||
) {
|
|
||||||
if (!this.rootOldConfig) {
|
|
||||||
this.rootOldConfig = getDefaultObject(this.rootSpec)
|
|
||||||
}
|
|
||||||
if (!this.rootMappedConfig) {
|
|
||||||
this.rootMappedConfig = JSON.parse(JSON.stringify(this.rootOldConfig))
|
|
||||||
mapConfigSpec(this.rootSpec, this.rootMappedConfig)
|
|
||||||
}
|
|
||||||
if (!this.rootConfig) {
|
|
||||||
this.rootConfig = JSON.parse(JSON.stringify(this.rootMappedConfig))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
seek<S extends ValueType> (ptr: string): ConfigCursor<S> {
|
|
||||||
return new ConfigCursor(
|
|
||||||
this.rootSpec,
|
|
||||||
this.rootOldConfig,
|
|
||||||
this.rootMappedConfig,
|
|
||||||
this.rootConfig,
|
|
||||||
pointer.compile(
|
|
||||||
pointer.parse(this.ptr)
|
|
||||||
.concat(pointer.parse(ptr)),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
seekNext<S extends ValueType> (key: string | number): ConfigCursor<S> {
|
|
||||||
return this.seek(pointer.compile([`${key}`]))
|
|
||||||
}
|
|
||||||
|
|
||||||
unseek<S extends ValueType> (levels?: number): ConfigCursor<S> {
|
|
||||||
let ptr: string
|
|
||||||
if (levels === undefined) {
|
|
||||||
ptr = ''
|
|
||||||
} else {
|
|
||||||
// TODO, delete or make use of, it isn't being used so far
|
|
||||||
// This is not being used so far
|
|
||||||
let ptr_arr = pointer.parse(this.ptr)
|
|
||||||
for (let i = 0; i < levels; i++) {
|
|
||||||
ptr_arr.pop()
|
|
||||||
}
|
|
||||||
ptr = pointer.compile(ptr_arr)
|
|
||||||
}
|
|
||||||
return new ConfigCursor(
|
|
||||||
this.rootSpec,
|
|
||||||
this.rootOldConfig,
|
|
||||||
this.rootMappedConfig,
|
|
||||||
this.rootConfig,
|
|
||||||
ptr,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
key (): string {
|
|
||||||
return pointer.parse(this.ptr).pop()
|
|
||||||
}
|
|
||||||
|
|
||||||
oldConfig (): any {
|
|
||||||
if (pointer.has(this.rootOldConfig, this.ptr)) {
|
|
||||||
return pointer.get(this.rootOldConfig, this.ptr)
|
|
||||||
} else {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mappedConfig (): any {
|
|
||||||
if (pointer.has(this.rootMappedConfig, this.ptr)) {
|
|
||||||
return pointer.get(this.rootMappedConfig, this.ptr)
|
|
||||||
} else {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
toString (): string {
|
|
||||||
const spec: ValueSpec = this.spec()
|
|
||||||
const config = this.config()
|
|
||||||
switch (spec.type) {
|
|
||||||
case 'string':
|
|
||||||
return config
|
|
||||||
case 'number':
|
|
||||||
return `${config}${spec.units ? ' ' + spec.units : ''}`
|
|
||||||
case 'object':
|
|
||||||
return spec['display-as'] ? handlebars.compile(spec['display-as'])(config) : ''
|
|
||||||
case 'union':
|
|
||||||
return spec['display-as'] ? handlebars.compile(spec['display-as'])(config) : config[spec.tag.id]
|
|
||||||
case 'pointer':
|
|
||||||
return 'System Defined'
|
|
||||||
default:
|
|
||||||
return ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (config : T) then (spec : ValueSpecOf<T>)
|
|
||||||
config (): any {
|
|
||||||
if (pointer.has(this.rootConfig, this.ptr)) {
|
|
||||||
return pointer.get(this.rootConfig, this.ptr)
|
|
||||||
} else {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (config : T) then (spec : ValueSpecOf<T>)
|
|
||||||
spec (): ValueSpecOf<T> {
|
|
||||||
if (this.cachedSpec) return this.cachedSpec
|
|
||||||
const parsed = pointer.parse(this.ptr)
|
|
||||||
|
|
||||||
// We elevate the rootSpec (ConfigSpec) to a dummy ValueSpecObject
|
|
||||||
let ret: ValueSpec = {
|
|
||||||
type: 'object',
|
|
||||||
spec: this.rootSpec,
|
|
||||||
name: 'Config',
|
|
||||||
'display-as': 'Config',
|
|
||||||
'unique-by': null,
|
|
||||||
}
|
|
||||||
let ptr = []
|
|
||||||
for (let seg of parsed) {
|
|
||||||
switch (ret.type) {
|
|
||||||
case 'object':
|
|
||||||
ret = ret.spec[seg]
|
|
||||||
break
|
|
||||||
case 'union':
|
|
||||||
if (seg === ret.tag.id) {
|
|
||||||
ret = {
|
|
||||||
type: 'enum',
|
|
||||||
default: ret.default,
|
|
||||||
values: Object.keys(ret.variants),
|
|
||||||
name: ret.tag.name,
|
|
||||||
description: ret.tag.description,
|
|
||||||
'value-names': ret.tag['variant-names'],
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const cfg = this.unseek().seek(pointer.compile(ptr))
|
|
||||||
ret = ret.variants[cfg.config()[ret.tag.id]][seg]
|
|
||||||
}
|
|
||||||
break
|
|
||||||
case 'list':
|
|
||||||
//in essence, for a list we replace the list typed ValueSpecOf with it's internal ListValueSpec, a ValueSpecOf<T> where config @ ptr is of type T[].
|
|
||||||
// we also append default values to it.
|
|
||||||
// note also that jsonKey is not used. jsonKey in this case is an index of an array, like 0, 1, etc.
|
|
||||||
// this implies that every index of a list has an identical inner spec
|
|
||||||
ret = listInnerSpec(ret)
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
if (ret === undefined) break
|
|
||||||
ptr.push(seg)
|
|
||||||
}
|
|
||||||
this.cachedSpec = ret as ValueSpecOf<T>
|
|
||||||
return this.cachedSpec
|
|
||||||
}
|
|
||||||
|
|
||||||
checkInvalid (): string | null { // null if valid
|
|
||||||
const spec: ValueSpec = this.spec()
|
|
||||||
const cfg = this.config()
|
|
||||||
switch (spec.type) {
|
|
||||||
case 'string':
|
|
||||||
if (!cfg) {
|
|
||||||
return spec.nullable ? null : `${spec.name} is missing.`
|
|
||||||
} else if (typeof cfg === 'string') {
|
|
||||||
if (!spec.pattern || new RegExp(spec.pattern).test(cfg)) {
|
|
||||||
return null
|
|
||||||
} else {
|
|
||||||
return spec['pattern-description']
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new TypeError(`${this.ptr}: expected string, got ${Array.isArray(cfg) ? 'array' : typeof cfg}`)
|
|
||||||
}
|
|
||||||
case 'number':
|
|
||||||
if (!cfg) {
|
|
||||||
return spec.nullable ? null : `${spec.name} is missing.`
|
|
||||||
} else if (typeof cfg === 'number') {
|
|
||||||
if (spec.integral && cfg != Math.trunc(cfg)) {
|
|
||||||
return `${spec.name} must be an integer.`
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Range.from(spec.range).checkIncludes(cfg)
|
|
||||||
return null
|
|
||||||
} catch (e) {
|
|
||||||
return e.message
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new TypeError(`${this.ptr}: expected number, got ${Array.isArray(cfg) ? 'array' : typeof cfg}`)
|
|
||||||
}
|
|
||||||
case 'boolean':
|
|
||||||
if (typeof cfg === 'boolean') {
|
|
||||||
return null
|
|
||||||
} else {
|
|
||||||
throw new TypeError(`${this.ptr}: expected boolean, got ${Array.isArray(cfg) ? 'array' : typeof cfg}`)
|
|
||||||
}
|
|
||||||
case 'enum':
|
|
||||||
if (typeof cfg === 'string') {
|
|
||||||
spec['values-set'] = spec['values-set'] || new Set(spec.values)
|
|
||||||
return spec['values-set'].has(cfg) ? null : `${cfg} is not a valid selection.`
|
|
||||||
} else {
|
|
||||||
throw new TypeError(`${this.ptr}: expected string, got ${Array.isArray(cfg) ? 'array' : typeof cfg}`)
|
|
||||||
}
|
|
||||||
case 'list':
|
|
||||||
if (Array.isArray(cfg)) {
|
|
||||||
const range = Range.from(spec.range)
|
|
||||||
const min = range.integralMin()
|
|
||||||
const max = range.integralMax()
|
|
||||||
const length = cfg.length
|
|
||||||
if (min && length < min) {
|
|
||||||
return spec.subtype === 'enum' ? 'Not enough options selected.' : 'List is too short.'
|
|
||||||
}
|
|
||||||
if (max && length > max) {
|
|
||||||
return spec.subtype === 'enum' ? 'Too many options selected.' : 'List is too long.'
|
|
||||||
}
|
|
||||||
for (let idx = 0; idx < cfg.length; idx++) {
|
|
||||||
let cursor = this.seekNext(idx)
|
|
||||||
const invalid = cursor.checkInvalid()
|
|
||||||
if (invalid) {
|
|
||||||
return `Item #${idx + 1} is invalid. ${invalid}.`
|
|
||||||
}
|
|
||||||
if (spec.subtype === 'enum') continue
|
|
||||||
for (let idx2 = idx + 1; idx2 < cfg.length; idx2++) {
|
|
||||||
if (cursor.equals(this.seekNext(idx2))) {
|
|
||||||
return `Item #${idx + 1} is not unique.` + ('uniqueBy' in cursor.spec()) ? `${
|
|
||||||
displayUniqueBy(
|
|
||||||
(cursor.spec() as ValueSpecObject | ValueSpecUnion)['unique-by'],
|
|
||||||
(cursor.spec() as ValueSpecObject | ValueSpecUnion),
|
|
||||||
cursor.config(),
|
|
||||||
)
|
|
||||||
} must be unique.` : ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
} else {
|
|
||||||
throw new TypeError(`${this.ptr}: expected array, got ${Array.isArray(cfg) ? 'array' : typeof cfg}`)
|
|
||||||
}
|
|
||||||
case 'object':
|
|
||||||
if (!cfg) {
|
|
||||||
return `${spec.name} is missing.`
|
|
||||||
} else if (typeof cfg === 'object' && !Array.isArray(cfg)) {
|
|
||||||
for (let idx in spec.spec) {
|
|
||||||
if (this.seekNext(idx).checkInvalid()) {
|
|
||||||
return `${spec.spec[idx].name} is invalid.`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
} else {
|
|
||||||
throw new TypeError(`${this.ptr}: expected object, got ${Array.isArray(cfg) ? 'array' : typeof cfg}`)
|
|
||||||
}
|
|
||||||
case 'pointer':
|
|
||||||
return null
|
|
||||||
case 'union':
|
|
||||||
if (typeof cfg === 'object' && !Array.isArray(cfg)) {
|
|
||||||
if (typeof cfg[spec.tag.id] === 'string') {
|
|
||||||
for (let idx in spec.variants[cfg[spec.tag.id]]) {
|
|
||||||
if (this.seekNext(idx).checkInvalid()) {
|
|
||||||
return `${spec.variants[cfg[spec.tag.id]][idx].name} is invalid.`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
} else {
|
|
||||||
throw new TypeError(`${this.ptr}/${spec.tag.id}: expected string, got ${Array.isArray(cfg) ? 'array' : typeof cfg}`)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new TypeError(`${this.ptr}: expected object, got ${Array.isArray(cfg) ? 'array' : typeof cfg}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isNew (): boolean {
|
|
||||||
const oldCfg = this.oldConfig()
|
|
||||||
const mappedCfg = this.mappedConfig()
|
|
||||||
if (mappedCfg && oldCfg && typeof mappedCfg === 'object' && typeof oldCfg === 'object') {
|
|
||||||
for (let key in mappedCfg) {
|
|
||||||
if (this.seekNext(key).isNew()) return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
} else {
|
|
||||||
return mappedCfg !== oldCfg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isEdited (): boolean {
|
|
||||||
const cfg = this.config()
|
|
||||||
const mappedCfg = this.mappedConfig()
|
|
||||||
if (cfg && mappedCfg && typeof cfg === 'object' && typeof mappedCfg === 'object') {
|
|
||||||
const spec = this.spec()
|
|
||||||
let allKeys: Set<string>
|
|
||||||
if (spec.type === 'union') {
|
|
||||||
let unionSpec = spec as ValueSpecOf<'union'>
|
|
||||||
const labelForSelection = unionSpec.tag.id
|
|
||||||
allKeys = new Set([labelForSelection, ...Object.keys(unionSpec.variants[cfg[labelForSelection]])])
|
|
||||||
} else {
|
|
||||||
allKeys = new Set([...Object.keys(cfg), ...Object.keys(mappedCfg)])
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let key of allKeys) {
|
|
||||||
if (this.seekNext(key).isEdited()) return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
} else {
|
|
||||||
return cfg !== mappedCfg
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
equals (cursor: ConfigCursor<T>): boolean {
|
|
||||||
const lhs = this.config()
|
|
||||||
const rhs = cursor.config()
|
|
||||||
const spec: ValueSpec = this.spec()
|
|
||||||
|
|
||||||
switch (spec.type) {
|
|
||||||
case 'string':
|
|
||||||
case 'number':
|
|
||||||
case 'boolean':
|
|
||||||
case 'enum':
|
|
||||||
return lhs === rhs
|
|
||||||
case 'object':
|
|
||||||
case 'union':
|
|
||||||
return isEqual(spec['unique-by'], this as ConfigCursor<'object' | 'union'>, cursor as ConfigCursor<'object' | 'union'>)
|
|
||||||
case 'list':
|
|
||||||
if (lhs.length !== rhs.length) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for (let idx = 0; idx < lhs.length; idx++) {
|
|
||||||
if (!this.seekNext(`${idx}`).equals(cursor.seekNext(`${idx}`))) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getAnnotations (): Annotations<T> {
|
|
||||||
const spec: ValueSpec = this.spec()
|
|
||||||
switch (spec.type) {
|
|
||||||
case 'object': {
|
|
||||||
const ret: Annotations<'object'> = {
|
|
||||||
self: {
|
|
||||||
invalid: this.checkInvalid(),
|
|
||||||
edited: this.isEdited(),
|
|
||||||
added: this.isNew(),
|
|
||||||
},
|
|
||||||
members: { },
|
|
||||||
}
|
|
||||||
for (let key in spec.spec) {
|
|
||||||
let annotation: any = this.seekNext(key).getAnnotations()
|
|
||||||
if ('self' in annotation) {
|
|
||||||
annotation = annotation.self
|
|
||||||
}
|
|
||||||
ret.members[key] = annotation
|
|
||||||
}
|
|
||||||
return ret as Annotations<T>
|
|
||||||
}
|
|
||||||
case 'union': {
|
|
||||||
const ret: Annotations<'union'> = {
|
|
||||||
self: {
|
|
||||||
invalid: this.checkInvalid(),
|
|
||||||
edited: this.isEdited(),
|
|
||||||
added: this.isNew(),
|
|
||||||
},
|
|
||||||
members: {
|
|
||||||
[spec.tag.id]: this.seekNext<'enum'>(spec.tag.id).getAnnotations(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for (let key in spec.variants[this.config()[spec.tag.id]]) {
|
|
||||||
let annotation: any = this.seekNext(key).getAnnotations()
|
|
||||||
if ('self' in annotation) {
|
|
||||||
annotation = annotation.self
|
|
||||||
}
|
|
||||||
ret.members[key] = annotation
|
|
||||||
}
|
|
||||||
return ret as Annotations<T>
|
|
||||||
}
|
|
||||||
case 'list': {
|
|
||||||
const ret: Annotations<'list'> = {
|
|
||||||
self: {
|
|
||||||
invalid: this.checkInvalid(),
|
|
||||||
edited: this.isEdited(),
|
|
||||||
added: this.isNew(),
|
|
||||||
},
|
|
||||||
members: [],
|
|
||||||
}
|
|
||||||
for (let key in this.config()) {
|
|
||||||
let annotation: any = this.seekNext(key).getAnnotations()
|
|
||||||
if ('self' in annotation) {
|
|
||||||
annotation = annotation.self
|
|
||||||
}
|
|
||||||
ret.members[key] = annotation
|
|
||||||
}
|
|
||||||
return ret as Annotations<T>
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return {
|
|
||||||
invalid: this.checkInvalid(),
|
|
||||||
edited: this.isEdited(),
|
|
||||||
added: this.isNew(),
|
|
||||||
} as Annotations<T>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async createFirstEntryForList () {
|
|
||||||
const spec: ValueSpec = this.spec()
|
|
||||||
|
|
||||||
if (spec.type === 'object' && !this.config()) {
|
|
||||||
pointer.set(this.rootConfig, this.ptr, getDefaultObject(spec.spec))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (spec.type === 'union' && !this.config()) {
|
|
||||||
pointer.set(this.rootConfig, this.ptr, getDefaultUnion(spec))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
injectModalData (res: { data?: any }): void {
|
|
||||||
if (res.data !== undefined) {
|
|
||||||
pointer.set(this.rootConfig, this.ptr, res.data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function isEqual (uniqueBy: UniqueBy, lhs: ConfigCursor<'object'>, rhs: ConfigCursor<'object'>): boolean {
|
|
||||||
if (uniqueBy === null) {
|
|
||||||
return false
|
|
||||||
} else if (typeof uniqueBy === 'string') {
|
|
||||||
return lhs.seekNext(uniqueBy).equals(rhs.seekNext(uniqueBy))
|
|
||||||
} else if ('any' in uniqueBy) {
|
|
||||||
for (let subSpec of uniqueBy.any) {
|
|
||||||
if (isEqual(subSpec, lhs, rhs)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
} else if ('all' in uniqueBy) {
|
|
||||||
for (let subSpec of uniqueBy.all) {
|
|
||||||
if (!isEqual(subSpec, lhs, rhs)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function displayUniqueBy (uniqueBy: UniqueBy, spec: ValueSpecObject | ValueSpecUnion, value: object): string {
|
|
||||||
if (typeof uniqueBy === 'string') {
|
|
||||||
if (spec.type === 'object') {
|
|
||||||
return spec.spec[uniqueBy].name
|
|
||||||
} else if (spec.type === 'union') {
|
|
||||||
if (uniqueBy === spec.tag.id) {
|
|
||||||
return spec.tag.name
|
|
||||||
} else {
|
|
||||||
return spec.variants[value[spec.tag.id]][uniqueBy].name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if ('any' in uniqueBy) {
|
|
||||||
return uniqueBy.any.map(uq => {
|
|
||||||
if (typeof uq === 'object' && 'all' in uq) {
|
|
||||||
return `(${displayUniqueBy(uq, spec, value)})`
|
|
||||||
} else {
|
|
||||||
return displayUniqueBy(uq, spec, value)
|
|
||||||
}
|
|
||||||
}).join(' and ')
|
|
||||||
} else if ('all' in uniqueBy) {
|
|
||||||
return uniqueBy.all.map(uq => {
|
|
||||||
if (typeof uq === 'object' && 'any' in uq) {
|
|
||||||
return `(${displayUniqueBy(uq, spec, value)})`
|
|
||||||
} else {
|
|
||||||
return displayUniqueBy(uq, spec, value)
|
|
||||||
}
|
|
||||||
}).join(' or ')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,6 +5,7 @@ import { ConfigService } from '../config.service'
|
|||||||
import { PatchDbService } from '../patch-db/patch-db.service'
|
import { PatchDbService } from '../patch-db/patch-db.service'
|
||||||
import { MarketplaceLiveApiService } from './marketplace/marketplace-live-api.service'
|
import { MarketplaceLiveApiService } from './marketplace/marketplace-live-api.service'
|
||||||
import { MarketplaceMockApiService } from './marketplace/marketplace-mock-api.service'
|
import { MarketplaceMockApiService } from './marketplace/marketplace-mock-api.service'
|
||||||
|
import { ApiService } from './embassy/embassy-api.service'
|
||||||
|
|
||||||
export function ApiServiceFactory (config: ConfigService, http: HttpService) {
|
export function ApiServiceFactory (config: ConfigService, http: HttpService) {
|
||||||
if (config.mocks.enabled) {
|
if (config.mocks.enabled) {
|
||||||
@@ -14,10 +15,10 @@ export function ApiServiceFactory (config: ConfigService, http: HttpService) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MarketplaceApiServiceFactory (config: ConfigService, http: HttpService, patch: PatchDbService) {
|
export function MarketplaceApiServiceFactory (config: ConfigService, patch: PatchDbService, apiService: ApiService) {
|
||||||
if (config.mocks.enabled) {
|
if (config.mocks.enabled) {
|
||||||
return new MarketplaceMockApiService(http, config, patch)
|
return new MarketplaceMockApiService(config, patch)
|
||||||
} else {
|
} else {
|
||||||
return new MarketplaceLiveApiService(http, config, patch)
|
return new MarketplaceLiveApiService(apiService, config, patch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@ import { Subject, Observable } from 'rxjs'
|
|||||||
import { Http, Update, Operation, Revision, Source, Store } from 'patch-db-client'
|
import { Http, Update, Operation, Revision, Source, Store } from 'patch-db-client'
|
||||||
import { RR } from '../api.types'
|
import { RR } from '../api.types'
|
||||||
import { DataModel } from 'src/app/services/patch-db/data-model'
|
import { DataModel } from 'src/app/services/patch-db/data-model'
|
||||||
import { RequestError, RPCError } from '../../http.service'
|
import { Method, RequestError } from '../../http.service'
|
||||||
|
|
||||||
export abstract class ApiService implements Source<DataModel>, Http<DataModel> {
|
export abstract class ApiService implements Source<DataModel>, Http<DataModel> {
|
||||||
protected readonly sync = new Subject<Update<DataModel>>()
|
protected readonly sync = new Subject<Update<DataModel>>()
|
||||||
@@ -65,10 +65,7 @@ export abstract class ApiService implements Source<DataModel>, Http<DataModel> {
|
|||||||
|
|
||||||
// marketplace URLs
|
// marketplace URLs
|
||||||
|
|
||||||
protected abstract setEosMarketplaceRaw (isTor: boolean): Promise<RR.SetEosMarketplaceRes>
|
abstract marketplaceProxy (url: string, params: { [key: string]: any }): Promise<any>
|
||||||
setEosMarketplace = (isTor: boolean) => this.syncResponse(
|
|
||||||
() => this.setEosMarketplaceRaw(isTor),
|
|
||||||
)()
|
|
||||||
|
|
||||||
// protected abstract setPackageMarketplaceRaw (params: RR.SetPackageMarketplaceReq): Promise<RR.SetPackageMarketplaceRes>
|
// protected abstract setPackageMarketplaceRaw (params: RR.SetPackageMarketplaceReq): Promise<RR.SetPackageMarketplaceRes>
|
||||||
// setPackageMarketplace = (params: RR.SetPackageMarketplaceReq) => this.syncResponse(
|
// setPackageMarketplace = (params: RR.SetPackageMarketplaceReq) => this.syncResponse(
|
||||||
|
|||||||
@@ -87,11 +87,12 @@ export class LiveApiService extends ApiService {
|
|||||||
|
|
||||||
// marketplace URLs
|
// marketplace URLs
|
||||||
|
|
||||||
async setEosMarketplaceRaw (isTor: boolean): Promise<RR.SetEosMarketplaceRes> {
|
async marketplaceProxy (url: string, params: { [key: string]: any }) {
|
||||||
const params: RR.SetEosMarketplaceReq = {
|
return this.http.httpRequest({
|
||||||
url: isTor ? this.config.start9Marketplace.tor : this.config.start9Marketplace.clearnet,
|
method: Method.GET,
|
||||||
}
|
url,
|
||||||
return this.http.rpcRequest({ method: 'marketplace.eos.set', params })
|
params,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// async setPackageMarketplaceRaw (params: RR.SetPackageMarketplaceReq): Promise<RR.SetPackageMarketplaceRes> {
|
// async setPackageMarketplaceRaw (params: RR.SetPackageMarketplaceReq): Promise<RR.SetPackageMarketplaceRes> {
|
||||||
@@ -105,130 +106,130 @@ export class LiveApiService extends ApiService {
|
|||||||
|
|
||||||
// notification
|
// notification
|
||||||
|
|
||||||
async getNotificationsRaw (params: RR.GetNotificationsReq): Promise<RR.GetNotificationsRes> {
|
async getNotificationsRaw (params: RR.GetNotificationsReq): Promise < RR.GetNotificationsRes > {
|
||||||
return this.http.rpcRequest({ method: 'notification.list', params })
|
return this.http.rpcRequest({ method: 'notification.list', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteNotification (params: RR.DeleteNotificationReq): Promise<RR.DeleteNotificationRes> {
|
async deleteNotification (params: RR.DeleteNotificationReq): Promise < RR.DeleteNotificationRes > {
|
||||||
return this.http.rpcRequest({ method: 'notification.delete', params })
|
return this.http.rpcRequest({ method: 'notification.delete', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteAllNotifications (params: RR.DeleteAllNotificationsReq): Promise<RR.DeleteAllNotificationsRes> {
|
async deleteAllNotifications (params: RR.DeleteAllNotificationsReq): Promise < RR.DeleteAllNotificationsRes > {
|
||||||
return this.http.rpcRequest({ method: 'notification.delete.all', params })
|
return this.http.rpcRequest({ method: 'notification.delete.all', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
// wifi
|
// wifi
|
||||||
|
|
||||||
async addWifi (params: RR.AddWifiReq): Promise<RR.AddWifiRes> {
|
async addWifi (params: RR.AddWifiReq): Promise < RR.AddWifiRes > {
|
||||||
return this.http.rpcRequest({ method: 'wifi.add', params })
|
return this.http.rpcRequest({ method: 'wifi.add', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
async connectWifiRaw (params: RR.ConnectWifiReq): Promise<RR.ConnectWifiRes> {
|
async connectWifiRaw (params: RR.ConnectWifiReq): Promise < RR.ConnectWifiRes > {
|
||||||
return this.http.rpcRequest({ method: 'wifi.connect', params })
|
return this.http.rpcRequest({ method: 'wifi.connect', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteWifiRaw (params: RR.DeleteWifiReq): Promise<RR.DeleteWifiRes> {
|
async deleteWifiRaw (params: RR.DeleteWifiReq): Promise < RR.DeleteWifiRes > {
|
||||||
return this.http.rpcRequest({ method: 'wifi.delete', params })
|
return this.http.rpcRequest({ method: 'wifi.delete', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
// ssh
|
// ssh
|
||||||
|
|
||||||
async getSshKeys (params: RR.GetSSHKeysReq): Promise<RR.GetSSHKeysRes> {
|
async getSshKeys (params: RR.GetSSHKeysReq): Promise < RR.GetSSHKeysRes > {
|
||||||
return this.http.rpcRequest({ method: 'ssh.get', params })
|
return this.http.rpcRequest({ method: 'ssh.get', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
async addSshKey (params: RR.AddSSHKeyReq): Promise<RR.AddSSHKeyRes> {
|
async addSshKey (params: RR.AddSSHKeyReq): Promise < RR.AddSSHKeyRes > {
|
||||||
return this.http.rpcRequest({ method: 'ssh.add', params })
|
return this.http.rpcRequest({ method: 'ssh.add', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteSshKey (params: RR.DeleteSSHKeyReq): Promise<RR.DeleteSSHKeyRes> {
|
async deleteSshKey (params: RR.DeleteSSHKeyReq): Promise < RR.DeleteSSHKeyRes > {
|
||||||
return this.http.rpcRequest({ method: 'ssh.delete', params })
|
return this.http.rpcRequest({ method: 'ssh.delete', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
// backup
|
// backup
|
||||||
|
|
||||||
async createBackupRaw (params: RR.CreateBackupReq): Promise<RR.CreateBackupRes> {
|
async createBackupRaw (params: RR.CreateBackupReq): Promise < RR.CreateBackupRes > {
|
||||||
return this.http.rpcRequest({ method: 'backup.create', params })
|
return this.http.rpcRequest({ method: 'backup.create', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
async restoreBackupRaw (params: RR.RestoreBackupReq): Promise<RR.RestoreBackupRes> {
|
async restoreBackupRaw (params: RR.RestoreBackupReq): Promise < RR.RestoreBackupRes > {
|
||||||
return this.http.rpcRequest({ method: 'backup.restore', params })
|
return this.http.rpcRequest({ method: 'backup.restore', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
// disk
|
// disk
|
||||||
|
|
||||||
getDisks (params: RR.GetDisksReq): Promise<RR.GetDisksRes> {
|
getDisks (params: RR.GetDisksReq): Promise < RR.GetDisksRes > {
|
||||||
return this.http.rpcRequest({ method: 'disk.list', params })
|
return this.http.rpcRequest({ method: 'disk.list', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
ejectDisk (params: RR.EjectDisksReq): Promise<RR.EjectDisksRes> {
|
ejectDisk (params: RR.EjectDisksReq): Promise < RR.EjectDisksRes > {
|
||||||
return this.http.rpcRequest({ method: 'disk.eject', params })
|
return this.http.rpcRequest({ method: 'disk.eject', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
// package
|
// package
|
||||||
|
|
||||||
async getPackageProperties (params: RR.GetPackagePropertiesReq): Promise<RR.GetPackagePropertiesRes<any>['data']> {
|
async getPackageProperties (params: RR.GetPackagePropertiesReq): Promise < RR.GetPackagePropertiesRes < any > ['data'] > {
|
||||||
return this.http.rpcRequest({ method: 'package.properties', params })
|
return this.http.rpcRequest({ method: 'package.properties', params })
|
||||||
.then(parsePropertiesPermissive)
|
.then(parsePropertiesPermissive)
|
||||||
}
|
}
|
||||||
|
|
||||||
async getPackageLogs (params: RR.GetPackageLogsReq): Promise<RR.GetPackageLogsRes> {
|
async getPackageLogs (params: RR.GetPackageLogsReq): Promise < RR.GetPackageLogsRes > {
|
||||||
return this.http.rpcRequest( { method: 'package.logs', params })
|
return this.http.rpcRequest( { method: 'package.logs', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
async getPkgMetrics (params: RR.GetPackageMetricsReq): Promise<RR.GetPackageMetricsRes> {
|
async getPkgMetrics (params: RR.GetPackageMetricsReq): Promise < RR.GetPackageMetricsRes > {
|
||||||
return this.http.rpcRequest({ method: 'package.metrics', params })
|
return this.http.rpcRequest({ method: 'package.metrics', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
async installPackageRaw (params: RR.InstallPackageReq): Promise<RR.InstallPackageRes> {
|
async installPackageRaw (params: RR.InstallPackageReq): Promise < RR.InstallPackageRes > {
|
||||||
return this.http.rpcRequest({ method: 'package.install', params })
|
return this.http.rpcRequest({ method: 'package.install', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
async dryUpdatePackage (params: RR.DryUpdatePackageReq): Promise<RR.DryUpdatePackageRes> {
|
async dryUpdatePackage (params: RR.DryUpdatePackageReq): Promise < RR.DryUpdatePackageRes > {
|
||||||
return this.http.rpcRequest({ method: 'package.update.dry', params })
|
return this.http.rpcRequest({ method: 'package.update.dry', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
async getPackageConfig (params: RR.GetPackageConfigReq): Promise<RR.GetPackageConfigRes> {
|
async getPackageConfig (params: RR.GetPackageConfigReq): Promise < RR.GetPackageConfigRes > {
|
||||||
return this.http.rpcRequest({ method: 'package.config.get', params })
|
return this.http.rpcRequest({ method: 'package.config.get', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
async drySetPackageConfig (params: RR.DrySetPackageConfigReq): Promise<RR.DrySetPackageConfigRes> {
|
async drySetPackageConfig (params: RR.DrySetPackageConfigReq): Promise < RR.DrySetPackageConfigRes > {
|
||||||
return this.http.rpcRequest({ method: 'package.config.set.dry', params })
|
return this.http.rpcRequest({ method: 'package.config.set.dry', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
async setPackageConfigRaw (params: RR.SetPackageConfigReq): Promise<RR.SetPackageConfigRes> {
|
async setPackageConfigRaw (params: RR.SetPackageConfigReq): Promise < RR.SetPackageConfigRes > {
|
||||||
return this.http.rpcRequest({ method: 'package.config.set', params })
|
return this.http.rpcRequest({ method: 'package.config.set', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
async restorePackageRaw (params: RR.RestorePackageReq): Promise<RR.RestorePackageRes> {
|
async restorePackageRaw (params: RR.RestorePackageReq): Promise < RR.RestorePackageRes > {
|
||||||
return this.http.rpcRequest({ method: 'package.restore', params })
|
return this.http.rpcRequest({ method: 'package.restore', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
async executePackageAction (params: RR.ExecutePackageActionReq): Promise<RR.ExecutePackageActionRes> {
|
async executePackageAction (params: RR.ExecutePackageActionReq): Promise < RR.ExecutePackageActionRes > {
|
||||||
return this.http.rpcRequest({ method: 'package.action', params })
|
return this.http.rpcRequest({ method: 'package.action', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
async startPackageRaw (params: RR.StartPackageReq): Promise<RR.StartPackageRes> {
|
async startPackageRaw (params: RR.StartPackageReq): Promise < RR.StartPackageRes > {
|
||||||
return this.http.rpcRequest({ method: 'package.start', params })
|
return this.http.rpcRequest({ method: 'package.start', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
async dryStopPackage (params: RR.DryStopPackageReq): Promise<RR.DryStopPackageRes> {
|
async dryStopPackage (params: RR.DryStopPackageReq): Promise < RR.DryStopPackageRes > {
|
||||||
return this.http.rpcRequest({ method: 'package.stop.dry', params })
|
return this.http.rpcRequest({ method: 'package.stop.dry', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
async stopPackageRaw (params: RR.StopPackageReq): Promise<RR.StopPackageRes> {
|
async stopPackageRaw (params: RR.StopPackageReq): Promise < RR.StopPackageRes > {
|
||||||
return this.http.rpcRequest({ method: 'package.stop', params })
|
return this.http.rpcRequest({ method: 'package.stop', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
async dryRemovePackage (params: RR.DryRemovePackageReq): Promise<RR.DryRemovePackageRes> {
|
async dryRemovePackage (params: RR.DryRemovePackageReq): Promise < RR.DryRemovePackageRes > {
|
||||||
return this.http.rpcRequest({ method: 'package.remove.dry', params })
|
return this.http.rpcRequest({ method: 'package.remove.dry', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
async removePackageRaw (params: RR.RemovePackageReq): Promise<RR.RemovePackageRes> {
|
async removePackageRaw (params: RR.RemovePackageReq): Promise < RR.RemovePackageRes > {
|
||||||
return this.http.rpcRequest({ method: 'package.remove', params })
|
return this.http.rpcRequest({ method: 'package.remove', params })
|
||||||
}
|
}
|
||||||
|
|
||||||
async dryConfigureDependency (params: RR.DryConfigureDependencyReq): Promise<RR.DryConfigureDependencyRes> {
|
async dryConfigureDependency (params: RR.DryConfigureDependencyReq): Promise < RR.DryConfigureDependencyRes > {
|
||||||
return this.http.rpcRequest({ method: 'package.dependency.configure.dry', params })
|
return this.http.rpcRequest({ method: 'package.dependency.configure.dry', params })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -147,19 +147,8 @@ export class MockApiService extends ApiService {
|
|||||||
|
|
||||||
// marketplace URLs
|
// marketplace URLs
|
||||||
|
|
||||||
async setEosMarketplaceRaw (isTor: boolean): Promise<RR.SetEosMarketplaceRes> {
|
async marketplaceProxy (params) {
|
||||||
await pauseFor(2000)
|
return null
|
||||||
const params: RR.SetEosMarketplaceReq = {
|
|
||||||
url: isTor ? this.config.start9Marketplace.tor : this.config.start9Marketplace.clearnet,
|
|
||||||
}
|
|
||||||
const patch = [
|
|
||||||
{
|
|
||||||
op: PatchOp.REPLACE,
|
|
||||||
path: '/server-info/eos-marketplace',
|
|
||||||
value: params.url,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
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> {
|
||||||
|
|||||||
@@ -32,17 +32,4 @@ export abstract class MarketplaceApiService {
|
|||||||
abstract getReleaseNotes (params: RR.GetReleaseNotesReq): Promise<RR.GetReleaseNotesRes>
|
abstract getReleaseNotes (params: RR.GetReleaseNotesReq): Promise<RR.GetReleaseNotesRes>
|
||||||
|
|
||||||
abstract getLatestVersion (params: RR.GetLatestVersionReq): Promise<RR.GetLatestVersionRes>
|
abstract getLatestVersion (params: RR.GetLatestVersionReq): Promise<RR.GetLatestVersionRes>
|
||||||
|
|
||||||
getMarketplaceURL (type: 'eos' | 'package', defaultToTor = false): string {
|
|
||||||
const packageMarketplace = this.server['package-marketplace']
|
|
||||||
if (defaultToTor && !packageMarketplace) {
|
|
||||||
return this.config.start9Marketplace.tor
|
|
||||||
}
|
|
||||||
const eosMarketplace = this.server['eos-marketplace'] || this.config.start9Marketplace.clearnet
|
|
||||||
if (type === 'eos') {
|
|
||||||
return eosMarketplace
|
|
||||||
} else {
|
|
||||||
return packageMarketplace || eosMarketplace
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,71 +1,39 @@
|
|||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { HttpService, Method } from '../../http.service'
|
import { 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'
|
||||||
import { ConfigService } from '../../config.service'
|
import { ConfigService } from '../../config.service'
|
||||||
|
import { ApiService } from '../embassy/embassy-api.service'
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class MarketplaceLiveApiService extends MarketplaceApiService {
|
export class MarketplaceLiveApiService extends MarketplaceApiService {
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private readonly http: HttpService,
|
private readonly embassyApiService: ApiService,
|
||||||
config: ConfigService,
|
config: ConfigService,
|
||||||
patch: PatchDbService,
|
patch: PatchDbService,
|
||||||
) {
|
) {
|
||||||
super(config, patch)
|
super( config, patch)
|
||||||
}
|
}
|
||||||
|
|
||||||
async getEos (params: RR.GetMarketplaceEOSReq): Promise<RR.GetMarketplaceEOSRes> {
|
async getEos (params: RR.GetMarketplaceEOSReq): Promise<RR.GetMarketplaceEOSRes> {
|
||||||
const url = this.getMarketplaceURL('eos')
|
return this.embassyApiService.marketplaceProxy('/marketplace/eos', params)
|
||||||
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 > {
|
||||||
const url = this.getMarketplaceURL('package')
|
return this.embassyApiService.marketplaceProxy('/marketplace/package/data', params)
|
||||||
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)
|
return this.embassyApiService.marketplaceProxy('/marketplace/package/packages', { ...params, ids: JSON.stringify(params.ids) })
|
||||||
return this.http.httpRequest<RR.GetMarketplacePackagesRes>({
|
|
||||||
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 > {
|
||||||
const url = this.getMarketplaceURL('package')
|
return this.embassyApiService.marketplaceProxy('/marketplace/package/release-notes', params)
|
||||||
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)
|
return this.embassyApiService.marketplaceProxy('/marketplace/package/latest-version', params)
|
||||||
return this.http.httpRequest<RR.GetLatestVersionRes>({
|
|
||||||
method: Method.GET,
|
|
||||||
url: url + '/latest-version',
|
|
||||||
params,
|
|
||||||
withCredentials: false,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ 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, 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'
|
||||||
@@ -10,7 +9,6 @@ import { ConfigService } from '../../config.service'
|
|||||||
@Injectable()
|
@Injectable()
|
||||||
export class MarketplaceMockApiService extends MarketplaceApiService {
|
export class MarketplaceMockApiService extends MarketplaceApiService {
|
||||||
constructor (
|
constructor (
|
||||||
private readonly http: HttpService,
|
|
||||||
config: ConfigService,
|
config: ConfigService,
|
||||||
patch: PatchDbService,
|
patch: PatchDbService,
|
||||||
) {
|
) {
|
||||||
@@ -20,85 +18,32 @@ export class MarketplaceMockApiService extends MarketplaceApiService {
|
|||||||
// marketplace
|
// marketplace
|
||||||
|
|
||||||
async getEos (params: RR.GetMarketplaceEOSReq): Promise<RR.GetMarketplaceEOSRes> {
|
async getEos (params: RR.GetMarketplaceEOSReq): Promise<RR.GetMarketplaceEOSRes> {
|
||||||
const url = this.getMarketplaceURL('eos')
|
await pauseFor(2000)
|
||||||
if (this.useLocal(url)) {
|
return Mock.MarketplaceEos
|
||||||
await pauseFor(2000)
|
|
||||||
return Mock.MarketplaceEos
|
|
||||||
}
|
|
||||||
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> {
|
||||||
const url = this.getMarketplaceURL('package')
|
await pauseFor(2000)
|
||||||
if (this.useLocal(url)) {
|
return {
|
||||||
await pauseFor(2000)
|
categories: ['featured', 'bitcoin', 'lightning', 'data', 'messaging', 'social', 'alt coin'],
|
||||||
return {
|
|
||||||
categories: ['featured', 'bitcoin', 'lightning', 'data', 'messaging', 'social', 'alt coin'],
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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)
|
await pauseFor(2000)
|
||||||
if (this.useLocal(url)) {
|
return Mock.MarketplacePkgsList
|
||||||
await pauseFor(2000)
|
|
||||||
return Mock.MarketplacePkgsList
|
|
||||||
}
|
|
||||||
return this.http.httpRequest<RR.GetMarketplacePackagesRes>({
|
|
||||||
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> {
|
||||||
const url = this.getMarketplaceURL('package')
|
await pauseFor(2000)
|
||||||
if (this.useLocal(url)) {
|
return Mock.ReleaseNotes
|
||||||
await pauseFor(2000)
|
|
||||||
return Mock.ReleaseNotes
|
|
||||||
}
|
|
||||||
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)
|
await pauseFor(2000)
|
||||||
if (this.useLocal(url)) {
|
return params.ids.reduce((obj, id) => {
|
||||||
await pauseFor(2000)
|
obj[id] = this.patch.getData()['package-data']?.[id]?.manifest.version.replace('0', '1')
|
||||||
return params.ids.reduce((obj, id) => {
|
return obj
|
||||||
obj[id] = this.patch.getData()['package-data']?.[id]?.manifest.version.replace('0', '1')
|
}, { })
|
||||||
return obj
|
|
||||||
}, { })
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.http.httpRequest<RR.GetLatestVersionRes>({
|
|
||||||
method: Method.GET,
|
|
||||||
url: `${url}/latest-version`,
|
|
||||||
params,
|
|
||||||
withCredentials: false,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private useLocal (url: string): boolean {
|
|
||||||
return !url || this.config.mocks.marketplace
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { InterfaceDef, PackageDataEntry, PackageMainStatus, PackageState } from './patch-db/data-model'
|
import { InterfaceDef, PackageDataEntry, PackageMainStatus, PackageState } from './patch-db/data-model'
|
||||||
|
|
||||||
const { start9Marketplace, patchDb, api, mocks } = require('../../../config.json') as UiConfig
|
const { patchDb, api, mocks } = require('../../../config.json') as UiConfig
|
||||||
|
|
||||||
type UiConfig = {
|
type UiConfig = {
|
||||||
start9Marketplace: {
|
|
||||||
clearnet: string
|
|
||||||
tor: string
|
|
||||||
}
|
|
||||||
patchDb: {
|
patchDb: {
|
||||||
poll: {
|
poll: {
|
||||||
cooldown: number /* in ms */
|
cooldown: number /* in ms */
|
||||||
@@ -19,7 +15,6 @@ type UiConfig = {
|
|||||||
}
|
}
|
||||||
mocks: {
|
mocks: {
|
||||||
enabled: boolean
|
enabled: boolean
|
||||||
marketplace: boolean
|
|
||||||
connection: 'ws' | 'poll'
|
connection: 'ws' | 'poll'
|
||||||
rpcPort: number
|
rpcPort: number
|
||||||
wsPort: number
|
wsPort: number
|
||||||
@@ -35,7 +30,6 @@ export class ConfigService {
|
|||||||
origin = removePort(removeProtocol(window.origin))
|
origin = removePort(removeProtocol(window.origin))
|
||||||
version = require('../../../package.json').version
|
version = require('../../../package.json').version
|
||||||
|
|
||||||
start9Marketplace = start9Marketplace
|
|
||||||
patchDb = patchDb
|
patchDb = patchDb
|
||||||
api = api
|
api = api
|
||||||
mocks = mocks
|
mocks = mocks
|
||||||
|
|||||||
@@ -111,9 +111,9 @@ export class ServerConfigService {
|
|||||||
ssh: async (pubkey: string) => {
|
ssh: async (pubkey: string) => {
|
||||||
return this.sshService.add(pubkey)
|
return this.sshService.add(pubkey)
|
||||||
},
|
},
|
||||||
'eos-marketplace': async (enabled: boolean) => {
|
// 'eos-marketplace': async () => {
|
||||||
return this.embassyApi.setEosMarketplace(enabled)
|
// return this.embassyApi.setEosMarketplace()
|
||||||
},
|
// },
|
||||||
// 'package-marketplace': async (url: string) => {
|
// 'package-marketplace': async (url: string) => {
|
||||||
// return this.embassyApi.setPackageMarketplace({ url })
|
// return this.embassyApi.setPackageMarketplace({ url })
|
||||||
// },
|
// },
|
||||||
@@ -144,13 +144,13 @@ export const serverConfig: ConfigSpec = {
|
|||||||
masked: false,
|
masked: false,
|
||||||
copyable: false,
|
copyable: false,
|
||||||
},
|
},
|
||||||
'eos-marketplace': {
|
// 'eos-marketplace': {
|
||||||
type: 'boolean',
|
// type: 'boolean',
|
||||||
name: 'Tor Only Marketplace',
|
// name: 'Tor Only Marketplace',
|
||||||
description: `Use Start9's Tor (instead of clearnet) Marketplace.`,
|
// description: `Use Start9's Tor (instead of clearnet) Marketplace.`,
|
||||||
'change-warning': 'This will result in higher latency and slower download times.',
|
// 'change-warning': 'This will result in higher latency and slower download times.',
|
||||||
default: false,
|
// default: false,
|
||||||
},
|
// },
|
||||||
// 'package-marketplace': {
|
// 'package-marketplace': {
|
||||||
// type: 'string',
|
// type: 'string',
|
||||||
// name: 'Package Marketplace',
|
// name: 'Package Marketplace',
|
||||||
|
|||||||
Reference in New Issue
Block a user