mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
@@ -1,7 +1,8 @@
|
||||
export abstract class Drop {
|
||||
private static weak: { [id: number]: Drop } = {}
|
||||
private static registry = new FinalizationRegistry((id: number) => {
|
||||
Drop.weak[id].drop()
|
||||
const weak = Drop.weak[id]
|
||||
if (weak) weak.drop()
|
||||
})
|
||||
private static idCtr: number = 0
|
||||
private id: number
|
||||
|
||||
@@ -34,10 +34,15 @@ export class GetSslCertificate {
|
||||
* Watches the SSL Certificate for the given hostnames if permitted. Returns an async iterator that yields whenever the value changes
|
||||
*/
|
||||
async *watch() {
|
||||
while (true) {
|
||||
let callback: () => void
|
||||
const resolveCell = { resolve: () => {} }
|
||||
this.effects.onLeaveContext(() => {
|
||||
resolveCell.resolve()
|
||||
})
|
||||
while (this.effects.isInContext) {
|
||||
let callback: () => void = () => {}
|
||||
const waitForNext = new Promise<void>((resolve) => {
|
||||
callback = resolve
|
||||
resolveCell.resolve = resolve
|
||||
})
|
||||
yield await this.effects.getSslCertificate({
|
||||
hostnames: this.hostnames,
|
||||
|
||||
@@ -4,6 +4,7 @@ import * as cp from "child_process"
|
||||
import { promisify } from "util"
|
||||
import { Buffer } from "node:buffer"
|
||||
import { once } from "../../../base/lib/util/once"
|
||||
import { Drop } from "./Drop"
|
||||
|
||||
export const execFile = promisify(cp.execFile)
|
||||
const False = () => false
|
||||
@@ -45,16 +46,8 @@ export interface ExecSpawnable {
|
||||
* Implements:
|
||||
* @see {@link ExecSpawnable}
|
||||
*/
|
||||
export class SubContainer implements ExecSpawnable {
|
||||
private static finalizationEffects: { effects?: T.Effects } = {}
|
||||
private static registry = new FinalizationRegistry((guid: string) => {
|
||||
if (this.finalizationEffects.effects) {
|
||||
this.finalizationEffects.effects.subcontainer
|
||||
.destroyFs({ guid })
|
||||
.catch((e) => console.error("failed to cleanup SubContainer", guid, e))
|
||||
}
|
||||
})
|
||||
|
||||
export class SubContainer extends Drop implements ExecSpawnable {
|
||||
private destroyed = false
|
||||
private leader: cp.ChildProcess
|
||||
private leaderExited: boolean = false
|
||||
private waitProc: () => Promise<null>
|
||||
@@ -64,8 +57,7 @@ export class SubContainer implements ExecSpawnable {
|
||||
readonly rootfs: string,
|
||||
readonly guid: T.Guid,
|
||||
) {
|
||||
if (!SubContainer.finalizationEffects.effects)
|
||||
SubContainer.finalizationEffects.effects = effects
|
||||
super()
|
||||
this.leaderExited = false
|
||||
this.leader = cp.spawn("start-cli", ["subcontainer", "launch", rootfs], {
|
||||
killSignal: "SIGKILL",
|
||||
@@ -106,7 +98,6 @@ export class SubContainer implements ExecSpawnable {
|
||||
name,
|
||||
})
|
||||
const res = new SubContainer(effects, imageId, rootfs, guid)
|
||||
SubContainer.registry.register(res, guid, res)
|
||||
|
||||
const shared = ["dev", "sys"]
|
||||
if (!!sharedRun) {
|
||||
@@ -212,14 +203,20 @@ export class SubContainer implements ExecSpawnable {
|
||||
|
||||
get destroy() {
|
||||
return async () => {
|
||||
const guid = this.guid
|
||||
await this.killLeader()
|
||||
await this.effects.subcontainer.destroyFs({ guid })
|
||||
SubContainer.registry.unregister(this)
|
||||
if (!this.destroyed) {
|
||||
const guid = this.guid
|
||||
await this.killLeader()
|
||||
await this.effects.subcontainer.destroyFs({ guid })
|
||||
this.destroyed = true
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
onDrop(): void {
|
||||
this.destroy()
|
||||
}
|
||||
|
||||
async exec(
|
||||
command: string[],
|
||||
options?: CommandOptions & ExecOptions,
|
||||
|
||||
@@ -152,7 +152,7 @@ export class FileHelper<A> {
|
||||
}
|
||||
|
||||
private async readConst(effects: T.Effects): Promise<A | null> {
|
||||
const watch = this.readWatch()
|
||||
const watch = this.readWatch(effects)
|
||||
const res = await watch.next()
|
||||
if (effects.constRetry) {
|
||||
if (!this.consts.includes(effects.constRetry))
|
||||
@@ -165,9 +165,9 @@ export class FileHelper<A> {
|
||||
return res.value
|
||||
}
|
||||
|
||||
private async *readWatch() {
|
||||
private async *readWatch(effects: T.Effects) {
|
||||
let res
|
||||
while (true) {
|
||||
while (effects.isInContext) {
|
||||
if (await exists(this.path)) {
|
||||
const ctrl = new AbortController()
|
||||
const watch = fs.watch(this.path, {
|
||||
@@ -194,10 +194,11 @@ export class FileHelper<A> {
|
||||
}
|
||||
|
||||
private readOnChange(
|
||||
effects: T.Effects,
|
||||
callback: (value: A | null, error?: Error) => void | Promise<void>,
|
||||
) {
|
||||
;(async () => {
|
||||
for await (const value of this.readWatch()) {
|
||||
for await (const value of this.readWatch(effects)) {
|
||||
try {
|
||||
await callback(value)
|
||||
} catch (e) {
|
||||
@@ -221,10 +222,11 @@ export class FileHelper<A> {
|
||||
return {
|
||||
once: () => this.readOnce(),
|
||||
const: (effects: T.Effects) => this.readConst(effects),
|
||||
watch: () => this.readWatch(),
|
||||
watch: (effects: T.Effects) => this.readWatch(effects),
|
||||
onChange: (
|
||||
effects: T.Effects,
|
||||
callback: (value: A | null, error?: Error) => void | Promise<void>,
|
||||
) => this.readOnChange(callback),
|
||||
) => this.readOnChange(effects, callback),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user