marketplace updates

This commit is contained in:
Drew Ansbacher
2021-07-16 12:46:27 -06:00
committed by Aiden McClelland
parent 301a19d644
commit 203eff7758
14 changed files with 164 additions and 99 deletions

View File

@@ -8,10 +8,10 @@
</ion-header>
<ion-content>
<ion-spinner *ngIf="!marketplaceService.pkgs[pkgId]; else loaded" class="center" name="lines" color="warning"></ion-spinner>
<ion-spinner *ngIf="!marketplaceService.releaseNotes[pkgId]; else loaded" class="center" name="lines" color="warning"></ion-spinner>
<ng-template #loaded>
<div *ngFor="let note of marketplaceService.pkgs[pkgId]['release-notes'] | keyvalue : asIsOrder">
<div *ngFor="let note of marketplaceService.releaseNotes[pkgId] | keyvalue : asIsOrder">
<ion-button (click)="setSelected(note.key)" expand="full" color="light" style="height: 50px;" >
<p style="position: absolute; left: 10px;">{{ note.key | displayEmver }}</p>
</ion-button>

View File

@@ -20,9 +20,8 @@ export class AppReleaseNotes {
ngOnInit () {
this.pkgId = this.route.snapshot.paramMap.get('pkgId')
const version = this.route.snapshot.paramMap.get('version')
if (!this.marketplaceService.pkgs[this.pkgId]?.['release-notes']) {
this.marketplaceService.getPkg(this.pkgId, version)
if (!this.marketplaceService.releaseNotes[this.pkgId]) {
this.marketplaceService.getReleaseNotes(this.pkgId)
}
}

View File

@@ -20,7 +20,7 @@ export class MarketplaceListPage {
pageLoading = true
pkgsLoading = true
category = 'all'
category = 'featured'
query: string
data: MarketplaceData
@@ -47,15 +47,19 @@ export class MarketplaceListPage {
async ngOnInit () {
try {
const [data, eos, pkgs] = await Promise.all([
const [data, eos] = await Promise.all([
this.marketplaceApiService.getMarketplaceData({ }),
this.marketplaceApiService.getEos({ }),
this.getPkgs(),
])
this.data = data
this.data.categories.unshift(this.category)
this.data.categories.push(this.category)
this.data.categories.unshift('updates')
if (data.categories.includes(this.category)) {
data.categories = data.categories.filter(cat => this.category !== cat)
}
data.categories.unshift(this.category)
this.eos = eos
this.pkgs = pkgs
} catch (e) {
console.error(e)
this.errToast.present(e.message)
@@ -74,8 +78,7 @@ export class MarketplaceListPage {
}
async doInfinite (e: any): Promise<void> {
const pkgs = await this.getPkgs()
this.pkgs = this.pkgs.concat(pkgs)
await this.getPkgs(true)
e.target.complete()
}
@@ -83,7 +86,7 @@ export class MarketplaceListPage {
this.query = e.target.value || undefined
this.page = 1
this.pkgsLoading = true
this.pkgs = await this.getPkgs()
await this.getPkgs()
}
async updateEos (): Promise<void> {
@@ -97,17 +100,26 @@ export class MarketplaceListPage {
)
}
private async getPkgs (): Promise<MarketplacePkg[]> {
private async getPkgs (doInfinite = false): Promise<void> {
try {
const pkgs = await this.marketplaceService.getPkgs(
this.category !== 'all' ? this.category : undefined,
this.query,
this.page,
this.perPage,
)
this.needInfinite = pkgs.length >= this.perPage
this.page++
return pkgs
if (this.category === 'updates') {
this.pkgs = this.marketplaceService.updates
if (this.pkgs.length) {
this.pkgsLoading = false
}
await this.marketplaceService.getUpdates(this.patch.data['package-data'])
this.pkgs = this.marketplaceService.updates
} else {
const pkgs = await this.marketplaceService.getPkgs(
this.category !== 'all' ? this.category : undefined,
this.query,
this.page,
this.perPage,
)
this.needInfinite = pkgs.length >= this.perPage
this.page++
this.pkgs = doInfinite ? this.pkgs.concat(pkgs) : pkgs
}
} catch (e) {
console.error(e)
this.errToast.present(e.message)
@@ -117,9 +129,10 @@ export class MarketplaceListPage {
}
async switchCategory (category: string): Promise<void> {
this.pkgs = []
this.category = category
this.pkgsLoading = true
this.page = 1
this.pkgs = await this.getPkgs()
await this.getPkgs()
}
}

View File

@@ -1,20 +1,41 @@
import { Injectable } from '@angular/core'
import { MarketplacePkg } from 'src/app/services/api/api.types'
import { MarketplaceApiService } from 'src/app/services/api/marketplace/marketplace-api.service'
import { Emver } from 'src/app/services/emver.service'
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
@Injectable({
providedIn: 'root',
})
export class MarketplaceService {
pkgs: { [id: string]: MarketplacePkg } = { }
updates: MarketplacePkg[] = null
releaseNotes: { [id: string]: {
[version: string]: string
} }
constructor (
private readonly marketplaceApiService: MarketplaceApiService,
private readonly emver: Emver,
) { }
async getUpdates (pkgData: { [id: string]: PackageDataEntry}) : Promise<MarketplacePkg[]> {
const idAndCurrentVersions = Object.keys(pkgData).map(key => ({ id: key, version: pkgData[key].manifest.version }))
console.log(JSON.stringify(idAndCurrentVersions))
const latestPkgs = (await this.marketplaceApiService.getMarketplacePkgs({
ids: idAndCurrentVersions,
}))
const updates = latestPkgs.filter(latestPkg => {
const latestVersion = latestPkg.manifest.version
const curVersion = pkgData[latestPkg.manifest.id]?.manifest.version
return !!curVersion && this.emver.compare(latestVersion, curVersion) === 1
})
this.updates = updates
return updates
}
async getPkgs (category: string, query: string, page: number, perPage: number) : Promise<MarketplacePkg[]> {
const pkgs = await this.marketplaceApiService.getMarketplacePkgs({
category: category !== 'all' ? category : undefined,
@@ -30,7 +51,7 @@ export class MarketplaceService {
}
async getPkg (id: string, version?: string): Promise<void> {
const pkg = (await this.marketplaceApiService.getMarketplacePkgs({ id, version }))[0]
const pkg = (await this.marketplaceApiService.getMarketplacePkgs({ ids: [{ id, version }]}))[0]
if (pkg) {
this.pkgs[id] = pkg
} else {

View File

@@ -15,20 +15,20 @@
<ion-label>Use Tor</ion-label>
<ion-note slot="end">{{ patch.data['server-info']['eos-marketplace'] === config.start9Marketplace.tor }}</ion-note>
</ion-item>
<ion-item button (click)="presentModalValueEdit('packageMarketplace', patch.data['server-info']['package-marketplace'])">
<!-- <ion-item button (click)="presentModalValueEdit('packageMarketplace', patch.data['server-info']['package-marketplace'])">
<ion-label>Package Marketplace</ion-label>
<ion-note slot="end">{{ patch.data['server-info']['package-marketplace'] }}</ion-note>
</ion-item>
</ion-item> -->
<ion-item button (click)="presentModalValueEdit('autoCheckUpdates', patch.data.ui['auto-check-updates'])">
<ion-label>Auto Check for Updates</ion-label>
<ion-note slot="end">{{ patch.data.ui['auto-check-updates'] }}</ion-note>
</ion-item>
<ion-item-divider></ion-item-divider>
<!-- <ion-item-divider></ion-item-divider>
<ion-item button (click)="presentModalValueEdit('password')">
<ion-label>Change Password</ion-label>
<ion-note slot="end">********</ion-note>
</ion-item>
</ion-item> -->
</ion-item-group>
</ion-content>

View File

@@ -168,10 +168,7 @@ export module RR {
export type GetMarketplaceEOSRes = MarketplaceEOS
export type GetMarketplacePackagesReq = {
ids?: string[]
id?: string
// iff id
version?: string
ids?: { id: string, version: string }[]
// iff !id
category?: string
query?: string
@@ -182,13 +179,17 @@ export module RR {
export type GetReleaseNotesReq = { id: string }
export type GetReleaseNotesRes = { [version: string]: string}
export type GetLatestVersionReq = { ids: string[] }
export type GetLatestVersionRes = { [id: string]: string}
}
export type WithExpire<T> = { 'expire-id'?: string } & T
export type WithRevision<T> = { response: T, revision?: Revision }
export interface MarketplaceData {
categories: string[]
categories: string[],
}
export interface MarketplaceEOS {

View File

@@ -60,10 +60,10 @@ export abstract class ApiService implements Source<DataModel>, Http<DataModel> {
() => this.setEosMarketplaceRaw(isTor),
)()
protected abstract setPackageMarketplaceRaw (params: RR.SetPackageMarketplaceReq): Promise<RR.SetPackageMarketplaceRes>
setPackageMarketplace = (params: RR.SetPackageMarketplaceReq) => this.syncResponse(
() => this.setPackageMarketplaceRaw(params),
)()
// protected abstract setPackageMarketplaceRaw (params: RR.SetPackageMarketplaceReq): Promise<RR.SetPackageMarketplaceRes>
// setPackageMarketplace = (params: RR.SetPackageMarketplaceReq) => this.syncResponse(
// () => this.setPackageMarketplaceRaw(params),
// )()
// password
abstract updatePassword (params: RR.UpdatePasswordReq): Promise<RR.UpdatePasswordRes>

View File

@@ -78,9 +78,9 @@ export class LiveApiService extends ApiService {
return this.http.rpcRequest({ method: 'marketplace.eos.set', params })
}
async setPackageMarketplaceRaw (params: RR.SetPackageMarketplaceReq): Promise<RR.SetPackageMarketplaceRes> {
return this.http.rpcRequest({ method: 'marketplace.package.set', params })
}
// async setPackageMarketplaceRaw (params: RR.SetPackageMarketplaceReq): Promise<RR.SetPackageMarketplaceRes> {
// return this.http.rpcRequest({ method: 'marketplace.package.set', params })
// }
// password
async updatePassword (params: RR.UpdatePasswordReq): Promise<RR.UpdatePasswordRes> {

View File

@@ -138,17 +138,17 @@ export class MockApiService extends ApiService {
return this.http.rpcRequest({ method: 'db.patch', params: { patch } })
}
async setPackageMarketplaceRaw (params: RR.SetPackageMarketplaceReq): Promise<RR.SetPackageMarketplaceRes> {
await pauseFor(2000)
const patch = [
{
op: PatchOp.REPLACE,
path: '/server-info/package-marketplace',
value: params.url,
},
]
return this.http.rpcRequest({ method: 'db.patch', params: { patch } })
}
// async setPackageMarketplaceRaw (params: RR.SetPackageMarketplaceReq): Promise<RR.SetPackageMarketplaceRes> {
// await pauseFor(2000)
// const patch = [
// {
// op: PatchOp.REPLACE,
// path: '/server-info/package-marketplace',
// value: params.url,
// },
// ]
// return this.http.rpcRequest({ method: 'db.patch', params: { patch } })
// }
// password
async updatePassword (params: RR.UpdatePasswordReq): Promise<RR.UpdatePasswordRes> {

View File

@@ -17,12 +17,17 @@ export abstract class MarketplaceApiService {
abstract getReleaseNotes (params: RR.GetReleaseNotesReq): Promise<RR.GetReleaseNotesRes>
getMarketplaceURL (type: 'eos' | 'package'): string {
abstract getLatestVersion (params: RR.GetLatestVersionReq): Promise<RR.GetLatestVersionRes>
getMarketplaceURL (type: 'eos' | 'package', defaultToTor = false): string {
const packageMarketplace = this.patch.data['server-info']['package-marketplace']
if (defaultToTor && !packageMarketplace) {
return this.config.start9Marketplace.tor
}
const eosMarketplace = this.patch.data['server-info']['eos-marketplace'] || this.config.start9Marketplace.clearnet
if (type === 'eos') {
return eosMarketplace
} else {
const packageMarketplace = this.patch.data['server-info']['package-marketplace']
return packageMarketplace || eosMarketplace
}
}

View File

@@ -25,10 +25,21 @@ export class MarketplaceLiveApiService extends MarketplaceApiService {
}
async getMarketplacePkgs (params: RR.GetMarketplacePackagesReq): Promise<RR.GetMarketplacePackagesRes> {
return this.http.simpleGet<RR.GetMarketplacePackagesRes>(this.getMarketplaceURL('package'), params)
const url = this.getMarketplaceURL('package', params.ids?.length > 1)
const threadParams = {
...params,
ids: JSON.stringify(params.ids),
}
return this.http.simpleGet<RR.GetMarketplacePackagesRes>(url, threadParams)
}
async getReleaseNotes (params: RR.GetReleaseNotesReq): Promise<RR.GetReleaseNotesRes> {
return this.http.simpleGet<RR.GetReleaseNotesRes>(this.getMarketplaceURL('package'), params)
}
async getLatestVersion (params: RR.GetLatestVersionReq): Promise<RR.GetLatestVersionRes> {
const url = this.getMarketplaceURL('package', params.ids?.length > 1)
return this.http.simpleGet<RR.GetLatestVersionRes>(url, params)
}
}

View File

@@ -6,9 +6,11 @@ import { HttpService } from '../../http.service'
import { MarketplaceApiService } from './marketplace-api.service'
import { PatchDbService } from '../../patch-db/patch-db.service'
import { ConfigService } from '../../config.service'
import { Storage } from '@ionic/storage'
@Injectable()
export class MarketplaceMockApiService extends MarketplaceApiService {
CONTENT_KEY = 'marketplace-cache'
constructor (
private readonly http: HttpService,
@@ -38,18 +40,22 @@ export class MarketplaceMockApiService extends MarketplaceApiService {
categories: ['featured', 'bitcoin', 'lightning', 'data', 'messaging', 'social', 'alt coin'],
}
}
url = `${url}/marketplace/data`
url = `${url}/data`
return this.http.simpleGet<RR.GetMarketplaceDataRes>(url)
}
async getMarketplacePkgs (params: RR.GetMarketplacePackagesReq): Promise<RR.GetMarketplacePackagesRes> {
let url = this.getMarketplaceURL('package')
let url = this.getMarketplaceURL('package', params.ids?.length > 1)
const threadParams = {
...params,
ids: JSON.stringify(params.ids),
}
if (this.useLocal(url)) {
await pauseFor(2000)
return Mock.AvailableList
}
url = `${url}/marketplace/packages`
return this.http.simpleGet<RR.GetMarketplacePackagesRes>(url, params)
url = `${url}/packages`
return this.http.simpleGet<RR.GetMarketplacePackagesRes>(url, threadParams)
}
async getReleaseNotes (params: RR.GetReleaseNotesReq): Promise<RR.GetReleaseNotesRes> {
@@ -58,8 +64,21 @@ export class MarketplaceMockApiService extends MarketplaceApiService {
await pauseFor(2000)
return Mock.ReleaseNotes
}
url = `${url}/marketplace/release-notes`
return this.http.simpleGet<RR.GetReleaseNotesRes>(url)
url = `${url}/release-notes`
return this.http.simpleGet<RR.GetReleaseNotesRes>(url, params)
}
async getLatestVersion (params: RR.GetLatestVersionReq): Promise<RR.GetLatestVersionRes> {
let url = this.getMarketplaceURL('package', params.ids?.length > 1)
if (this.useLocal(url)) {
await pauseFor(2000)
return params.ids.reduce((obj, id) => {
obj[id] = this.patch.data['package-data']?.[id]?.manifest.version.replace('0', '1')
return obj
}, { })
}
url = `${url}/latest-version`
return this.http.simpleGet<RR.GetLatestVersionRes>(url)
}
private useLocal (url: string): boolean {

View File

@@ -43,12 +43,12 @@ export class ServerConfigService {
eosMarketplace: async (enabled: boolean) => {
return this.apiService.setEosMarketplace(enabled)
},
packageMarketplace: async (url: string) => {
return this.apiService.setPackageMarketplace({ url })
},
password: async (password: string) => {
return this.apiService.updatePassword({ password })
},
// packageMarketplace: async (url: string) => {
// return this.apiService.setPackageMarketplace({ url })
// },
// password: async (password: string) => {
// return this.apiService.updatePassword({ password })
// },
}
}
@@ -76,27 +76,27 @@ const serverConfig: ConfigSpec = {
description: `Use Start9's Tor Hidden Service Marketplace (instead of clearnet).`,
default: false,
},
packageMarketplace: {
type: 'string',
name: 'Package Marketplace',
description: `Use for alternative embassy marketplace. Leave empty to use start9's marketplace.`,
nullable: true,
// @TODO regex for URL
// pattern: '',
patternDescription: 'Must be a valid URL.',
masked: false,
copyable: false,
},
password: {
type: 'string',
name: 'Change Password',
description: `Your Embassy's master password, used for authentication and disk encryption.`,
nullable: false,
// @TODO regex for 12 chars
// pattern: '',
patternDescription: 'Must contain at least 12 characters.',
changeWarning: 'If you forget your master password, there is absolutely no way to recover your data. This can result in loss of money! Keep in mind, old backups will still be encrypted by the password used to encrypt them.',
masked: false,
copyable: false,
},
// packageMarketplace: {
// type: 'string',
// name: 'Package Marketplace',
// description: `Use for alternative embassy marketplace. Leave empty to use start9's marketplace.`,
// nullable: true,
// // @TODO regex for URL
// // pattern: '',
// patternDescription: 'Must be a valid URL.',
// masked: false,
// copyable: false,
// },
// password: {
// type: 'string',
// name: 'Change Password',
// description: `Your Embassy's master password, used for authentication and disk encryption.`,
// nullable: false,
// // @TODO regex for 12 chars
// // pattern: '',
// patternDescription: 'Must contain at least 12 characters.',
// changeWarning: 'If you forget your master password, there is absolutely no way to recover your data. This can result in loss of money! Keep in mind, old backups will still be encrypted by the password used to encrypt them.',
// masked: false,
// copyable: false,
// },
}

View File

@@ -5,10 +5,11 @@ import { WizardBaker } from '../components/install-wizard/prebaked-wizards'
import { OSWelcomePage } from '../modals/os-welcome/os-welcome.page'
import { displayEmver } from '../pipes/emver.pipe'
import { RR } from './api/api.types'
import { MarketplaceApiService } from './api/marketplace/marketplace-api.service'
import { PatchDbService } from './patch-db/patch-db.service'
import { ConfigService } from './config.service'
import { Emver } from './emver.service'
import { MarketplaceService } from '../pages/marketplace-routes/marketplace.service'
import { MarketplaceApiService } from './api/marketplace/marketplace-api.service'
@Injectable({
providedIn: 'root',
@@ -21,6 +22,7 @@ export class StartupAlertsService {
private readonly navCtrl: NavController,
private readonly config: ConfigService,
private readonly modalCtrl: ModalController,
private readonly marketplaceService: MarketplaceService,
private readonly marketplaceApi: MarketplaceApiService,
private readonly emver: Emver,
private readonly wizardBaker: WizardBaker,
@@ -63,6 +65,7 @@ export class StartupAlertsService {
let checkRes: any
try {
checkRes = await c.check()
console.log('CHECK RES', checkRes)
} catch (e) {
console.error(`Exception in ${c.name} check:`, e)
return true
@@ -99,15 +102,8 @@ export class StartupAlertsService {
}
private async appsCheck (): Promise<boolean> {
const pkgs = await this.marketplaceApi.getMarketplacePkgs({
ids: Object.keys(this.patch.data['package-data']).filter(id => {
return !!this.patch.data['package-data'][id].installed
}),
})
return !!pkgs.find(pkg => {
const versionInstalled = this.patch.data['package-data'][pkg.manifest.id].manifest.version
return this.emver.compare(versionInstalled, pkg.manifest.version) === -1
})
const updates = await this.marketplaceService.getUpdates(this.patch.data['package-data'])
return !!updates.length
}
private async displayOsWelcome (): Promise<boolean> {