Feature/callbacks (#2678)

* wip

* initialize callbacks

* wip

* smtp

* list_service_interfaces

* wip

* wip

* fix domains

* fix hostname handling in NetService

* misc fixes

* getInstalledPackages

* misc fixes

* publish v6 lib

* refactor service effects

* fix import

* fix container runtime

* fix tests

* apply suggestions from review
This commit is contained in:
Aiden McClelland
2024-07-25 11:44:51 -06:00
committed by GitHub
parent ab465a755e
commit b36b62c68e
113 changed files with 4853 additions and 2517 deletions

View File

@@ -3,8 +3,8 @@ import * as fs from "fs/promises"
import { polyfillEffects } from "./polyfillEffects"
import { Duration, duration, fromDuration } from "../../../Models/Duration"
import { System } from "../../../Interfaces/System"
import { matchManifest, Manifest, Procedure } from "./matchManifest"
import { System, Procedure } from "../../../Interfaces/System"
import { matchManifest, Manifest } from "./matchManifest"
import * as childProcess from "node:child_process"
import { DockerProcedureContainer } from "./DockerProcedureContainer"
import { promisify } from "node:util"
@@ -27,7 +27,6 @@ import {
Parser,
array,
} from "ts-matches"
import { hostSystemStartOs } from "../../HostSystemStartOs"
import { JsonPath, unNestPath } from "../../../Models/JsonPath"
import { RpcResult, matchRpcResult } from "../../RpcListener"
import { CT } from "@start9labs/start-sdk"
@@ -48,6 +47,7 @@ import {
transformConfigSpec,
transformOldConfigToNew,
} from "./transformConfigSpec"
import { MainEffects } from "@start9labs/start-sdk/cjs/lib/StartSdk"
type Optional<A> = A | undefined | null
function todo(): never {
@@ -203,16 +203,39 @@ export class SystemForEmbassy implements System {
readonly manifest: Manifest,
readonly moduleCode: Partial<U.ExpectedExports>,
) {}
async init(): Promise<void> {}
async exit(): Promise<void> {
if (this.currentRunning) await this.currentRunning.clean()
delete this.currentRunning
}
async start(effects: MainEffects): Promise<void> {
if (!!this.currentRunning) return
this.currentRunning = await MainLoop.of(this, effects)
}
callCallback(_callback: number, _args: any[]): void {}
async stop(): Promise<void> {
const { currentRunning } = this
this.currentRunning?.clean()
delete this.currentRunning
if (currentRunning) {
await currentRunning.clean({
timeout: fromDuration(this.manifest.main["sigterm-timeout"] || "30s"),
})
}
}
async execute(
effectCreator: ReturnType<typeof hostSystemStartOs>,
effects: Effects,
options: {
id: string
procedure: JsonPath
input: unknown
timeout?: number | undefined
},
): Promise<RpcResult> {
const effects = effectCreator(options.id)
return this._execute(effects, options)
.then((x) =>
matches(x)
@@ -267,10 +290,6 @@ export class SystemForEmbassy implements System {
}
})
}
async exit(): Promise<void> {
if (this.currentRunning) await this.currentRunning.clean()
delete this.currentRunning
}
async _execute(
effects: Effects,
options: {
@@ -294,7 +313,7 @@ export class SystemForEmbassy implements System {
case "/actions/metadata":
return todo()
case "/init":
return this.init(
return this.initProcedure(
effects,
string.optional().unsafeCast(input),
options.timeout || null,
@@ -305,10 +324,6 @@ export class SystemForEmbassy implements System {
string.optional().unsafeCast(input),
options.timeout || null,
)
case "/main/start":
return this.mainStart(effects, options.timeout || null)
case "/main/stop":
return this.mainStop(effects, options.timeout || null)
default:
const procedures = unNestPath(options.procedure)
switch (true) {
@@ -345,7 +360,14 @@ export class SystemForEmbassy implements System {
}
throw new Error(`Could not find the path for ${options.procedure}`)
}
private async init(
async sandbox(
effects: Effects,
options: { procedure: Procedure; input: unknown; timeout?: number },
): Promise<RpcResult> {
return this.execute(effects, options)
}
private async initProcedure(
effects: Effects,
previousVersion: Optional<string>,
timeoutMs: number | null,
@@ -470,42 +492,22 @@ export class SystemForEmbassy implements System {
// TODO Do a migration down if the version exists
await effects.setMainStatus({ status: "stopped" })
}
private async mainStart(
effects: Effects,
timeoutMs: number | null,
): Promise<void> {
if (!!this.currentRunning) return
this.currentRunning = new MainLoop(this, effects)
}
private async mainStop(
effects: Effects,
timeoutMs: number | null,
): Promise<void> {
try {
const { currentRunning } = this
this.currentRunning?.clean()
delete this.currentRunning
if (currentRunning) {
await currentRunning.clean({
timeout: utils.inMs(this.manifest.main["sigterm-timeout"]),
})
}
return
} finally {
await effects.setMainStatus({ status: "stopped" })
}
}
private async createBackup(
effects: Effects,
timeoutMs: number | null,
): Promise<void> {
const backup = this.manifest.backup.create
if (backup.type === "docker") {
const container = await DockerProcedureContainer.of(effects, backup, {
...this.manifest.volumes,
BACKUP: { type: "backup", readonly: false },
})
const container = await DockerProcedureContainer.of(
effects,
this.manifest.id,
backup,
{
...this.manifest.volumes,
BACKUP: { type: "backup", readonly: false },
},
)
await container.execFail([backup.entrypoint, ...backup.args], timeoutMs)
} else {
const moduleCode = await this.moduleCode
@@ -520,6 +522,7 @@ export class SystemForEmbassy implements System {
if (restoreBackup.type === "docker") {
const container = await DockerProcedureContainer.of(
effects,
this.manifest.id,
restoreBackup,
{
...this.manifest.volumes,
@@ -552,6 +555,7 @@ export class SystemForEmbassy implements System {
if (config.type === "docker") {
const container = await DockerProcedureContainer.of(
effects,
this.manifest.id,
config,
this.manifest.volumes,
)
@@ -594,6 +598,7 @@ export class SystemForEmbassy implements System {
if (setConfigValue.type === "docker") {
const container = await DockerProcedureContainer.of(
effects,
this.manifest.id,
setConfigValue,
this.manifest.volumes,
)
@@ -702,6 +707,7 @@ export class SystemForEmbassy implements System {
if (procedure.type === "docker") {
const container = await DockerProcedureContainer.of(
effects,
this.manifest.id,
procedure,
this.manifest.volumes,
)
@@ -744,6 +750,7 @@ export class SystemForEmbassy implements System {
if (setConfigValue.type === "docker") {
const container = await DockerProcedureContainer.of(
effects,
this.manifest.id,
setConfigValue,
this.manifest.volumes,
)
@@ -785,6 +792,7 @@ export class SystemForEmbassy implements System {
if (actionProcedure.type === "docker") {
const container = await DockerProcedureContainer.of(
effects,
this.manifest.id,
actionProcedure,
this.manifest.volumes,
)
@@ -825,6 +833,7 @@ export class SystemForEmbassy implements System {
if (actionProcedure.type === "docker") {
const container = await DockerProcedureContainer.of(
effects,
this.manifest.id,
actionProcedure,
this.manifest.volumes,
)
@@ -1039,15 +1048,15 @@ async function updateConfig(
}
}
const url: string =
filled === null
filled === null || filled.addressInfo === null
? ""
: catchFn(() =>
utils.hostnameInfoToAddress(
specValue.target === "lan-address"
? filled.addressInfo.localHostnames[0] ||
filled.addressInfo.onionHostnames[0]
: filled.addressInfo.onionHostnames[0] ||
filled.addressInfo.localHostnames[0],
? filled.addressInfo!.localHostnames[0] ||
filled.addressInfo!.onionHostnames[0]
: filled.addressInfo!.onionHostnames[0] ||
filled.addressInfo!.localHostnames[0],
),
) || ""
mutConfigValue[key] = url