From df4c92672f5c1f0013c8fd9789e869948062a5b4 Mon Sep 17 00:00:00 2001 From: Lucy <12953208+elvece@users.noreply.github.com> Date: Wed, 23 Apr 2025 09:17:46 -0400 Subject: [PATCH] Fix/os update version (#2890) * dynamically set a registry to use for os updates * fix os updates response type * fix saving high score --------- Co-authored-by: Matt Hill --- Makefile | 12 +- web/config-sample.json | 1 + web/package-lock.json | 11 +- .../shared/src/types/workspace-config.ts | 4 + .../system/routes/general/snek.directive.ts | 2 +- .../system/routes/general/update.component.ts | 6 +- .../ui/src/app/services/api/api.fixures.ts | 157 ++++++++++++++++-- .../ui/src/app/services/api/api.types.ts | 10 +- .../app/services/api/embassy-api.service.ts | 4 +- .../services/api/embassy-live-api.service.ts | 8 +- .../services/api/embassy-mock-api.service.ts | 6 +- .../ui/src/app/services/config.service.ts | 3 +- .../ui/src/app/services/os.service.ts | 8 +- 13 files changed, 184 insertions(+), 48 deletions(-) diff --git a/Makefile b/Makefile index 882d22047..d0daf1ad8 100644 --- a/Makefile +++ b/Makefile @@ -305,7 +305,17 @@ $(COMPRESSED_WEB_UIS): $(WEB_UIS) $(ENVIRONMENT_FILE) ./compress-uis.sh web/config.json: $(GIT_HASH_FILE) web/config-sample.json - jq '.useMocks = false' web/config-sample.json | jq '.gitHash = "$(shell cat GIT_HASH.txt)"' > web/config.json + @ver=$$(cat VERSION.txt); \ + case $$ver in \ + *alpha*) osUrl="https://alpha-registry-x.start9.com/" ;; \ + *beta*) osUrl="https://beta-registry.start9.com/" ;; \ + *) osUrl="https://registry.start9.com/" ;; \ + esac; \ + gitHash=$$(cat GIT_HASH.txt); \ + jq '.useMocks = false' web/config-sample.json \ + | jq --arg gitHash "$$gitHash" '.gitHash = $$gitHash' \ + | jq --arg osUrl "$$osUrl" '.ui.startosRegistry = $$osUrl' \ + > web/config.json; patch-db/client/node_modules/.package-lock.json: patch-db/client/package.json npm --prefix patch-db/client ci diff --git a/web/config-sample.json b/web/config-sample.json index b38effc8d..9dc0e2bf5 100644 --- a/web/config-sample.json +++ b/web/config-sample.json @@ -9,6 +9,7 @@ "start9": "https://registry.start9.com/", "community": "https://community-registry.start9.com/" }, + "startosRegistry": "https://registry.start9.com/", "mocks": { "maskAs": "tor", "maskAsHttps": true, diff --git a/web/package-lock.json b/web/package-lock.json index 404f4f0fb..291084dc0 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -123,15 +123,14 @@ "name": "@start9labs/start-sdk-base", "license": "MIT", "dependencies": { - "@iarna/toml": "^2.2.5", - "@noble/curves": "^1.4.0", - "@noble/hashes": "^1.4.0", + "@iarna/toml": "^3.0.0", + "@noble/curves": "^1.8.2", + "@noble/hashes": "^1.7.2", "deep-equality-data-structures": "^1.5.0", "isomorphic-fetch": "^3.0.0", - "lodash.merge": "^4.6.2", - "mime-types": "^2.1.35", + "mime-types": "^3.0.1", "ts-matches": "^6.2.1", - "yaml": "^2.2.2" + "yaml": "^2.7.1" }, "devDependencies": { "@types/jest": "^29.4.0", diff --git a/web/projects/shared/src/types/workspace-config.ts b/web/projects/shared/src/types/workspace-config.ts index c59f85ee5..eced51db1 100644 --- a/web/projects/shared/src/types/workspace-config.ts +++ b/web/projects/shared/src/types/workspace-config.ts @@ -8,6 +8,10 @@ export type WorkspaceConfig = { version: string } marketplace: MarketplaceConfig + startosRegistry: + | 'https://alpha-registry-x.start9.com/' + | 'https://beta-registry.start9.com/' + | 'https://registry.start9.com/' mocks: { maskAs: 'tor' | 'local' | 'localhost' | 'ipv4' | 'ipv6' | 'clearnet' maskAsHttps: boolean diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/general/snek.directive.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/general/snek.directive.ts index 423a5cb49..120970a80 100644 --- a/web/projects/ui/src/app/routes/portal/routes/system/routes/general/snek.directive.ts +++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/general/snek.directive.ts @@ -38,7 +38,7 @@ export class SnekDirective { try { await this.api.setDbValue( - ['gaming', 'snake', 'high-score'], + ['gaming', 'snake', 'highScore'], score, ) } catch (e: any) { diff --git a/web/projects/ui/src/app/routes/portal/routes/system/routes/general/update.component.ts b/web/projects/ui/src/app/routes/portal/routes/system/routes/general/update.component.ts index 98185636b..719ff0969 100644 --- a/web/projects/ui/src/app/routes/portal/routes/system/routes/general/update.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/system/routes/general/update.component.ts @@ -47,12 +47,12 @@ import { OSService } from 'src/app/services/os.service' ], }) export class SystemUpdateModal { - readonly versions = Object.entries(this.os.osUpdate?.releaseNotes!) + readonly versions = Object.entries(this.os.osUpdate!) .sort(([a], [b]) => a.localeCompare(b)) .reverse() - .map(([version, notes]) => ({ + .map(([version, info]) => ({ version, - notes, + notes: info.releaseNotes, })) constructor( diff --git a/web/projects/ui/src/app/services/api/api.fixures.ts b/web/projects/ui/src/app/services/api/api.fixures.ts index b7f1bbdaa..e77dab33b 100644 --- a/web/projects/ui/src/app/services/api/api.fixures.ts +++ b/web/projects/ui/src/app/services/api/api.fixures.ts @@ -30,23 +30,146 @@ export namespace Mock { shuttingDown: false, } - export const MarketplaceEos: RR.CheckOSUpdateRes = { - version: '0.3.6', - headline: 'Our biggest release ever.', - releaseNotes: { - '0.3.6': 'Some **Markdown** release _notes_ for 0.3.6', - '0.3.5.2': 'Some **Markdown** release _notes_ for 0.3.5.2', - '0.3.5.1': 'Some **Markdown** release _notes_ for 0.3.5.1', - '0.3.4.4': 'Some **Markdown** release _notes_ for 0.3.4.4', - '0.3.4.3': 'Some **Markdown** release _notes_ for 0.3.4.3', - '0.3.4.2': 'Some **Markdown** release _notes_ for 0.3.4.2', - '0.3.4.1': 'Some **Markdown** release _notes_ for 0.3.4.1', - '0.3.4': 'Some **Markdown** release _notes_ for 0.3.4', - '0.3.3': 'Some **Markdown** release _notes_ for 0.3.3', - '0.3.2.1': 'Some **Markdown** release _notes_ for 0.3.2.1', - '0.3.2': 'Some **Markdown** release _notes_ for 0.3.2', - '0.3.1': 'Some **Markdown** release _notes_ for 0.3.1', - '0.3.0': 'Some **Markdown** release _notes_ from a prior version', + export const RegistryOSUpdate: RR.GetRegistryOsUpdateRes = { + '0.3.6-alpha.17': { + headline: 'v0.3.6-alpha.17', + releaseNotes: '', + sourceVersion: '>=0.3.5:0 <=0.3.6-alpha.17:0', + authorized: ['G24CSA5HNYEPIXJNMK7ZM4KD5SX5N6X4'], + iso: {}, + squashfs: { + aarch64: { + publishedAt: '2025-03-21T23:55:29.583006392Z', + url: 'https://alpha-registry-x.start9.com/startos/v0.3.6-alpha.17/startos-0.3.6-alpha.17-b8ff331~dev_aarch64.squashfs', + commitment: { + hash: 'OUnANnZePtf7rSbj38JESl+iJAV0z0aiZ4opCiwpGbo=', + size: 1331900416, + }, + signatures: { + '-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAqPjOeMD2CB3UEASoICgfJlfrO5ygjOSBCCNRyDBs75A=\n-----END PUBLIC KEY-----\n': + '-----BEGIN SIGNATURE-----\nMEkwBQYDK2VwBEAMbmYB7TQknW7AdeasgNsqhWBVuRkYzrgZs7I1yHPHmLtMcNRo\nErEz7QKhKTgdzGn1FUQlHJh4GWGd8tkzCi8N\n-----END SIGNATURE-----\n', + }, + }, + 'aarch64-nonfree': { + publishedAt: '2025-03-21T23:56:38.299572946Z', + url: 'https://alpha-registry-x.start9.com/startos/v0.3.6-alpha.17/startos-0.3.6-alpha.17-b8ff331~dev_aarch64-nonfree.squashfs', + commitment: { + hash: '6k+0RcyRQV+5A+h06OqpHxd4IT6IlFkfdy9dfHIP90c=', + size: 1641500672, + }, + signatures: { + '-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAqPjOeMD2CB3UEASoICgfJlfrO5ygjOSBCCNRyDBs75A=\n-----END PUBLIC KEY-----\n': + '-----BEGIN SIGNATURE-----\nMEkwBQYDK2VwBEBEc2Vwxgf7Hxnm9GPlmc59DGRP6z0QyIQho7BlTSglXe3yz4FS\n8vtBGpOT9w0tRhZrWn5pInKr2R1OdGqoSosI\n-----END SIGNATURE-----\n', + }, + }, + raspberrypi: { + publishedAt: '2025-03-22T00:08:17.083064390Z', + url: 'https://alpha-registry-x.start9.com/startos/v0.3.6-alpha.17/startos-0.3.6-alpha.17-b8ff331~dev_raspberrypi.squashfs', + commitment: { + hash: 'K+XuTZxo1KVsKjNSV8PPOMruCvAEZwerF9mbpFl53Gk=', + size: 1544417280, + }, + signatures: { + '-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAqPjOeMD2CB3UEASoICgfJlfrO5ygjOSBCCNRyDBs75A=\n-----END PUBLIC KEY-----\n': + '-----BEGIN SIGNATURE-----\nMEkwBQYDK2VwBEAA07qx3oBE23A4XSRs5nRm4pCT534+wMwfozy0dEVdIwJ4tIWn\nnWhREVWXPJjmh5haoF+U4fISBbFKgJZhWbkD\n-----END SIGNATURE-----\n', + }, + }, + x86_64: { + publishedAt: '2025-03-22T00:05:57.684319247Z', + url: 'https://alpha-registry-x.start9.com/startos/v0.3.6-alpha.17/startos-0.3.6-alpha.17-b8ff331~dev_x86_64.squashfs', + commitment: { + hash: '3UVkx3TQMBPlSU1OnV48Om9vjjA3s+Nk6dX3auYGpBo=', + size: 1424007168, + }, + signatures: { + '-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAqPjOeMD2CB3UEASoICgfJlfrO5ygjOSBCCNRyDBs75A=\n-----END PUBLIC KEY-----\n': + '-----BEGIN SIGNATURE-----\nMEkwBQYDK2VwBEDuGbncT5wcXd26p8ieqZyDQKmAcWKx/gP90i2GMNXgCf9L4jA4\nTz+B5PqC6kljRstyT1600wL3R02+fRpqkAUH\n-----END SIGNATURE-----\n', + }, + }, + 'x86_64-nonfree': { + publishedAt: '2025-03-22T00:07:11.893777122Z', + url: 'https://alpha-registry-x.start9.com/startos/v0.3.6-alpha.17/startos-0.3.6-alpha.17-b8ff331~dev_x86_64-nonfree.squashfs', + commitment: { + hash: 'IS1gJ56n/HlQqFbl1upMOAtLxyxB0cY0H89Ha+9h1lE=', + size: 1743425536, + }, + signatures: { + '-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAqPjOeMD2CB3UEASoICgfJlfrO5ygjOSBCCNRyDBs75A=\n-----END PUBLIC KEY-----\n': + '-----BEGIN SIGNATURE-----\nMEkwBQYDK2VwBEBOt5QUnB6XA2kOph45ARpAN9vlftX29Ic/8/Wcp4TmBQz3A+be\n5zGqW1Gvm4eoyocL+PjibxPYXS6kcC8O9YUA\n-----END SIGNATURE-----\n', + }, + }, + }, + img: {}, + }, + '0.4.0-alpha.0': { + headline: 'v0.4.0-alpha.0', + releaseNotes: '', + sourceVersion: '>=0.3.5:0 <=0.4.0-alpha.0:0', + authorized: ['G24CSA5HNYEPIXJNMK7ZM4KD5SX5N6X4'], + iso: {}, + squashfs: { + aarch64: { + publishedAt: '2025-04-21T20:58:48.140749883Z', + url: 'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.0/startos-0.4.0-alpha.0-33ae46f~dev_aarch64.squashfs', + commitment: { + hash: '4elBFVkd/r8hNadKmKtLIs42CoPltMvKe2z3LRqkphk=', + size: 1343500288, + }, + signatures: { + '-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAqPjOeMD2CB3UEASoICgfJlfrO5ygjOSBCCNRyDBs75A=\n-----END PUBLIC KEY-----\n': + '-----BEGIN SIGNATURE-----\nMEkwBQYDK2VwBEAQlzQCZ07nY4REcknK3aZWtHlcAwSzV+Pae/5wb6ijV/utaNWu\n3BPWtKZFrS8K8fCfDmCHgFScLJCLUk4GwKoI\n-----END SIGNATURE-----\n', + }, + }, + 'aarch64-nonfree': { + publishedAt: '2025-04-21T21:07:00.249285116Z', + url: 'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.0/startos-0.4.0-alpha.0-33ae46f~dev_aarch64-nonfree.squashfs', + commitment: { + hash: 'MrCEi4jxbmPS7zAiGk/JSKlMsiuKqQy6RbYOxlGHOIQ=', + size: 1653075968, + }, + signatures: { + '-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAqPjOeMD2CB3UEASoICgfJlfrO5ygjOSBCCNRyDBs75A=\n-----END PUBLIC KEY-----\n': + '-----BEGIN SIGNATURE-----\nMEkwBQYDK2VwBECg1u7PoQAuTvSjtVNGZz0tpZOV8TC0P8xpNSQacGfcklSGN5OT\nsmtu/E+z/o4c9mWa3h9QB4jRTWyYpz49H+gJ\n-----END SIGNATURE-----\n', + }, + }, + raspberrypi: { + publishedAt: '2025-04-21T21:16:12.933319237Z', + url: 'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.0/startos-0.4.0-alpha.0-33ae46f~dev_raspberrypi.squashfs', + commitment: { + hash: '/XTVQRCqY3RK544PgitlKu7UplXjkmzWoXUh2E4HCw0=', + size: 1490731008, + }, + signatures: { + '-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAqPjOeMD2CB3UEASoICgfJlfrO5ygjOSBCCNRyDBs75A=\n-----END PUBLIC KEY-----\n': + '-----BEGIN SIGNATURE-----\nMEkwBQYDK2VwBEDQAJaxCtyZSzUQ+oBB2TP9ctf7AyBD659vkhHVct7DTM+ZUqjm\ncCbUMV77PNlGFmDJEJ9kaGq8LmLMD467zqMA\n-----END SIGNATURE-----\n', + }, + }, + x86_64: { + publishedAt: '2025-04-21T21:14:20.246908903Z', + url: 'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.0/startos-0.4.0-alpha.0-33ae46f~dev_x86_64.squashfs', + commitment: { + hash: '/6romKTVQGSaOU7FqSZdw0kFyd7P+NBSYNwM3q7Fe44=', + size: 1411657728, + }, + signatures: { + '-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAqPjOeMD2CB3UEASoICgfJlfrO5ygjOSBCCNRyDBs75A=\n-----END PUBLIC KEY-----\n': + '-----BEGIN SIGNATURE-----\nMEkwBQYDK2VwBECWOeNTSyjYn2D5FLtyEtjfUbmNPB/vnGFfc3WK+HfuUvZrZEGj\n1bCdShp/4kuLrqEjasonSJTXUQfAJ1NT4gkA\n-----END SIGNATURE-----\n', + }, + }, + 'x86_64-nonfree': { + publishedAt: '2025-04-21T21:15:17.955265284Z', + url: 'https://alpha-registry-x.start9.com/startos/v0.4.0-alpha.0/startos-0.4.0-alpha.0-33ae46f~dev_x86_64-nonfree.squashfs', + commitment: { + hash: 'HCRq9sr/0t85pMdrEgNBeM4x11zVKHszGnD1GDyZbSE=', + size: 1731035136, + }, + signatures: { + '-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAqPjOeMD2CB3UEASoICgfJlfrO5ygjOSBCCNRyDBs75A=\n-----END PUBLIC KEY-----\n': + '-----BEGIN SIGNATURE-----\nMEkwBQYDK2VwBECMvpyxKmTCzv+1Dlk28TSzyjCCb6+QNaXNA01rl4OHTN3YcqAQ\n4ubS89dDDoiOkxXv0J+aImG94SUqrSWXglYI\n-----END SIGNATURE-----\n', + }, + }, + }, + img: {}, }, } diff --git a/web/projects/ui/src/app/services/api/api.types.ts b/web/projects/ui/src/app/services/api/api.types.ts index 50ef1826a..8c696b1f4 100644 --- a/web/projects/ui/src/app/services/api/api.types.ts +++ b/web/projects/ui/src/app/services/api/api.types.ts @@ -362,16 +362,8 @@ export namespace RR { // registry /** these are returned in ASCENDING order. the newest available version will be the LAST in the object */ - export type GetRegistryOsUpdateRes = { [version: string]: T.OsVersionInfo } - export type CheckOSUpdateReq = { serverId: string } - export type CheckOSUpdateRes = OSUpdate -} - -export type OSUpdate = { - version: string - headline: string - releaseNotes: { [version: string]: string } + export type GetRegistryOsUpdateRes = { [version: string]: T.OsVersionInfo } } export type Breakages = { diff --git a/web/projects/ui/src/app/services/api/embassy-api.service.ts b/web/projects/ui/src/app/services/api/embassy-api.service.ts index 0cd79b9eb..2aec7d40d 100644 --- a/web/projects/ui/src/app/services/api/embassy-api.service.ts +++ b/web/projects/ui/src/app/services/api/embassy-api.service.ts @@ -150,7 +150,9 @@ export abstract class ApiService { options: RPCOptions, ): Promise - abstract checkOSUpdate(qp: RR.CheckOSUpdateReq): Promise + abstract checkOSUpdate( + qp: RR.CheckOSUpdateReq, + ): Promise abstract getRegistryInfo(registryUrl: string): Promise diff --git a/web/projects/ui/src/app/services/api/embassy-live-api.service.ts b/web/projects/ui/src/app/services/api/embassy-live-api.service.ts index e3003a5da..2fc56270c 100644 --- a/web/projects/ui/src/app/services/api/embassy-live-api.service.ts +++ b/web/projects/ui/src/app/services/api/embassy-live-api.service.ts @@ -250,7 +250,7 @@ export class LiveApiService extends ApiService { async updateServer(url?: string): Promise { const params = { - registry: url || this.config.marketplace.start9, + registry: url || this.config.startosRegistry, } return this.rpcRequest({ method: 'server.update', params }) } @@ -294,10 +294,12 @@ export class LiveApiService extends ApiService { }) } - async checkOSUpdate(qp: RR.CheckOSUpdateReq): Promise { + async checkOSUpdate( + qp: RR.CheckOSUpdateReq, + ): Promise { const { serverId } = qp - return this.registryRequest(this.config.marketplace.start9, { + return this.registryRequest(this.config.startosRegistry, { method: 'os.version.get', params: { serverId }, }) diff --git a/web/projects/ui/src/app/services/api/embassy-mock-api.service.ts b/web/projects/ui/src/app/services/api/embassy-mock-api.service.ts index 395aa126a..458cd309e 100644 --- a/web/projects/ui/src/app/services/api/embassy-mock-api.service.ts +++ b/web/projects/ui/src/app/services/api/embassy-mock-api.service.ts @@ -484,9 +484,11 @@ export class MockApiService extends ApiService { return Error('do not call directly') } - async checkOSUpdate(qp: RR.CheckOSUpdateReq): Promise { + async checkOSUpdate( + qp: RR.CheckOSUpdateReq, + ): Promise { await pauseFor(2000) - return Mock.MarketplaceEos + return Mock.RegistryOSUpdate } async getRegistryInfo(registryUrl: string): Promise { diff --git a/web/projects/ui/src/app/services/config.service.ts b/web/projects/ui/src/app/services/config.service.ts index 9f2fa11a0..2ed5b8eaf 100644 --- a/web/projects/ui/src/app/services/config.service.ts +++ b/web/projects/ui/src/app/services/config.service.ts @@ -7,7 +7,7 @@ import { PackageDataEntry } from './patch-db/data-model' const { gitHash, useMocks, - ui: { api, marketplace, mocks }, + ui: { api, marketplace, mocks, startosRegistry }, } = require('../../../../../config.json') as WorkspaceConfig @Injectable({ @@ -27,6 +27,7 @@ export class ConfigService { gitHash = gitHash api = api marketplace = marketplace + startosRegistry = startosRegistry skipStartupAlerts = useMocks && mocks.skipStartupAlerts supportsWebSockets = !!window.WebSocket diff --git a/web/projects/ui/src/app/services/os.service.ts b/web/projects/ui/src/app/services/os.service.ts index 95d859b90..f88d558e9 100644 --- a/web/projects/ui/src/app/services/os.service.ts +++ b/web/projects/ui/src/app/services/os.service.ts @@ -1,17 +1,17 @@ import { Injectable } from '@angular/core' import { PatchDB } from 'patch-db-client' import { BehaviorSubject, distinctUntilChanged, map, combineLatest } from 'rxjs' -import { OSUpdate } from 'src/app/services/api/api.types' import { ApiService } from 'src/app/services/api/embassy-api.service' import { getServerInfo } from 'src/app/utils/get-server-info' import { DataModel } from './patch-db/data-model' import { Version } from '@start9labs/start-sdk' +import { RR } from './api/api.types' @Injectable({ providedIn: 'root', }) export class OSService { - osUpdate?: OSUpdate + osUpdate?: RR.GetRegistryOsUpdateRes updateAvailable$ = new BehaviorSubject(false) readonly updating$ = this.patch.watch$('serverInfo', 'statusInfo').pipe( @@ -48,9 +48,9 @@ export class OSService { async loadOS(): Promise { const { version, id } = await getServerInfo(this.patch) this.osUpdate = await this.api.checkOSUpdate({ serverId: id }) + const [latestVersion, _] = Object.entries(this.osUpdate).at(-1)! const updateAvailable = - Version.parse(this.osUpdate.version).compare(Version.parse(version)) === - 'greater' + Version.parse(latestVersion).compare(Version.parse(version)) === 'greater' this.updateAvailable$.next(updateAvailable) } }