Skip to content

Commit

Permalink
feat(windows): support windows
Browse files Browse the repository at this point in the history
Signed-off-by: Kevin Cui <[email protected]>
  • Loading branch information
BlackHole1 committed Jul 3, 2024
1 parent 38370e9 commit cd23f2c
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 4 deletions.
1 change: 1 addition & 0 deletions cspell.config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ words:
- vsock
- btrfs
- chrony
- npipe
dictionaries:
- companies
- softwareTerms
Expand Down
13 changes: 11 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
import type { OVMDarwinOptions } from "./type";
import type { OVMDarwinOptions, OVMWindowsOptions } from "./type";
import { DarwinOVM } from "./darwin";
import { WindowsOVM } from "./windows";

export const createDarwinOVM = (options: OVMDarwinOptions): Promise<DarwinOVM> => {
return DarwinOVM.create(options);
};

export const createWindowsOVM = (options: OVMWindowsOptions): WindowsOVM => {
return WindowsOVM.create(options);
};

export {
OVMDarwinAppEventValue,
OVMDarwinVzState,
OVMWindowsSysEventValue,
OVMWindowsAppEventValue,
} from "./type";

export type {
OVMDarwinEventData,
OVMDarwinOptions,
OVMDarwinInfo,
OVMDarwinState,
OVMWindowsOptions,
OVMWindowsEventData,
} from "./type";
export type { DarwinOVM };
export type { DarwinOVM, WindowsOVM };
27 changes: 25 additions & 2 deletions src/request.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import path from "node:path";
import http from "node:http";
import type { OVMDarwinInfo, OVMDarwinState } from "./type";
import type { OVMDarwinInfo, OVMDarwinState, OVMWindowsInfo } from "./type";

enum Method {
GET = "GET",
Expand All @@ -9,9 +9,10 @@ enum Method {
}

const DEFAULT_TIMEOUT = 200;
const NEVER_TIMEOUT = 0;

abstract class Request {
public abstract info(): Promise<OVMDarwinInfo>;
public abstract info(): Promise<OVMDarwinInfo | OVMWindowsInfo>;

protected readonly socketPath: string;
protected constructor(socketPath: string) {
Expand Down Expand Up @@ -90,3 +91,25 @@ export class RequestDarwin extends Request {
});
}
}

export class RequestWindows extends Request {
public constructor(name: string) {
super(`//./pipe/ovm-${name}`);
}

public async info(): Promise<OVMWindowsInfo> {
return JSON.parse(await this.do("info", Method.GET)) as OVMWindowsInfo;
}

public async enableFeature(): Promise<void> {
await this.do("enable-feature", Method.POST, NEVER_TIMEOUT);
}

public async reboot(): Promise<void> {
await this.do("reboot", Method.POST, NEVER_TIMEOUT);
}

public async updateWSL(): Promise<void> {
await this.do("update-wsl", Method.PUT, NEVER_TIMEOUT);
}
}
54 changes: 54 additions & 0 deletions src/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,57 @@ export interface OVMDarwinState {
canRequestStop: boolean;
CanStop: boolean;
}

// ----- windows

export interface OVMWindowsInfo {
podmanHost: string;
podmanPort: number;
}

export interface OVMWindowsOptions {
name: string;
ovmPath: string;
linuxPath: {
rootfs: string;
};
imageDir: string;
logDir: string;
versions: OVMWindowsOptions["linuxPath"] & { data: string; };
}

export enum OVMWindowsSysEventValue {
SystemNotSupport = "SystemNotSupport",

NeedEnableFeature = "NeedEnableFeature",
EnableFeaturing = "EnableFeaturing",
EnableFeatureFailed = "EnableFeatureFailed",
EnableFeatureSuccess = "EnableFeatureSuccess",
NeedReboot = "NeedReboot",

NeedUpdateWSL = "NeedUpdateWSL",
UpdatingWSL = "UpdatingWSL",
UpdateWSLFailed = "UpdateWSLFailed",
UpdateWSLSuccess = "UpdateWSLSuccess",
}

export enum OVMWindowsAppEventValue {
UpdatingRootFS = "UpdatingRootFS",
UpdateRootFSFailed = "UpdateRootFSFailed",
UpdateRootFSSuccess = "UpdateRootFSSuccess",

UpdatingData = "UpdatingData",
UpdateDataFailed = "UpdateDataFailed",
UpdateDataSuccess = "UpdateDataSuccess",

Starting = "Starting",
Ready = "Ready",
Exit = "Exit",
}

export interface OVMWindowsEventData {
app: OVMWindowsAppEventValue,
sys: OVMWindowsSysEventValue,
error: string,
}

79 changes: 79 additions & 0 deletions src/windows.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import cp from "node:child_process";
import type { EventReceiver } from "remitter";
import { Remitter } from "remitter";
import type { OVMWindowsEventData, OVMWindowsOptions } from "./type";
import { Restful } from "./event_restful";
import { RequestWindows } from "./request";

export class WindowsOVM extends RequestWindows {
public readonly events : EventReceiver<OVMWindowsEventData>;
readonly #events: Remitter<OVMWindowsEventData>;
private restful: Restful;
private readonly restfulNPipeName: string;

private constructor(private options: OVMWindowsOptions) {
super(options.name);
this.restfulNPipeName = `ovm-${options.name}-restful`;
this.events = this.#events = new Remitter();
}

public static create(options: OVMWindowsOptions): WindowsOVM {
const ovm = new WindowsOVM(options);
ovm.initEventRestful();
return ovm;
}

private initEventRestful(): void {
this.restful = new Restful();

this.#events.remitAny((o) => {
return this.restful.events.onAny((data) => {
o.emit(data.event as keyof OVMWindowsEventData, data.data);
});
});

this.restful.start(`//./pipe/${this.restfulNPipeName}`);
}

public start(): void {
const versions = Object.keys(this.options.versions).map((key) => {
return `${key}=${this.options.versions[key]}`;
}).join(",");

const launchTimeout = new Promise<void>((resolve, reject) => {
const id = setTimeout(() => {
disposer();
// eslint-disable-next-line prefer-promise-reject-errors
reject();
}, 30 * 1000);

const disposer = this.#events.onceAny(() => {
clearTimeout(id);
resolve();
});
});

const ovm = cp.spawn(this.options.ovmPath, [
"-name", this.options.name,
"-log-path", this.options.logDir,
"-image-dir", this.options.imageDir,
"-rootfs-path", this.options.linuxPath.rootfs,
"-versions", versions,
"-event-npipe-name", this.restfulNPipeName,
"-bind-pid", String(process.pid),
], {
timeout: 0,
windowsHide: true,
detached: true,
stdio: "ignore",
cwd: this.options.imageDir,
});

ovm.unref();

launchTimeout
.catch(() => {
this.#events.emit("error", "OVM start timeout");
});
}
}

0 comments on commit cd23f2c

Please sign in to comment.