From fba1484e2e83b91630f8845cf201d48a6317e27d Mon Sep 17 00:00:00 2001 From: J H Date: Mon, 25 Mar 2024 11:07:59 -0600 Subject: [PATCH 1/3] fix: Bringing in a building for the browser --- sdk/lib/index.browser.ts | 14 ++++++++++++++ sdk/lib/index.ts | 1 + sdk/lib/util/index.browser.ts | 25 +++++++++++++++++++++++++ sdk/package-lock.json | 12 +++++++----- sdk/package.json | 14 ++++---------- web/package-lock.json | 8 ++++---- 6 files changed, 55 insertions(+), 19 deletions(-) create mode 100644 sdk/lib/index.browser.ts create mode 100644 sdk/lib/util/index.browser.ts diff --git a/sdk/lib/index.browser.ts b/sdk/lib/index.browser.ts new file mode 100644 index 000000000..ff422a7f2 --- /dev/null +++ b/sdk/lib/index.browser.ts @@ -0,0 +1,14 @@ +export { EmVer } from "./emverLite/mod" +export { setupManifest } from "./manifest/setupManifest" +export { setupExposeStore } from "./store/setupExposeStore" +export * as config from "./config" +export * as CB from "./config/builder" +export * as CT from "./config/configTypes" +export * as dependencyConfig from "./dependencyConfig" +export * as manifest from "./manifest" +export * as types from "./types" +export * as T from "./types" +export * as yaml from "yaml" +export * as matches from "ts-matches" + +export * as util from "./util/index.browser" diff --git a/sdk/lib/index.ts b/sdk/lib/index.ts index e89d45457..2fef6a4fa 100644 --- a/sdk/lib/index.ts +++ b/sdk/lib/index.ts @@ -5,6 +5,7 @@ export { StartSdk } from "./StartSdk" export { setupManifest } from "./manifest/setupManifest" export { FileHelper } from "./util/fileHelper" export { setupExposeStore } from "./store/setupExposeStore" +export { pathBuilder } from "./store/PathBuilder" export * as actions from "./actions" export * as backup from "./backup" export * as config from "./config" diff --git a/sdk/lib/util/index.browser.ts b/sdk/lib/util/index.browser.ts new file mode 100644 index 000000000..6ff7ed01c --- /dev/null +++ b/sdk/lib/util/index.browser.ts @@ -0,0 +1,25 @@ +import * as T from "../types" + +export { GetServiceInterface, getServiceInterface } from "./getServiceInterface" +export { getServiceInterfaces } from "./getServiceInterfaces" +// prettier-ignore +export type FlattenIntersection = +T extends ArrayLike ? T : +T extends object ? {} & {[P in keyof T]: T[P]} : + T; + +export type _ = FlattenIntersection + +export const isKnownError = (e: unknown): e is T.KnownError => + e instanceof Object && ("error" in e || "error-code" in e) + +declare const affine: unique symbol + +export type Affine = { [affine]: A } + +type NeverPossible = { [affine]: string } +export type NoAny = NeverPossible extends A + ? keyof NeverPossible extends keyof A + ? never + : A + : A diff --git a/sdk/package-lock.json b/sdk/package-lock.json index c00bd6701..f0d61ea4d 100644 --- a/sdk/package-lock.json +++ b/sdk/package-lock.json @@ -9,19 +9,19 @@ "version": "0.4.0-rev0.lib0.rc8.beta10", "license": "MIT", "dependencies": { - "@iarna/toml": "^2.2.5", "isomorphic-fetch": "^3.0.0", - "ts-matches": "^5.4.1", - "yaml": "^2.2.2" + "ts-matches": "^5.4.1" }, "devDependencies": { + "@iarna/toml": "^2.2.5", "@types/jest": "^29.4.0", "jest": "^29.4.3", "prettier": "^3.2.5", "ts-jest": "^29.0.5", "ts-node": "^10.9.1", "tsx": "^4.7.1", - "typescript": "^5.0.4" + "typescript": "^5.0.4", + "yaml": "^2.2.2" } }, "node_modules/@ampproject/remapping": { @@ -651,7 +651,8 @@ "node_modules/@iarna/toml": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz", - "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==" + "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==", + "dev": true }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", @@ -4235,6 +4236,7 @@ "version": "2.2.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz", "integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==", + "dev": true, "engines": { "node": ">= 14" } diff --git a/sdk/package.json b/sdk/package.json index 539d8f90a..6176f4d8e 100644 --- a/sdk/package.json +++ b/sdk/package.json @@ -5,14 +5,8 @@ "main": "./cjs/sdk/lib/index.js", "types": "./cjs/sdk/lib/index.d.ts", "module": "./mjs/sdk/lib/index.js", + "browser": "./mjs/sdk/lib/index.browser.js", "sideEffects": true, - "exports": { - ".": { - "import": "./mjs/sdk/lib/index.js", - "require": "./cjs/sdk/lib/index.js", - "types": "./cjs/sdk/lib/index.d.ts" - } - }, "typesVersion": { ">=3.1": { "*": [ @@ -36,10 +30,8 @@ }, "homepage": "https://github.com/Start9Labs/start-sdk#readme", "dependencies": { - "@iarna/toml": "^2.2.5", "isomorphic-fetch": "^3.0.0", - "ts-matches": "^5.4.1", - "yaml": "^2.2.2" + "ts-matches": "^5.4.1" }, "prettier": { "trailingComma": "all", @@ -48,6 +40,8 @@ "singleQuote": false }, "devDependencies": { + "@iarna/toml": "^2.2.5", + "yaml": "^2.2.2", "@types/jest": "^29.4.0", "jest": "^29.4.3", "prettier": "^3.2.5", diff --git a/web/package-lock.json b/web/package-lock.json index a4cc53e5c..90a6ad58d 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -1976,19 +1976,19 @@ "version": "0.4.0-rev0.lib0.rc8.beta10", "license": "MIT", "dependencies": { - "@iarna/toml": "^2.2.5", "isomorphic-fetch": "^3.0.0", - "ts-matches": "^5.4.1", - "yaml": "^2.2.2" + "ts-matches": "^5.4.1" }, "devDependencies": { + "@iarna/toml": "^2.2.5", "@types/jest": "^29.4.0", "jest": "^29.4.3", "prettier": "^3.2.5", "ts-jest": "^29.0.5", "ts-node": "^10.9.1", "tsx": "^4.7.1", - "typescript": "^5.0.4" + "typescript": "^5.0.4", + "yaml": "^2.2.2" } }, "node_modules/@adobe/css-tools": { From 299d9998ad95fb0726e872fca3d374aacbb91e94 Mon Sep 17 00:00:00 2001 From: J H Date: Mon, 25 Mar 2024 12:01:13 -0600 Subject: [PATCH 2/3] chore: Making sure that the values that we are returning are valid now with the new types --- .../src/Adapters/HostSystemStartOs.ts | 5 - .../Systems/SystemForEmbassy/MainLoop.ts | 14 +- .../Systems/SystemForEmbassy/index.ts | 397 +++--------------- container-runtime/src/Models/JsonPath.ts | 1 + 4 files changed, 55 insertions(+), 362 deletions(-) diff --git a/container-runtime/src/Adapters/HostSystemStartOs.ts b/container-runtime/src/Adapters/HostSystemStartOs.ts index f173e4e62..5e52224fa 100644 --- a/container-runtime/src/Adapters/HostSystemStartOs.ts +++ b/container-runtime/src/Adapters/HostSystemStartOs.ts @@ -147,11 +147,6 @@ export class HostSystemStartOs implements Effects { T.Effects["exposeForDependents"] > } - exposeUi(...[options]: Parameters) { - return this.rpcRound("exposeUi", options) as ReturnType< - T.Effects["exposeUi"] - > - } getConfigured(...[]: Parameters) { return this.rpcRound("getConfigured", null) as ReturnType< T.Effects["getConfigured"] diff --git a/container-runtime/src/Adapters/Systems/SystemForEmbassy/MainLoop.ts b/container-runtime/src/Adapters/Systems/SystemForEmbassy/MainLoop.ts index e5e532246..69e3e6615 100644 --- a/container-runtime/src/Adapters/Systems/SystemForEmbassy/MainLoop.ts +++ b/container-runtime/src/Adapters/Systems/SystemForEmbassy/MainLoop.ts @@ -25,15 +25,12 @@ export class MainLoop { wait: Promise }> | undefined - private propertiesEvent: NodeJS.Timeout | undefined constructor( readonly system: SystemForEmbassy, readonly effects: HostSystemStartOs, - readonly runProperties: () => Promise, ) { this.healthLoops = this.constructHealthLoops() this.mainEvent = this.constructMainEvent() - this.propertiesEvent = this.constructPropertiesEvent() } private async constructMainEvent() { @@ -85,23 +82,14 @@ export class MainLoop { } public async clean(options?: { timeout?: number }) { - const { mainEvent, healthLoops, propertiesEvent } = this + const { mainEvent, healthLoops } = this const main = await mainEvent delete this.mainEvent delete this.healthLoops - delete this.propertiesEvent if (mainEvent) await main?.daemon.term() - clearInterval(propertiesEvent) if (healthLoops) healthLoops.forEach((x) => clearInterval(x.interval)) } - private constructPropertiesEvent() { - const { runProperties } = this - return setInterval(() => { - runProperties() - }, EMBASSY_PROPERTIES_LOOP) - } - private constructHealthLoops() { const { manifest } = this.system const effects = this.effects diff --git a/container-runtime/src/Adapters/Systems/SystemForEmbassy/index.ts b/container-runtime/src/Adapters/Systems/SystemForEmbassy/index.ts index ae9b3f462..fb99795cc 100644 --- a/container-runtime/src/Adapters/Systems/SystemForEmbassy/index.ts +++ b/container-runtime/src/Adapters/Systems/SystemForEmbassy/index.ts @@ -59,6 +59,33 @@ export type PackagePropertyObject = { type: "object" description: string } + +const asProperty_ = ( + x: PackagePropertyString | PackagePropertyObject, +): T.PropertiesValue => { + if (x.type === "object") { + return { + ...x, + value: Object.fromEntries( + Object.entries(x.value).map(([key, value]) => [ + key, + asProperty_(value), + ]), + ), + } + } + return { + masked: false, + description: null, + qr: null, + copyable: null, + ...x, + } +} +const asProperty = (x: PackagePropertiesV2): T.PropertiesReturn => + Object.fromEntries( + Object.entries(x).map(([key, value]) => [key, asProperty_(value)]), + ) const [matchPackageProperties, setMatchPackageProperties] = deferred() const matchPackagePropertyObject: Parser = @@ -92,44 +119,6 @@ const matchProperties = object({ data: matchPackageProperties, }) -type ExportUi = { - values: { [key: string]: any } - expose: { [key: string]: T.ExposeUiPathsAll } -} - -function propertiesToExportUi( - properties: PackagePropertiesV2, - previousPath = "", -): ExportUi { - const exportUi: ExportUi = { - values: {}, - expose: {}, - } - for (const [key, value] of Object.entries(properties)) { - const path = `${previousPath}/${key}` - if (value.type === "object") { - const { values, expose } = propertiesToExportUi(value.value, path) - exportUi.values[key] = values - exportUi.expose[key] = { - type: "object", - value: expose, - description: value.description, - } - continue - } - exportUi.values[key] = value.value - exportUi.expose[key] = { - type: "string", - path, - description: value.description ?? null, - masked: value.masked ?? false, - copyable: value.copyable ?? null, - qr: value.qr ?? null, - } - } - return exportUi -} - export class SystemForEmbassy implements System { currentRunning: MainLoop | undefined static async of(manifestLocation: string = MANIFEST_LOCATION) { @@ -236,6 +225,8 @@ export class SystemForEmbassy implements System { return this.getConfig(effects) case "/config/set": return this.setConfig(effects, input) + case "/properties": + return this.properties(effects) case "/actions/metadata": return todo() case "/init": @@ -279,9 +270,7 @@ export class SystemForEmbassy implements System { private async mainStart(effects: HostSystemStartOs): Promise { if (!!this.currentRunning) return - this.currentRunning = new MainLoop(this, effects, () => - this.properties(effects), - ) + this.currentRunning = new MainLoop(this, effects) } private async mainStop( effects: HostSystemStartOs, @@ -472,51 +461,44 @@ export class SystemForEmbassy implements System { } return { configured: true } } - private async properties(effects: HostSystemStartOs): Promise { + private async properties( + effects: HostSystemStartOs, + ): Promise> { // TODO BLU-J set the properties ever so often const setConfigValue = this.manifest.properties - if (!setConfigValue) return + if (!setConfigValue) throw new Error("There is no properties") if (setConfigValue.type === "docker") { const container = await DockerProcedureContainer.of( effects, setConfigValue, this.manifest.volumes, ) - const properties = JSON.parse( - ( - await container.exec([ - setConfigValue.entrypoint, - ...setConfigValue.args, - ]) - ).stdout.toString(), + const properties = matchProperties.unsafeCast( + JSON.parse( + ( + await container.exec([ + setConfigValue.entrypoint, + ...setConfigValue.args, + ]) + ).stdout.toString(), + ), ) - if (!matchProperties.test(properties)) return - const exposeUis = propertiesToExportUi(properties.data) - await effects.store.set({ - path: "/properties", - value: exposeUis.values, - }) - await effects.exposeUi(exposeUis.expose) + return asProperty(properties.data) } else if (setConfigValue.type === "script") { const moduleCode = this.moduleCode const method = moduleCode.properties if (!method) throw new Error("Expecting that the method properties exists") - const properties = await method( - new PolyfillEffects(effects, this.manifest), - ).then((x) => { - if ("result" in x) return x.result - if ("error" in x) throw new Error("Error getting config: " + x.error) - throw new Error("Error getting config: " + x["error-code"][1]) - }) - if (!matchProperties.test(properties)) return - const exposeUis = propertiesToExportUi(properties.data) - await effects.store.set({ - path: "/properties", - value: exposeUis.values, - }) - await effects.exposeUi(exposeUis.expose) + const properties = matchProperties.unsafeCast( + await method(new PolyfillEffects(effects, this.manifest)).then((x) => { + if ("result" in x) return x.result + if ("error" in x) throw new Error("Error getting config: " + x.error) + throw new Error("Error getting config: " + x["error-code"][1]) + }), + ) + return asProperty(properties.data) } + throw new Error(`Unknown type in the fetch properties: ${setConfigValue}`) } private async health( effects: HostSystemStartOs, @@ -651,279 +633,6 @@ export class SystemForEmbassy implements System { throw new Error("Error getting config: " + x["error-code"][1]) })) as any } - // private async sandbox( - // effects: HostSystemStartOs, - // options: { - // procedure: - // | "/createBackup" - // | "/restoreBackup" - // | "/getConfig" - // | "/setConfig" - // | "migration" - // | "/properties" - // | `/action/${string}` - // | `/dependencies/${string}/check` - // | `/dependencies/${string}/autoConfigure` - // input: unknown - // timeout?: number | undefined - // }, - // ): Promise { - // const input = options.input - // switch (options.procedure) { - // case "/createBackup": - // return this.roCreateBackup(effects) - // case "/restoreBackup": - // return this.roRestoreBackup(effects) - // case "/getConfig": - // return this.roGetConfig(effects) - // case "/setConfig": - // return this.roSetConfig(effects, input) - // case "migration": - // return this.roMigration(effects, input) - // case "/properties": - // return this.roProperties(effects) - // default: - // const procedure = options.procedure.split("/") - // switch (true) { - // case options.procedure.startsWith("/action/"): - // return this.roAction(effects, procedure[2], input) - // case options.procedure.startsWith("/dependencies/") && - // procedure[3] === "check": - // return this.roDependenciesCheck(effects, procedure[2], input) - - // case options.procedure.startsWith("/dependencies/") && - // procedure[3] === "autoConfigure": - // return this.roDependenciesAutoconfig(effects, procedure[2], input) - // } - // } - // } - - // private async roCreateBackup(effects: HostSystemStartOs): Promise { - // const backup = this.manifest.backup.create - // if (backup.type === "docker") { - // const container = await DockerProcedureContainer.readonlyOf(backup) - // await container.exec([backup.entrypoint, ...backup.args]) - // } else { - // const moduleCode = await this.moduleCode - // await moduleCode.createBackup?.(new PolyfillEffects(effects)) - // } - // } - // private async roRestoreBackup(effects: HostSystemStartOs): Promise { - // const restoreBackup = this.manifest.backup.restore - // if (restoreBackup.type === "docker") { - // const container = await DockerProcedureContainer.readonlyOf(restoreBackup) - // await container.exec([restoreBackup.entrypoint, ...restoreBackup.args]) - // } else { - // const moduleCode = await this.moduleCode - // await moduleCode.restoreBackup?.(new PolyfillEffects(effects)) - // } - // } - // private async roGetConfig(effects: HostSystemStartOs): Promise { - // const config = this.manifest.config?.get - // if (!config) return { spec: {} } - // if (config.type === "docker") { - // const container = await DockerProcedureContainer.readonlyOf(config) - // return JSON.parse( - // (await container.exec([config.entrypoint, ...config.args])).stdout, - // ) - // } else { - // const moduleCode = await this.moduleCode - // const method = moduleCode.getConfig - // if (!method) throw new Error("Expecting that the method getConfig exists") - // return (await method(new PolyfillEffects(effects)).then((x) => { - // if ("result" in x) return x.result - // if ("error" in x) throw new Error("Error getting config: " + x.error) - // throw new Error("Error getting config: " + x["error-code"][1]) - // })) as any - // } - // } - // private async roSetConfig( - // effects: HostSystemStartOs, - // newConfig: unknown, - // ): Promise { - // const setConfigValue = this.manifest.config?.set - // if (!setConfigValue) return { signal: "SIGTERM", "depends-on": {} } - // if (setConfigValue.type === "docker") { - // const container = await DockerProcedureContainer.readonlyOf( - // setConfigValue, - // ) - // return JSON.parse( - // ( - // await container.exec([ - // setConfigValue.entrypoint, - // ...setConfigValue.args, - // JSON.stringify(newConfig), - // ]) - // ).stdout, - // ) - // } else { - // const moduleCode = await this.moduleCode - // const method = moduleCode.setConfig - // if (!method) throw new Error("Expecting that the method setConfig exists") - // return await method( - // new PolyfillEffects(effects), - // newConfig as U.Config, - // ).then((x) => { - // if ("result" in x) return x.result - // if ("error" in x) throw new Error("Error getting config: " + x.error) - // throw new Error("Error getting config: " + x["error-code"][1]) - // }) - // } - // } - // private async roMigration( - // effects: HostSystemStartOs, - // fromVersion: unknown, - // ): Promise { - // throw new Error("Migrations should never be ran in the sandbox mode") - // } - // private async roProperties(effects: HostSystemStartOs): Promise { - // const setConfigValue = this.manifest.properties - // if (!setConfigValue) return {} - // if (setConfigValue.type === "docker") { - // const container = await DockerProcedureContainer.readonlyOf( - // setConfigValue, - // ) - // return JSON.parse( - // ( - // await container.exec([ - // setConfigValue.entrypoint, - // ...setConfigValue.args, - // ]) - // ).stdout, - // ) - // } else { - // const moduleCode = await this.moduleCode - // const method = moduleCode.properties - // if (!method) - // throw new Error("Expecting that the method properties exists") - // return await method(new PolyfillEffects(effects)).then((x) => { - // if ("result" in x) return x.result - // if ("error" in x) throw new Error("Error getting config: " + x.error) - // throw new Error("Error getting config: " + x["error-code"][1]) - // }) - // } - // } - // private async roHealth( - // effects: HostSystemStartOs, - // healthId: string, - // timeSinceStarted: unknown, - // ): Promise { - // const healthProcedure = this.manifest["health-checks"][healthId] - // if (!healthProcedure) return - // if (healthProcedure.type === "docker") { - // const container = await DockerProcedureContainer.readonlyOf( - // healthProcedure, - // ) - // return JSON.parse( - // ( - // await container.exec([ - // healthProcedure.entrypoint, - // ...healthProcedure.args, - // JSON.stringify(timeSinceStarted), - // ]) - // ).stdout, - // ) - // } else { - // const moduleCode = await this.moduleCode - // const method = moduleCode.health?.[healthId] - // if (!method) throw new Error("Expecting that the method health exists") - // await method(new PolyfillEffects(effects), Number(timeSinceStarted)).then( - // (x) => { - // if ("result" in x) return x.result - // if ("error" in x) throw new Error("Error getting config: " + x.error) - // throw new Error("Error getting config: " + x["error-code"][1]) - // }, - // ) - // } - // } - // private async roAction( - // effects: HostSystemStartOs, - // actionId: string, - // formData: unknown, - // ): Promise { - // const actionProcedure = this.manifest.actions?.[actionId]?.implementation - // if (!actionProcedure) return { message: "Action not found", value: null } - // if (actionProcedure.type === "docker") { - // const container = await DockerProcedureContainer.readonlyOf( - // actionProcedure, - // ) - // return JSON.parse( - // ( - // await container.exec([ - // actionProcedure.entrypoint, - // ...actionProcedure.args, - // JSON.stringify(formData), - // ]) - // ).stdout, - // ) - // } else { - // const moduleCode = await this.moduleCode - // const method = moduleCode.action?.[actionId] - // if (!method) throw new Error("Expecting that the method action exists") - // return (await method(new PolyfillEffects(effects), formData as any).then( - // (x) => { - // if ("result" in x) return x.result - // if ("error" in x) throw new Error("Error getting config: " + x.error) - // throw new Error("Error getting config: " + x["error-code"][1]) - // }, - // )) as any - // } - // } - // private async roDependenciesCheck( - // effects: HostSystemStartOs, - // id: string, - // oldConfig: unknown, - // ): Promise { - // const actionProcedure = this.manifest.dependencies?.[id]?.config?.check - // if (!actionProcedure) return { message: "Action not found", value: null } - // if (actionProcedure.type === "docker") { - // const container = await DockerProcedureContainer.readonlyOf( - // actionProcedure, - // ) - // return JSON.parse( - // ( - // await container.exec([ - // actionProcedure.entrypoint, - // ...actionProcedure.args, - // JSON.stringify(oldConfig), - // ]) - // ).stdout, - // ) - // } else { - // const moduleCode = await this.moduleCode - // const method = moduleCode.dependencies?.[id]?.check - // if (!method) - // throw new Error( - // `Expecting that the method dependency check ${id} exists`, - // ) - // return (await method(new PolyfillEffects(effects), oldConfig as any).then( - // (x) => { - // if ("result" in x) return x.result - // if ("error" in x) throw new Error("Error getting config: " + x.error) - // throw new Error("Error getting config: " + x["error-code"][1]) - // }, - // )) as any - // } - // } - // private async roDependenciesAutoconfig( - // effects: HostSystemStartOs, - // id: string, - // oldConfig: unknown, - // ): Promise { - // const moduleCode = await this.moduleCode - // const method = moduleCode.dependencies?.[id]?.autoConfigure - // if (!method) - // throw new Error( - // `Expecting that the method dependency autoConfigure ${id} exists`, - // ) - // return (await method(new PolyfillEffects(effects), oldConfig as any).then( - // (x) => { - // if ("result" in x) return x.result - // if ("error" in x) throw new Error("Error getting config: " + x.error) - // throw new Error("Error getting config: " + x["error-code"][1]) - // }, - // )) as any - // } } async function removePointers(value: T.ConfigRes): Promise { const startingSpec = structuredClone(value.spec) diff --git a/container-runtime/src/Models/JsonPath.ts b/container-runtime/src/Models/JsonPath.ts index 627eb3be2..773331b19 100644 --- a/container-runtime/src/Models/JsonPath.ts +++ b/container-runtime/src/Models/JsonPath.ts @@ -35,6 +35,7 @@ export const jsonPath = some( "/backup/create", "/backup/restore", "/actions/metadata", + "/properties", ), string.refine(isNestedPath, "isNestedPath"), ) From e148f143ea5f9bab23fb9e3ea403810d2eab029b Mon Sep 17 00:00:00 2001 From: J H Date: Mon, 25 Mar 2024 14:18:09 -0600 Subject: [PATCH 3/3] wip: Properties --- core/models/src/procedure_name.rs | 2 + core/startos/src/properties.rs | 66 ++++--------------------------- core/startos/src/service/mod.rs | 11 ++++++ 3 files changed, 21 insertions(+), 58 deletions(-) diff --git a/core/models/src/procedure_name.rs b/core/models/src/procedure_name.rs index bf69b06b8..c42068be3 100644 --- a/core/models/src/procedure_name.rs +++ b/core/models/src/procedure_name.rs @@ -9,6 +9,7 @@ pub enum ProcedureName { GetConfig, SetConfig, CreateBackup, + Properties, RestoreBackup, ActionMetadata, RunAction(ActionId), @@ -29,6 +30,7 @@ impl ProcedureName { ProcedureName::SetConfig => "/config/set".to_string(), ProcedureName::GetConfig => "/config/get".to_string(), ProcedureName::CreateBackup => "/backup/create".to_string(), + ProcedureName::Properties => "/properties".to_string(), ProcedureName::RestoreBackup => "/backup/restore".to_string(), ProcedureName::ActionMetadata => "/actions/metadata".to_string(), ProcedureName::RunAction(id) => format!("/actions/{}/run", id), diff --git a/core/startos/src/properties.rs b/core/startos/src/properties.rs index cfb0dd66b..5482bdb58 100644 --- a/core/startos/src/properties.rs +++ b/core/startos/src/properties.rs @@ -1,4 +1,4 @@ -use std::collections::BTreeMap; +use std::{borrow::Borrow, collections::BTreeMap}; use clap::Parser; use imbl_value::{json, InOMap, InternedString, Value}; @@ -15,48 +15,6 @@ pub fn display_properties(response: Value) { println!("{}", response); } -trait IntoProperties { - fn into_properties(self, store: &Value) -> Value; -} -impl IntoProperties for ExposedUI { - fn into_properties(self, store: &Value) -> Value { - match self { - ExposedUI::Object { value, description } => { - json!({ - "type": "object", - "description": description, - "value": value.into_iter().map(|(k, v)| (k, v.into_properties(store))).collect::>() - }) - } - ExposedUI::String { - path, - description, - masked, - copyable, - qr, - } => json!({ - "type": "string", - "description": description, - "value": path.get(store).cloned().unwrap_or_default(), - "copyable": copyable, - "qr": qr, - "masked": masked - }), - } - } -} - -impl IntoProperties for StoreExposedUI { - fn into_properties(self, store: &Value) -> Value { - Value::Object( - self.0 - .into_iter() - .map(|(k, v)| (k, v.into_properties(store))) - .collect::>(), - ) - } -} - #[derive(Deserialize, Serialize, Parser)] #[serde(rename_all = "camelCase")] #[command(rename_all = "kebab-case")] @@ -68,19 +26,11 @@ pub async fn properties( ctx: RpcContext, PropertiesParam { id }: PropertiesParam, ) -> Result { - let peeked = ctx.db.peek().await; - let data = peeked - .as_private() - .as_package_stores() - .as_idx(&id) - .map(|x| x.de()) - .unwrap_or_else(|| Ok(json!({})))?; - Ok(peeked - .as_public() - .as_package_data() - .as_idx(&id) - .or_not_found(&id)? - .as_store_exposed_ui() - .de()? - .into_properties(&data)) + match &*ctx.services.get(&id).await { + Some(service) => service.properties().await, + None => Err(Error::new( + eyre!("Could not find a service with id {id}"), + ErrorKind::NotFound, + )), + } } diff --git a/core/startos/src/service/mod.rs b/core/startos/src/service/mod.rs index fb521ca34..2feb4ca34 100644 --- a/core/startos/src/service/mod.rs +++ b/core/startos/src/service/mod.rs @@ -325,6 +325,17 @@ impl Service { .await .with_kind(ErrorKind::Action) } + pub async fn properties(&self) -> Result { + let container = &self.seed.persistent_container; + container + .execute::( + ProcedureName::Properties, + Value::Null, + Some(Duration::from_secs(30)), + ) + .await + .with_kind(ErrorKind::Unknown) + } pub async fn shutdown(self) -> Result<(), Error> { self.actor