diff --git a/src/darwin.ts b/src/darwin.ts index bb059f3..d1f58a9 100644 --- a/src/darwin.ts +++ b/src/darwin.ts @@ -1,13 +1,15 @@ import cp from "node:child_process"; import fs from "node:fs/promises"; import { Remitter } from "remitter"; -import { OVMStatusName } from "./type"; -import type { OVMDarwinOptions, OVMEventData, OVMInfo, OVMState } from "./type"; +import { OVMDarwinStatusName } from "./type"; +import type { OVMDarwinOptions, OVMDarwinEventData, OVMDarwinInfo, OVMDarwinState } from "./type"; import { Restful } from "./event_restful"; import { Request } from "./request"; +import path from "node:path"; +import { tmpdir } from "node:os"; export class DarwinOVM { - private readonly remitter = new Remitter(); + private readonly remitter = new Remitter(); private eventSocketPath: string; private request: Request; @@ -23,13 +25,24 @@ export class DarwinOVM { return ovm; } - public on(event: keyof OVMEventData, listener: (datum: OVMEventData["status"]) => void): void { + public on(event: keyof OVMDarwinEventData, listener: (datum: OVMDarwinEventData["status"]) => void): void { this.remitter.on(event, listener); } private async initEventRestful(): Promise { - const restful = new Restful(this.remitter); - this.eventSocketPath = await restful.start(); + const restful = new Restful((name, message) => { + if (name in OVMDarwinStatusName) { + this.remitter.emit("status", { + name: name as OVMDarwinStatusName, + message, + }); + } + }); + + const dir = await fs.mkdtemp(path.join(tmpdir(), "ovm-")); + const socketPath = path.join(dir, "event-restful.sock"); + restful.start(socketPath); + this.eventSocketPath = socketPath; } private initRequest(): void { @@ -90,17 +103,17 @@ export class DarwinOVM { launchTimeout .catch(() => { this.remitter.emit("status", { - name: OVMStatusName.Error, + name: OVMDarwinStatusName.Error, message: "OVM start timeout", }); }); } - public async info(): Promise { + public async info(): Promise { return this.request.info(); } - public async state(): Promise { + public async state(): Promise { return this.request.state(); } diff --git a/src/event_restful.ts b/src/event_restful.ts index 8b7525e..7f05edd 100644 --- a/src/event_restful.ts +++ b/src/event_restful.ts @@ -1,17 +1,12 @@ import url from "node:url"; import http from "node:http"; -import type { OVMEventData } from "./type"; -import { OVMStatusName } from "./type"; -import type { Remitter } from "remitter"; -import fs from "node:fs/promises"; -import { tmpdir } from "node:os"; -import path from "node:path"; + export class Restful { private readonly server: http.Server; public constructor( - private readonly emitter: Remitter, + callback: (name: string, message: string) => void, ) { this.server = http.createServer((request, response) => { if (!request.url) { @@ -23,15 +18,7 @@ export class Restful { response.statusCode = 200; response.end("ok"); - const event = parsedUrl.query.event as OVMStatusName; - const message = parsedUrl.query.message as string; - - if (event in OVMStatusName) { - this.emitter.emit("status", { - name: event, - message: message, - }); - } + callback(parsedUrl.query.event as string, parsedUrl.query.message as string); } else { response.statusCode = 404; response.end("Not Found"); @@ -39,12 +26,8 @@ export class Restful { }); } - public async start(): Promise { - const dir = await fs.mkdtemp(path.join(tmpdir(), "ovm-")); - const socketPath = path.join(dir, "event-restful.sock"); + public start(socketPath: string): void { this.server.listen(socketPath); - - return socketPath; } public stop(): void { diff --git a/src/index.ts b/src/index.ts index faf0095..cb77eb8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,14 +6,14 @@ export const createDarwinOVM = (options: OVMDarwinOptions): Promise = }; export { - OVMStatusName, - OVMVzState, + OVMDarwinStatusName, + OVMDarwinVzState, } from "./type"; export type { - OVMEventData, + OVMDarwinEventData, OVMDarwinOptions, - OVMInfo, - OVMState, + OVMDarwinInfo, + OVMDarwinState, } from "./type"; export type { DarwinOVM }; diff --git a/src/request.ts b/src/request.ts index 7dafe58..68c7bb3 100644 --- a/src/request.ts +++ b/src/request.ts @@ -1,6 +1,36 @@ import path from "node:path"; import http from "node:http"; -import type { OVMInfo, OVMState } from "./type"; +import type { OVMDarwinInfo, OVMDarwinState } from "./type"; +import type { RequestOptions } from "http"; + +const generateRequest = async (option: RequestOptions): Promise => { + return new Promise((resolve, reject) => { + http.request({ + timeout: 200, + ...option, + }, (response) => { + response.setEncoding("utf8"); + + let body = ""; + response.on("data", (chunk) => { + body += chunk; + }); + + response.on("end", () => { + const { statusCode } = response; + if (!statusCode || statusCode >= 400) { + return reject(new Error(`Request Failed. Status Code: ${statusCode}, Response: ${body}`)); + } + + return resolve(body); + }); + }) + .once("error", (error) => { + reject(error); + }) + .end(); + }); +}; export class Request { private readonly socketPath: string; @@ -10,33 +40,10 @@ export class Request { } private async request(p: string, method: string): Promise { - return new Promise((resolve, reject) => { - http.request({ - socketPath: this.socketPath, - path: `http://ovm/${p}`, - method: method, - timeout: 200, - }, (response) => { - response.setEncoding("utf8"); - - let body = ""; - response.on("data", (chunk) => { - body += chunk; - }); - - response.on("end", () => { - const { statusCode } = response; - if (!statusCode || statusCode >= 400) { - return reject(new Error(`Request Failed. Status Code: ${statusCode}, Response: ${body}`)); - } else { - resolve(body); - } - }); - }) - .once("error", (error) => { - reject(error); - }) - .end(); + return await generateRequest({ + socketPath: this.socketPath, + path: `http://ovm/${p}`, + method: method, }); } @@ -58,12 +65,12 @@ export class Request { } } - public async state(): Promise { - return JSON.parse(await this.send("state")) as OVMState; + public async state(): Promise { + return JSON.parse(await this.send("state")) as OVMDarwinState; } - public async info(): Promise { - return JSON.parse(await this.send("info")) as OVMInfo; + public async info(): Promise { + return JSON.parse(await this.send("info")) as OVMDarwinInfo; } public async pause(): Promise { diff --git a/src/type.ts b/src/type.ts index c2d2443..245ac72 100644 --- a/src/type.ts +++ b/src/type.ts @@ -17,7 +17,7 @@ export interface OVMDarwinOptions { extendShareDir?: string, } -export enum OVMStatusName { +export enum OVMDarwinStatusName { Initializing = "Initializing", GVProxyReady = "GVProxyReady", IgnitionProgress = "IgnitionProgress", @@ -27,21 +27,21 @@ export enum OVMStatusName { Error = "Error", } -export interface OVMEventData { +export interface OVMDarwinEventData { status: { - name: OVMStatusName, + name: OVMDarwinStatusName, message: string, } } -export interface OVMInfo { +export interface OVMDarwinInfo { podmanSocketPath: string; } /** * @see https://github.com/Code-Hex/vz/blob/bd29a7ea3d39465c4224bfb01e990e8c220a8449/virtualization.go#L23 */ -export enum OVMVzState { +export enum OVMDarwinVzState { VirtualMachineStateStopped = "VirtualMachineStateStopped", VirtualMachineStateRunning = "VirtualMachineStateRunning", VirtualMachineStatePaused = "VirtualMachineStatePaused", @@ -54,8 +54,8 @@ export enum OVMVzState { VirtualMachineStateRestoring = "VirtualMachineStateRestoring", } -export interface OVMState { - state: OVMVzState; +export interface OVMDarwinState { + state: OVMDarwinVzState; canStart: boolean; canPause: boolean; canResume: boolean;