mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 02:11:53 +00:00
Chore/refactoring effects (#2644)
* fix mac build * wip * chore: Update the effects to get rid of bad pattern * chore: Some small changes --------- Co-authored-by: Aiden McClelland <me@drbonez.dev>
This commit is contained in:
@@ -31,26 +31,21 @@ type RpcError = typeof matchRpcError._TYPE
|
||||
|
||||
const SOCKET_PATH = "/media/startos/rpc/host.sock"
|
||||
const MAIN = "/main" as const
|
||||
export class HostSystemStartOs implements Effects {
|
||||
procedureId: string | null = null
|
||||
|
||||
static of(callbackHolder: CallbackHolder) {
|
||||
return new HostSystemStartOs(callbackHolder)
|
||||
}
|
||||
|
||||
constructor(readonly callbackHolder: CallbackHolder) {}
|
||||
id = 0
|
||||
rpcRound<K extends keyof Effects | "getStore" | "setStore">(
|
||||
let hostSystemId = 0
|
||||
export const hostSystemStartOs =
|
||||
(callbackHolder: CallbackHolder) =>
|
||||
(procedureId: null | string): Effects => {
|
||||
const rpcRound = <K extends keyof Effects | "getStore" | "setStore">(
|
||||
method: K,
|
||||
params: Record<string, unknown>,
|
||||
) {
|
||||
const id = this.id++
|
||||
) => {
|
||||
const id = hostSystemId++
|
||||
const client = net.createConnection({ path: SOCKET_PATH }, () => {
|
||||
client.write(
|
||||
JSON.stringify({
|
||||
id,
|
||||
method,
|
||||
params: { ...params, procedureId: this.procedureId },
|
||||
params: { ...params, procedureId: procedureId },
|
||||
}) + "\n",
|
||||
)
|
||||
})
|
||||
@@ -96,209 +91,213 @@ export class HostSystemStartOs implements Effects {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const self: Effects = {
|
||||
bind(...[options]: Parameters<T.Effects["bind"]>) {
|
||||
return this.rpcRound("bind", {
|
||||
return rpcRound("bind", {
|
||||
...options,
|
||||
stack: new Error().stack,
|
||||
}) as ReturnType<T.Effects["bind"]>
|
||||
}
|
||||
},
|
||||
clearBindings(...[]: Parameters<T.Effects["clearBindings"]>) {
|
||||
return this.rpcRound("clearBindings", {}) as ReturnType<
|
||||
return rpcRound("clearBindings", {}) as ReturnType<
|
||||
T.Effects["clearBindings"]
|
||||
>
|
||||
}
|
||||
},
|
||||
clearServiceInterfaces(
|
||||
...[]: Parameters<T.Effects["clearServiceInterfaces"]>
|
||||
) {
|
||||
return this.rpcRound("clearServiceInterfaces", {}) as ReturnType<
|
||||
return rpcRound("clearServiceInterfaces", {}) as ReturnType<
|
||||
T.Effects["clearServiceInterfaces"]
|
||||
>
|
||||
}
|
||||
},
|
||||
createOverlayedImage(options: {
|
||||
imageId: string
|
||||
}): Promise<[string, string]> {
|
||||
return this.rpcRound("createOverlayedImage", options) as ReturnType<
|
||||
return rpcRound("createOverlayedImage", options) as ReturnType<
|
||||
T.Effects["createOverlayedImage"]
|
||||
>
|
||||
}
|
||||
},
|
||||
destroyOverlayedImage(options: { guid: string }): Promise<void> {
|
||||
return this.rpcRound("destroyOverlayedImage", options) as ReturnType<
|
||||
return rpcRound("destroyOverlayedImage", options) as ReturnType<
|
||||
T.Effects["destroyOverlayedImage"]
|
||||
>
|
||||
}
|
||||
},
|
||||
executeAction(...[options]: Parameters<T.Effects["executeAction"]>) {
|
||||
return this.rpcRound("executeAction", options) as ReturnType<
|
||||
return rpcRound("executeAction", options) as ReturnType<
|
||||
T.Effects["executeAction"]
|
||||
>
|
||||
}
|
||||
},
|
||||
exists(...[packageId]: Parameters<T.Effects["exists"]>) {
|
||||
return this.rpcRound("exists", packageId) as ReturnType<T.Effects["exists"]>
|
||||
}
|
||||
return rpcRound("exists", packageId) as ReturnType<T.Effects["exists"]>
|
||||
},
|
||||
exportAction(...[options]: Parameters<T.Effects["exportAction"]>) {
|
||||
return this.rpcRound("exportAction", options) as ReturnType<
|
||||
return rpcRound("exportAction", options) as ReturnType<
|
||||
T.Effects["exportAction"]
|
||||
>
|
||||
}
|
||||
exportServiceInterface: Effects["exportServiceInterface"] = (
|
||||
},
|
||||
exportServiceInterface: ((
|
||||
...[options]: Parameters<Effects["exportServiceInterface"]>
|
||||
) => {
|
||||
return this.rpcRound("exportServiceInterface", options) as ReturnType<
|
||||
return rpcRound("exportServiceInterface", options) as ReturnType<
|
||||
T.Effects["exportServiceInterface"]
|
||||
>
|
||||
}
|
||||
}) as Effects["exportServiceInterface"],
|
||||
exposeForDependents(
|
||||
...[options]: Parameters<T.Effects["exposeForDependents"]>
|
||||
) {
|
||||
return this.rpcRound("exposeForDependents", options) as ReturnType<
|
||||
return rpcRound("exposeForDependents", options) as ReturnType<
|
||||
T.Effects["exposeForDependents"]
|
||||
>
|
||||
}
|
||||
},
|
||||
getConfigured(...[]: Parameters<T.Effects["getConfigured"]>) {
|
||||
return this.rpcRound("getConfigured", {}) as ReturnType<
|
||||
return rpcRound("getConfigured", {}) as ReturnType<
|
||||
T.Effects["getConfigured"]
|
||||
>
|
||||
}
|
||||
},
|
||||
getContainerIp(...[]: Parameters<T.Effects["getContainerIp"]>) {
|
||||
return this.rpcRound("getContainerIp", {}) as ReturnType<
|
||||
return rpcRound("getContainerIp", {}) as ReturnType<
|
||||
T.Effects["getContainerIp"]
|
||||
>
|
||||
}
|
||||
getHostInfo: Effects["getHostInfo"] = (...[allOptions]: any[]) => {
|
||||
},
|
||||
getHostInfo: ((...[allOptions]: any[]) => {
|
||||
const options = {
|
||||
...allOptions,
|
||||
callback: this.callbackHolder.addCallback(allOptions.callback),
|
||||
callback: callbackHolder.addCallback(allOptions.callback),
|
||||
}
|
||||
return this.rpcRound("getHostInfo", options) as ReturnType<
|
||||
return rpcRound("getHostInfo", options) as ReturnType<
|
||||
T.Effects["getHostInfo"]
|
||||
> as any
|
||||
}
|
||||
}) as Effects["getHostInfo"],
|
||||
getServiceInterface(
|
||||
...[options]: Parameters<T.Effects["getServiceInterface"]>
|
||||
) {
|
||||
return this.rpcRound("getServiceInterface", {
|
||||
return rpcRound("getServiceInterface", {
|
||||
...options,
|
||||
callback: this.callbackHolder.addCallback(options.callback),
|
||||
callback: callbackHolder.addCallback(options.callback),
|
||||
}) as ReturnType<T.Effects["getServiceInterface"]>
|
||||
}
|
||||
},
|
||||
|
||||
getPrimaryUrl(...[options]: Parameters<T.Effects["getPrimaryUrl"]>) {
|
||||
return this.rpcRound("getPrimaryUrl", {
|
||||
return rpcRound("getPrimaryUrl", {
|
||||
...options,
|
||||
callback: this.callbackHolder.addCallback(options.callback),
|
||||
callback: callbackHolder.addCallback(options.callback),
|
||||
}) as ReturnType<T.Effects["getPrimaryUrl"]>
|
||||
}
|
||||
},
|
||||
getServicePortForward(
|
||||
...[options]: Parameters<T.Effects["getServicePortForward"]>
|
||||
) {
|
||||
return this.rpcRound("getServicePortForward", options) as ReturnType<
|
||||
return rpcRound("getServicePortForward", options) as ReturnType<
|
||||
T.Effects["getServicePortForward"]
|
||||
>
|
||||
}
|
||||
getSslCertificate(options: Parameters<T.Effects["getSslCertificate"]>[0]) {
|
||||
return this.rpcRound("getSslCertificate", options) as ReturnType<
|
||||
},
|
||||
getSslCertificate(
|
||||
options: Parameters<T.Effects["getSslCertificate"]>[0],
|
||||
) {
|
||||
return rpcRound("getSslCertificate", options) as ReturnType<
|
||||
T.Effects["getSslCertificate"]
|
||||
>
|
||||
}
|
||||
},
|
||||
getSslKey(options: Parameters<T.Effects["getSslKey"]>[0]) {
|
||||
return this.rpcRound("getSslKey", options) as ReturnType<
|
||||
return rpcRound("getSslKey", options) as ReturnType<
|
||||
T.Effects["getSslKey"]
|
||||
>
|
||||
}
|
||||
},
|
||||
getSystemSmtp(...[options]: Parameters<T.Effects["getSystemSmtp"]>) {
|
||||
return this.rpcRound("getSystemSmtp", {
|
||||
return rpcRound("getSystemSmtp", {
|
||||
...options,
|
||||
callback: this.callbackHolder.addCallback(options.callback),
|
||||
callback: callbackHolder.addCallback(options.callback),
|
||||
}) as ReturnType<T.Effects["getSystemSmtp"]>
|
||||
}
|
||||
},
|
||||
listServiceInterfaces(
|
||||
...[options]: Parameters<T.Effects["listServiceInterfaces"]>
|
||||
) {
|
||||
return this.rpcRound("listServiceInterfaces", {
|
||||
return rpcRound("listServiceInterfaces", {
|
||||
...options,
|
||||
callback: this.callbackHolder.addCallback(options.callback),
|
||||
callback: callbackHolder.addCallback(options.callback),
|
||||
}) as ReturnType<T.Effects["listServiceInterfaces"]>
|
||||
}
|
||||
},
|
||||
mount(...[options]: Parameters<T.Effects["mount"]>) {
|
||||
return this.rpcRound("mount", options) as ReturnType<T.Effects["mount"]>
|
||||
}
|
||||
return rpcRound("mount", options) as ReturnType<T.Effects["mount"]>
|
||||
},
|
||||
removeAction(...[options]: Parameters<T.Effects["removeAction"]>) {
|
||||
return this.rpcRound("removeAction", options) as ReturnType<
|
||||
return rpcRound("removeAction", options) as ReturnType<
|
||||
T.Effects["removeAction"]
|
||||
>
|
||||
}
|
||||
},
|
||||
removeAddress(...[options]: Parameters<T.Effects["removeAddress"]>) {
|
||||
return this.rpcRound("removeAddress", options) as ReturnType<
|
||||
return rpcRound("removeAddress", options) as ReturnType<
|
||||
T.Effects["removeAddress"]
|
||||
>
|
||||
}
|
||||
},
|
||||
restart(...[]: Parameters<T.Effects["restart"]>) {
|
||||
return this.rpcRound("restart", {}) as ReturnType<T.Effects["restart"]>
|
||||
}
|
||||
return rpcRound("restart", {}) as ReturnType<T.Effects["restart"]>
|
||||
},
|
||||
running(...[packageId]: Parameters<T.Effects["running"]>) {
|
||||
return this.rpcRound("running", { packageId }) as ReturnType<
|
||||
return rpcRound("running", { packageId }) as ReturnType<
|
||||
T.Effects["running"]
|
||||
>
|
||||
}
|
||||
},
|
||||
// runRsync(...[options]: Parameters<T.Effects[""]>) {
|
||||
//
|
||||
// return this.rpcRound('executeAction', options) as ReturnType<T.Effects["executeAction"]>
|
||||
// return rpcRound('executeAction', options) as ReturnType<T.Effects["executeAction"]>
|
||||
//
|
||||
// return this.rpcRound('executeAction', options) as ReturnType<T.Effects["executeAction"]>
|
||||
// return rpcRound('executeAction', options) as ReturnType<T.Effects["executeAction"]>
|
||||
// }
|
||||
setConfigured(...[configured]: Parameters<T.Effects["setConfigured"]>) {
|
||||
return this.rpcRound("setConfigured", { configured }) as ReturnType<
|
||||
return rpcRound("setConfigured", { configured }) as ReturnType<
|
||||
T.Effects["setConfigured"]
|
||||
>
|
||||
}
|
||||
},
|
||||
setDependencies(
|
||||
dependencies: Parameters<T.Effects["setDependencies"]>[0],
|
||||
): ReturnType<T.Effects["setDependencies"]> {
|
||||
return this.rpcRound("setDependencies", dependencies) as ReturnType<
|
||||
return rpcRound("setDependencies", dependencies) as ReturnType<
|
||||
T.Effects["setDependencies"]
|
||||
>
|
||||
}
|
||||
},
|
||||
checkDependencies(
|
||||
options: Parameters<T.Effects["checkDependencies"]>[0],
|
||||
): ReturnType<T.Effects["checkDependencies"]> {
|
||||
return this.rpcRound("checkDependencies", options) as ReturnType<
|
||||
return rpcRound("checkDependencies", options) as ReturnType<
|
||||
T.Effects["checkDependencies"]
|
||||
>
|
||||
}
|
||||
},
|
||||
getDependencies(): ReturnType<T.Effects["getDependencies"]> {
|
||||
return this.rpcRound("getDependencies", {}) as ReturnType<
|
||||
return rpcRound("getDependencies", {}) as ReturnType<
|
||||
T.Effects["getDependencies"]
|
||||
>
|
||||
}
|
||||
},
|
||||
setHealth(...[options]: Parameters<T.Effects["setHealth"]>) {
|
||||
return this.rpcRound("setHealth", options) as ReturnType<
|
||||
return rpcRound("setHealth", options) as ReturnType<
|
||||
T.Effects["setHealth"]
|
||||
>
|
||||
}
|
||||
},
|
||||
|
||||
setMainStatus(o: { status: "running" | "stopped" }): Promise<void> {
|
||||
return this.rpcRound("setMainStatus", o) as ReturnType<
|
||||
return rpcRound("setMainStatus", o) as ReturnType<
|
||||
T.Effects["setHealth"]
|
||||
>
|
||||
}
|
||||
},
|
||||
|
||||
shutdown(...[]: Parameters<T.Effects["shutdown"]>) {
|
||||
return this.rpcRound("shutdown", {}) as ReturnType<T.Effects["shutdown"]>
|
||||
}
|
||||
return rpcRound("shutdown", {}) as ReturnType<T.Effects["shutdown"]>
|
||||
},
|
||||
stopped(...[packageId]: Parameters<T.Effects["stopped"]>) {
|
||||
return this.rpcRound("stopped", { packageId }) as ReturnType<
|
||||
return rpcRound("stopped", { packageId }) as ReturnType<
|
||||
T.Effects["stopped"]
|
||||
>
|
||||
}
|
||||
store: T.Effects["store"] = {
|
||||
},
|
||||
store: {
|
||||
get: async (options: any) =>
|
||||
this.rpcRound("getStore", {
|
||||
rpcRound("getStore", {
|
||||
...options,
|
||||
callback: this.callbackHolder.addCallback(options.callback),
|
||||
callback: callbackHolder.addCallback(options.callback),
|
||||
}) as any,
|
||||
set: async (options: any) =>
|
||||
this.rpcRound("setStore", options) as ReturnType<
|
||||
rpcRound("setStore", options) as ReturnType<
|
||||
T.Effects["store"]["set"]
|
||||
>,
|
||||
} as T.Effects["store"],
|
||||
}
|
||||
return self
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,7 +247,7 @@ export class RpcListener {
|
||||
})),
|
||||
)
|
||||
.when(exitType, async ({ id }) => {
|
||||
if (this._system) await this._system.exit(this.effects)
|
||||
if (this._system) await this._system.exit(this.effects(null))
|
||||
delete this._system
|
||||
delete this._effects
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { PolyfillEffects } from "./polyfillEffects"
|
||||
import { polyfillEffects } from "./polyfillEffects"
|
||||
import { DockerProcedureContainer } from "./DockerProcedureContainer"
|
||||
import { SystemForEmbassy } from "."
|
||||
import { HostSystemStartOs } from "../../HostSystemStartOs"
|
||||
import { hostSystemStartOs } from "../../HostSystemStartOs"
|
||||
import { Daemons, T, daemons } from "@start9labs/start-sdk"
|
||||
import { Daemon } from "@start9labs/start-sdk/cjs/lib/mainFn/Daemon"
|
||||
import { Effects } from "../../../Models/Effects"
|
||||
|
||||
const EMBASSY_HEALTH_INTERVAL = 15 * 1000
|
||||
const EMBASSY_PROPERTIES_LOOP = 30 * 1000
|
||||
@@ -27,7 +28,7 @@ export class MainLoop {
|
||||
| undefined
|
||||
constructor(
|
||||
readonly system: SystemForEmbassy,
|
||||
readonly effects: HostSystemStartOs,
|
||||
readonly effects: Effects,
|
||||
) {
|
||||
this.healthLoops = this.constructHealthLoops()
|
||||
this.mainEvent = this.constructMainEvent()
|
||||
@@ -65,7 +66,7 @@ export class MainLoop {
|
||||
}
|
||||
}
|
||||
|
||||
private async setupInterfaces(effects: HostSystemStartOs) {
|
||||
private async setupInterfaces(effects: T.Effects) {
|
||||
for (const interfaceId in this.system.manifest.interfaces) {
|
||||
const iface = this.system.manifest.interfaces[interfaceId]
|
||||
const internalPorts = new Set<number>()
|
||||
@@ -211,7 +212,7 @@ export class MainLoop {
|
||||
}
|
||||
|
||||
const result = await method(
|
||||
new PolyfillEffects(effects, this.system.manifest),
|
||||
polyfillEffects(effects, this.system.manifest),
|
||||
timeChanged,
|
||||
)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { types as T, utils, EmVer } from "@start9labs/start-sdk"
|
||||
import * as fs from "fs/promises"
|
||||
|
||||
import { PolyfillEffects } from "./polyfillEffects"
|
||||
import { polyfillEffects } from "./polyfillEffects"
|
||||
import { Duration, duration, fromDuration } from "../../../Models/Duration"
|
||||
import { System } from "../../../Interfaces/System"
|
||||
import { matchManifest, Manifest, Procedure } from "./matchManifest"
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
Parser,
|
||||
array,
|
||||
} from "ts-matches"
|
||||
import { HostSystemStartOs } from "../../HostSystemStartOs"
|
||||
import { hostSystemStartOs } from "../../HostSystemStartOs"
|
||||
import { JsonPath, unNestPath } from "../../../Models/JsonPath"
|
||||
import { RpcResult, matchRpcResult } from "../../RpcListener"
|
||||
import { CT } from "@start9labs/start-sdk"
|
||||
@@ -41,6 +41,7 @@ import {
|
||||
MultiHost,
|
||||
} from "@start9labs/start-sdk/cjs/lib/interfaces/Host"
|
||||
import { ServiceInterfaceBuilder } from "@start9labs/start-sdk/cjs/lib/interfaces/ServiceInterfaceBuilder"
|
||||
import { Effects } from "../../../Models/Effects"
|
||||
|
||||
type Optional<A> = A | undefined | null
|
||||
function todo(): never {
|
||||
@@ -197,7 +198,7 @@ export class SystemForEmbassy implements System {
|
||||
readonly moduleCode: Partial<U.ExpectedExports>,
|
||||
) {}
|
||||
async execute(
|
||||
effects: HostSystemStartOs,
|
||||
effectCreator: ReturnType<typeof hostSystemStartOs>,
|
||||
options: {
|
||||
id: string
|
||||
procedure: JsonPath
|
||||
@@ -205,8 +206,7 @@ export class SystemForEmbassy implements System {
|
||||
timeout?: number | undefined
|
||||
},
|
||||
): Promise<RpcResult> {
|
||||
effects = Object.create(effects)
|
||||
effects.procedureId = options.id
|
||||
const effects = effectCreator(options.id)
|
||||
return this._execute(effects, options)
|
||||
.then((x) =>
|
||||
matches(x)
|
||||
@@ -261,12 +261,12 @@ export class SystemForEmbassy implements System {
|
||||
}
|
||||
})
|
||||
}
|
||||
async exit(effects: HostSystemStartOs): Promise<void> {
|
||||
async exit(): Promise<void> {
|
||||
if (this.currentRunning) await this.currentRunning.clean()
|
||||
delete this.currentRunning
|
||||
}
|
||||
async _execute(
|
||||
effects: HostSystemStartOs,
|
||||
effects: Effects,
|
||||
options: {
|
||||
procedure: JsonPath
|
||||
input: unknown
|
||||
@@ -340,7 +340,7 @@ export class SystemForEmbassy implements System {
|
||||
throw new Error(`Could not find the path for ${options.procedure}`)
|
||||
}
|
||||
private async init(
|
||||
effects: HostSystemStartOs,
|
||||
effects: Effects,
|
||||
previousVersion: Optional<string>,
|
||||
timeoutMs: number | null,
|
||||
): Promise<void> {
|
||||
@@ -350,7 +350,7 @@ export class SystemForEmbassy implements System {
|
||||
await this.exportActions(effects)
|
||||
await this.exportNetwork(effects)
|
||||
}
|
||||
async exportNetwork(effects: HostSystemStartOs) {
|
||||
async exportNetwork(effects: Effects) {
|
||||
for (const [id, interfaceValue] of Object.entries(
|
||||
this.manifest.interfaces,
|
||||
)) {
|
||||
@@ -428,7 +428,7 @@ export class SystemForEmbassy implements System {
|
||||
)
|
||||
}
|
||||
}
|
||||
async exportActions(effects: HostSystemStartOs) {
|
||||
async exportActions(effects: Effects) {
|
||||
const manifest = this.manifest
|
||||
if (!manifest.actions) return
|
||||
for (const [actionId, action] of Object.entries(manifest.actions)) {
|
||||
@@ -457,7 +457,7 @@ export class SystemForEmbassy implements System {
|
||||
}
|
||||
}
|
||||
private async uninit(
|
||||
effects: HostSystemStartOs,
|
||||
effects: Effects,
|
||||
nextVersion: Optional<string>,
|
||||
timeoutMs: number | null,
|
||||
): Promise<void> {
|
||||
@@ -465,7 +465,7 @@ export class SystemForEmbassy implements System {
|
||||
await effects.setMainStatus({ status: "stopped" })
|
||||
}
|
||||
private async mainStart(
|
||||
effects: HostSystemStartOs,
|
||||
effects: Effects,
|
||||
timeoutMs: number | null,
|
||||
): Promise<void> {
|
||||
if (!!this.currentRunning) return
|
||||
@@ -473,7 +473,7 @@ export class SystemForEmbassy implements System {
|
||||
this.currentRunning = new MainLoop(this, effects)
|
||||
}
|
||||
private async mainStop(
|
||||
effects: HostSystemStartOs,
|
||||
effects: Effects,
|
||||
timeoutMs: number | null,
|
||||
): Promise<Duration> {
|
||||
const { currentRunning } = this
|
||||
@@ -491,7 +491,7 @@ export class SystemForEmbassy implements System {
|
||||
return durationValue
|
||||
}
|
||||
private async createBackup(
|
||||
effects: HostSystemStartOs,
|
||||
effects: Effects,
|
||||
timeoutMs: number | null,
|
||||
): Promise<void> {
|
||||
const backup = this.manifest.backup.create
|
||||
@@ -503,13 +503,11 @@ export class SystemForEmbassy implements System {
|
||||
await container.execFail([backup.entrypoint, ...backup.args], timeoutMs)
|
||||
} else {
|
||||
const moduleCode = await this.moduleCode
|
||||
await moduleCode.createBackup?.(
|
||||
new PolyfillEffects(effects, this.manifest),
|
||||
)
|
||||
await moduleCode.createBackup?.(polyfillEffects(effects, this.manifest))
|
||||
}
|
||||
}
|
||||
private async restoreBackup(
|
||||
effects: HostSystemStartOs,
|
||||
effects: Effects,
|
||||
timeoutMs: number | null,
|
||||
): Promise<void> {
|
||||
const restoreBackup = this.manifest.backup.restore
|
||||
@@ -528,19 +526,17 @@ export class SystemForEmbassy implements System {
|
||||
)
|
||||
} else {
|
||||
const moduleCode = await this.moduleCode
|
||||
await moduleCode.restoreBackup?.(
|
||||
new PolyfillEffects(effects, this.manifest),
|
||||
)
|
||||
await moduleCode.restoreBackup?.(polyfillEffects(effects, this.manifest))
|
||||
}
|
||||
}
|
||||
private async getConfig(
|
||||
effects: HostSystemStartOs,
|
||||
effects: Effects,
|
||||
timeoutMs: number | null,
|
||||
): Promise<T.ConfigRes> {
|
||||
return this.getConfigUncleaned(effects, timeoutMs).then(removePointers)
|
||||
}
|
||||
private async getConfigUncleaned(
|
||||
effects: HostSystemStartOs,
|
||||
effects: Effects,
|
||||
timeoutMs: number | null,
|
||||
): Promise<T.ConfigRes> {
|
||||
const config = this.manifest.config?.get
|
||||
@@ -564,7 +560,7 @@ export class SystemForEmbassy implements System {
|
||||
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, this.manifest)).then(
|
||||
return (await method(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)
|
||||
@@ -574,7 +570,7 @@ export class SystemForEmbassy implements System {
|
||||
}
|
||||
}
|
||||
private async setConfig(
|
||||
effects: HostSystemStartOs,
|
||||
effects: Effects,
|
||||
newConfigWithoutPointers: unknown,
|
||||
timeoutMs: number | null,
|
||||
): Promise<void> {
|
||||
@@ -617,7 +613,7 @@ export class SystemForEmbassy implements System {
|
||||
|
||||
const answer = matchSetResult.unsafeCast(
|
||||
await method(
|
||||
new PolyfillEffects(effects, this.manifest),
|
||||
polyfillEffects(effects, this.manifest),
|
||||
newConfig as U.Config,
|
||||
).then((x): T.SetResult => {
|
||||
if ("result" in x)
|
||||
@@ -636,7 +632,7 @@ export class SystemForEmbassy implements System {
|
||||
}
|
||||
}
|
||||
private async setConfigSetConfig(
|
||||
effects: HostSystemStartOs,
|
||||
effects: Effects,
|
||||
dependsOn: { [x: string]: readonly string[] },
|
||||
) {
|
||||
await effects.setDependencies({
|
||||
@@ -660,7 +656,7 @@ export class SystemForEmbassy implements System {
|
||||
}
|
||||
|
||||
private async migration(
|
||||
effects: HostSystemStartOs,
|
||||
effects: Effects,
|
||||
fromVersion: string,
|
||||
timeoutMs: number | null,
|
||||
): Promise<T.MigrationRes> {
|
||||
@@ -713,7 +709,7 @@ export class SystemForEmbassy implements System {
|
||||
if (!method)
|
||||
throw new Error("Expecting that the method migration exists")
|
||||
return (await method(
|
||||
new PolyfillEffects(effects, this.manifest),
|
||||
polyfillEffects(effects, this.manifest),
|
||||
fromVersion as string,
|
||||
).then((x) => {
|
||||
if ("result" in x) return x.result
|
||||
@@ -725,7 +721,7 @@ export class SystemForEmbassy implements System {
|
||||
return { configured: true }
|
||||
}
|
||||
private async properties(
|
||||
effects: HostSystemStartOs,
|
||||
effects: Effects,
|
||||
timeoutMs: number | null,
|
||||
): Promise<ReturnType<T.ExpectedExports.properties>> {
|
||||
// TODO BLU-J set the properties ever so often
|
||||
@@ -754,7 +750,7 @@ export class SystemForEmbassy implements System {
|
||||
if (!method)
|
||||
throw new Error("Expecting that the method properties exists")
|
||||
const properties = matchProperties.unsafeCast(
|
||||
await method(new PolyfillEffects(effects, this.manifest)).then((x) => {
|
||||
await method(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])
|
||||
@@ -765,7 +761,7 @@ export class SystemForEmbassy implements System {
|
||||
throw new Error(`Unknown type in the fetch properties: ${setConfigValue}`)
|
||||
}
|
||||
private async action(
|
||||
effects: HostSystemStartOs,
|
||||
effects: Effects,
|
||||
actionId: string,
|
||||
formData: unknown,
|
||||
timeoutMs: number | null,
|
||||
@@ -795,7 +791,7 @@ export class SystemForEmbassy implements System {
|
||||
const method = moduleCode.action?.[actionId]
|
||||
if (!method) throw new Error("Expecting that the method action exists")
|
||||
return (await method(
|
||||
new PolyfillEffects(effects, this.manifest),
|
||||
polyfillEffects(effects, this.manifest),
|
||||
formData as any,
|
||||
).then((x) => {
|
||||
if ("result" in x) return x.result
|
||||
@@ -805,7 +801,7 @@ export class SystemForEmbassy implements System {
|
||||
}
|
||||
}
|
||||
private async dependenciesCheck(
|
||||
effects: HostSystemStartOs,
|
||||
effects: Effects,
|
||||
id: string,
|
||||
oldConfig: unknown,
|
||||
timeoutMs: number | null,
|
||||
@@ -838,7 +834,7 @@ export class SystemForEmbassy implements System {
|
||||
`Expecting that the method dependency check ${id} exists`,
|
||||
)
|
||||
return (await method(
|
||||
new PolyfillEffects(effects, this.manifest),
|
||||
polyfillEffects(effects, this.manifest),
|
||||
oldConfig as any,
|
||||
).then((x) => {
|
||||
if ("result" in x) return x.result
|
||||
@@ -850,7 +846,7 @@ export class SystemForEmbassy implements System {
|
||||
}
|
||||
}
|
||||
private async dependenciesAutoconfig(
|
||||
effects: HostSystemStartOs,
|
||||
effects: Effects,
|
||||
id: string,
|
||||
oldConfig: unknown,
|
||||
timeoutMs: number | null,
|
||||
@@ -863,7 +859,7 @@ export class SystemForEmbassy implements System {
|
||||
`Expecting that the method dependency autoConfigure ${id} exists`,
|
||||
)
|
||||
return (await method(
|
||||
new PolyfillEffects(effects, this.manifest),
|
||||
polyfillEffects(effects, this.manifest),
|
||||
oldConfig as any,
|
||||
).then((x) => {
|
||||
if ("result" in x) return x.result
|
||||
@@ -961,7 +957,7 @@ function cleanConfigFromPointers<C, S>(
|
||||
}
|
||||
|
||||
async function updateConfig(
|
||||
effects: HostSystemStartOs,
|
||||
effects: Effects,
|
||||
manifest: Manifest,
|
||||
spec: unknown,
|
||||
mutConfigValue: unknown,
|
||||
|
||||
@@ -4,17 +4,19 @@ import { Volume } from "../../../Models/Volume"
|
||||
import * as child_process from "child_process"
|
||||
import { promisify } from "util"
|
||||
import { daemons, startSdk, T } from "@start9labs/start-sdk"
|
||||
import { HostSystemStartOs } from "../../HostSystemStartOs"
|
||||
import "isomorphic-fetch"
|
||||
import { Manifest } from "./matchManifest"
|
||||
import { DockerProcedureContainer } from "./DockerProcedureContainer"
|
||||
import * as cp from "child_process"
|
||||
import { Effects } from "../../../Models/Effects"
|
||||
export const execFile = promisify(cp.execFile)
|
||||
export class PolyfillEffects implements oet.Effects {
|
||||
constructor(
|
||||
readonly effects: HostSystemStartOs,
|
||||
private manifest: Manifest,
|
||||
) {}
|
||||
export const polyfillEffects = (
|
||||
effects: Effects,
|
||||
manifest: Manifest,
|
||||
): oet.Effects => {
|
||||
const self = {
|
||||
effects,
|
||||
manifest,
|
||||
async writeFile(input: {
|
||||
path: string
|
||||
volumeId: string
|
||||
@@ -24,12 +26,12 @@ export class PolyfillEffects implements oet.Effects {
|
||||
new Volume(input.volumeId, input.path).path,
|
||||
input.toWrite,
|
||||
)
|
||||
}
|
||||
},
|
||||
async readFile(input: { volumeId: string; path: string }): Promise<string> {
|
||||
return (
|
||||
await fs.readFile(new Volume(input.volumeId, input.path).path)
|
||||
).toString()
|
||||
}
|
||||
},
|
||||
async metadata(input: {
|
||||
volumeId: string
|
||||
path: string
|
||||
@@ -46,25 +48,34 @@ export class PolyfillEffects implements oet.Effects {
|
||||
len: stats.size,
|
||||
readonly: (stats.mode & 0o200) > 0,
|
||||
}
|
||||
}
|
||||
async createDir(input: { volumeId: string; path: string }): Promise<string> {
|
||||
},
|
||||
async createDir(input: {
|
||||
volumeId: string
|
||||
path: string
|
||||
}): Promise<string> {
|
||||
const path = new Volume(input.volumeId, input.path).path
|
||||
await fs.mkdir(path, { recursive: true })
|
||||
return path
|
||||
}
|
||||
async readDir(input: { volumeId: string; path: string }): Promise<string[]> {
|
||||
},
|
||||
async readDir(input: {
|
||||
volumeId: string
|
||||
path: string
|
||||
}): Promise<string[]> {
|
||||
return fs.readdir(new Volume(input.volumeId, input.path).path)
|
||||
}
|
||||
async removeDir(input: { volumeId: string; path: string }): Promise<string> {
|
||||
},
|
||||
async removeDir(input: {
|
||||
volumeId: string
|
||||
path: string
|
||||
}): Promise<string> {
|
||||
const path = new Volume(input.volumeId, input.path).path
|
||||
await fs.rmdir(new Volume(input.volumeId, input.path).path, {
|
||||
recursive: true,
|
||||
})
|
||||
return path
|
||||
}
|
||||
},
|
||||
removeFile(input: { volumeId: string; path: string }): Promise<void> {
|
||||
return fs.rm(new Volume(input.volumeId, input.path).path)
|
||||
}
|
||||
},
|
||||
async writeJsonFile(input: {
|
||||
volumeId: string
|
||||
path: string
|
||||
@@ -74,7 +85,7 @@ export class PolyfillEffects implements oet.Effects {
|
||||
new Volume(input.volumeId, input.path).path,
|
||||
JSON.stringify(input.toWrite),
|
||||
)
|
||||
}
|
||||
},
|
||||
async readJsonFile(input: {
|
||||
volumeId: string
|
||||
path: string
|
||||
@@ -84,7 +95,7 @@ export class PolyfillEffects implements oet.Effects {
|
||||
await fs.readFile(new Volume(input.volumeId, input.path).path)
|
||||
).toString(),
|
||||
)
|
||||
}
|
||||
},
|
||||
runCommand({
|
||||
command,
|
||||
args,
|
||||
@@ -96,8 +107,8 @@ export class PolyfillEffects implements oet.Effects {
|
||||
}): Promise<oet.ResultType<string>> {
|
||||
return startSdk
|
||||
.runCommand(
|
||||
this.effects,
|
||||
{ id: this.manifest.main.image },
|
||||
effects,
|
||||
{ id: manifest.main.image },
|
||||
[command, ...(args || [])],
|
||||
{},
|
||||
)
|
||||
@@ -108,20 +119,20 @@ export class PolyfillEffects implements oet.Effects {
|
||||
.then((x: any) =>
|
||||
!!x.stderr ? { error: x.stderr } : { result: x.stdout },
|
||||
)
|
||||
}
|
||||
},
|
||||
runDaemon(input: { command: string; args?: string[] | undefined }): {
|
||||
wait(): Promise<oet.ResultType<string>>
|
||||
term(): Promise<void>
|
||||
} {
|
||||
const dockerProcedureContainer = DockerProcedureContainer.of(
|
||||
this.effects,
|
||||
this.manifest.main,
|
||||
this.manifest.volumes,
|
||||
effects,
|
||||
manifest.main,
|
||||
manifest.volumes,
|
||||
)
|
||||
const daemon = dockerProcedureContainer.then((dockerProcedureContainer) =>
|
||||
daemons.runCommand()(
|
||||
this.effects,
|
||||
{ id: this.manifest.main.image },
|
||||
effects,
|
||||
{ id: manifest.main.image },
|
||||
[input.command, ...(input.args || [])],
|
||||
{
|
||||
overlay: dockerProcedureContainer.overlay,
|
||||
@@ -137,7 +148,7 @@ export class PolyfillEffects implements oet.Effects {
|
||||
),
|
||||
term: () => daemon.then((daemon) => daemon.term()),
|
||||
}
|
||||
}
|
||||
},
|
||||
async chown(input: {
|
||||
volumeId: string
|
||||
path: string
|
||||
@@ -145,8 +156,8 @@ export class PolyfillEffects implements oet.Effects {
|
||||
}): Promise<null> {
|
||||
await startSdk
|
||||
.runCommand(
|
||||
this.effects,
|
||||
{ id: this.manifest.main.image },
|
||||
effects,
|
||||
{ id: manifest.main.image },
|
||||
["chown", "--recursive", input.uid, `/drive/${input.path}`],
|
||||
{
|
||||
mounts: [
|
||||
@@ -172,7 +183,7 @@ export class PolyfillEffects implements oet.Effects {
|
||||
}
|
||||
})
|
||||
return null
|
||||
}
|
||||
},
|
||||
async chmod(input: {
|
||||
volumeId: string
|
||||
path: string
|
||||
@@ -180,8 +191,8 @@ export class PolyfillEffects implements oet.Effects {
|
||||
}): Promise<null> {
|
||||
await startSdk
|
||||
.runCommand(
|
||||
this.effects,
|
||||
{ id: this.manifest.main.image },
|
||||
effects,
|
||||
{ id: manifest.main.image },
|
||||
["chmod", "--recursive", input.mode, `/drive/${input.path}`],
|
||||
{
|
||||
mounts: [
|
||||
@@ -207,33 +218,34 @@ export class PolyfillEffects implements oet.Effects {
|
||||
}
|
||||
})
|
||||
return null
|
||||
}
|
||||
},
|
||||
sleep(timeMs: number): Promise<null> {
|
||||
return new Promise((resolve) => setTimeout(resolve, timeMs))
|
||||
}
|
||||
},
|
||||
trace(whatToPrint: string): void {
|
||||
console.trace(whatToPrint)
|
||||
}
|
||||
},
|
||||
warn(whatToPrint: string): void {
|
||||
console.warn(whatToPrint)
|
||||
}
|
||||
},
|
||||
error(whatToPrint: string): void {
|
||||
console.error(whatToPrint)
|
||||
}
|
||||
},
|
||||
debug(whatToPrint: string): void {
|
||||
console.debug(whatToPrint)
|
||||
}
|
||||
},
|
||||
info(whatToPrint: string): void {
|
||||
console.log(false)
|
||||
}
|
||||
},
|
||||
is_sandboxed(): boolean {
|
||||
return false
|
||||
}
|
||||
},
|
||||
exists(input: { volumeId: string; path: string }): Promise<boolean> {
|
||||
return this.metadata(input)
|
||||
return self
|
||||
.metadata(input)
|
||||
.then(() => true)
|
||||
.catch(() => false)
|
||||
}
|
||||
},
|
||||
async fetch(
|
||||
url: string,
|
||||
options?:
|
||||
@@ -269,7 +281,7 @@ export class PolyfillEffects implements oet.Effects {
|
||||
text: () => fetched.text(),
|
||||
json: () => fetched.json(),
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
runRsync(rsyncOptions: {
|
||||
srcVolume: string
|
||||
@@ -282,10 +294,10 @@ export class PolyfillEffects implements oet.Effects {
|
||||
wait: () => Promise<null>
|
||||
progress: () => Promise<number>
|
||||
} {
|
||||
let secondRun: ReturnType<typeof this._runRsync> | undefined
|
||||
let firstRun = this._runRsync(rsyncOptions)
|
||||
let secondRun: ReturnType<typeof self._runRsync> | undefined
|
||||
let firstRun = self._runRsync(rsyncOptions)
|
||||
let waitValue = firstRun.wait().then((x) => {
|
||||
secondRun = this._runRsync(rsyncOptions)
|
||||
secondRun = self._runRsync(rsyncOptions)
|
||||
return secondRun.wait()
|
||||
})
|
||||
const id = async () => {
|
||||
@@ -300,7 +312,7 @@ export class PolyfillEffects implements oet.Effects {
|
||||
return (await firstRun.progress()) / 2.0
|
||||
}
|
||||
return { id, wait, progress }
|
||||
}
|
||||
},
|
||||
_runRsync(rsyncOptions: {
|
||||
srcVolume: string
|
||||
dstVolume: string
|
||||
@@ -366,7 +378,7 @@ export class PolyfillEffects implements oet.Effects {
|
||||
const wait = () => waitPromise
|
||||
const progress = () => Promise.resolve(percentage)
|
||||
return { id, wait, progress }
|
||||
}
|
||||
},
|
||||
async diskUsage(
|
||||
options?: { volumeId: string; path: string } | undefined,
|
||||
): Promise<{ used: number; total: number }> {
|
||||
@@ -404,7 +416,9 @@ export class PolyfillEffects implements oet.Effects {
|
||||
}
|
||||
}
|
||||
return output
|
||||
},
|
||||
}
|
||||
return self
|
||||
}
|
||||
|
||||
function parseDfOutput(output: string): { used: number; total: number } {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ExecuteResult, System } from "../../Interfaces/System"
|
||||
import { unNestPath } from "../../Models/JsonPath"
|
||||
import matches, { any, number, object, string, tuple } from "ts-matches"
|
||||
import { HostSystemStartOs } from "../HostSystemStartOs"
|
||||
import { hostSystemStartOs } from "../HostSystemStartOs"
|
||||
import { Effects } from "../../Models/Effects"
|
||||
import { RpcResult, matchRpcResult } from "../RpcListener"
|
||||
import { duration } from "../../Models/Duration"
|
||||
@@ -15,7 +15,7 @@ export class SystemForStartOs implements System {
|
||||
}
|
||||
constructor(readonly abi: T.ABI) {}
|
||||
async execute(
|
||||
effects: HostSystemStartOs,
|
||||
effectCreator: ReturnType<typeof hostSystemStartOs>,
|
||||
options: {
|
||||
id: string
|
||||
procedure:
|
||||
@@ -36,8 +36,7 @@ export class SystemForStartOs implements System {
|
||||
timeout?: number | undefined
|
||||
},
|
||||
): Promise<RpcResult> {
|
||||
effects = Object.create(effects)
|
||||
effects.procedureId = options.id
|
||||
const effects = effectCreator(options.id)
|
||||
return this._execute(effects, options)
|
||||
.then((x) =>
|
||||
matches(x)
|
||||
|
||||
@@ -2,6 +2,7 @@ import { types as T } from "@start9labs/start-sdk"
|
||||
|
||||
import { CallbackHolder } from "../Models/CallbackHolder"
|
||||
import { Effects } from "../Models/Effects"
|
||||
|
||||
export type HostSystem = Effects
|
||||
export type GetHostSystem = (callbackHolder: CallbackHolder) => HostSystem
|
||||
export type GetHostSystem = (
|
||||
callbackHolder: CallbackHolder,
|
||||
) => (procedureId: null | string) => Effects
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { types as T } from "@start9labs/start-sdk"
|
||||
import { JsonPath } from "../Models/JsonPath"
|
||||
import { HostSystemStartOs } from "../Adapters/HostSystemStartOs"
|
||||
import { RpcResult } from "../Adapters/RpcListener"
|
||||
import { hostSystemStartOs } from "../Adapters/HostSystemStartOs"
|
||||
export type ExecuteResult =
|
||||
| { ok: unknown }
|
||||
| { err: { code: number; message: string } }
|
||||
@@ -12,7 +12,7 @@ export interface System {
|
||||
// stop(effects: Effects, options: { timeout: number, signal?: number }): Promise<void>
|
||||
|
||||
execute(
|
||||
effects: T.Effects,
|
||||
effectCreator: ReturnType<typeof hostSystemStartOs>,
|
||||
options: {
|
||||
id: string
|
||||
procedure: JsonPath
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { RpcListener } from "./Adapters/RpcListener"
|
||||
import { SystemForEmbassy } from "./Adapters/Systems/SystemForEmbassy"
|
||||
import { HostSystemStartOs } from "./Adapters/HostSystemStartOs"
|
||||
import { hostSystemStartOs } from "./Adapters/HostSystemStartOs"
|
||||
import { AllGetDependencies } from "./Interfaces/AllGetDependencies"
|
||||
import { getSystem } from "./Adapters/Systems"
|
||||
|
||||
const getDependencies: AllGetDependencies = {
|
||||
system: getSystem,
|
||||
hostSystem: () => HostSystemStartOs.of,
|
||||
hostSystem: () => hostSystemStartOs,
|
||||
}
|
||||
|
||||
new RpcListener(getDependencies)
|
||||
|
||||
@@ -16,7 +16,8 @@ mkdir -p ./firmware/$PLATFORM
|
||||
|
||||
cd ./firmware/$PLATFORM
|
||||
|
||||
mapfile -t firmwares <<< "$(jq -c ".[] | select(.platform[] | contains(\"$PLATFORM\"))" ../../build/lib/firmware.json)"
|
||||
firmwares=()
|
||||
while IFS= read -r line; do firmwares+=("$line"); done < <(jq -c ".[] | select(.platform[] | contains(\"$PLATFORM\"))" ../../build/lib/firmware.json)
|
||||
for firmware in "${firmwares[@]}"; do
|
||||
if [ -n "$firmware" ]; then
|
||||
id=$(echo "$firmware" | jq --raw-output '.id')
|
||||
|
||||
Reference in New Issue
Block a user