mirror of
https://github.com/wu736139669/hapi.git
synced 2026-10-27 22:51:43 +00:00
refactor: extract remote launcher base class for code reuse
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
import { render } from 'ink';
|
||||
import type { ReactElement } from 'react';
|
||||
import { MessageBuffer } from '@/ui/ink/messageBuffer';
|
||||
import { restoreTerminalState } from '@/ui/terminalState';
|
||||
|
||||
export type RemoteLauncherExitReason = 'switch' | 'exit';
|
||||
|
||||
export type RemoteLauncherDisplayContext = {
|
||||
messageBuffer: MessageBuffer;
|
||||
logPath?: string;
|
||||
onExit: () => void | Promise<void>;
|
||||
onSwitchToLocal: () => void | Promise<void>;
|
||||
};
|
||||
|
||||
export type RemoteLauncherTerminalHandlers = {
|
||||
onExit: () => void | Promise<void>;
|
||||
onSwitchToLocal: () => void | Promise<void>;
|
||||
};
|
||||
|
||||
export type RemoteLauncherAbortHandlers = {
|
||||
onAbort: () => void | Promise<void>;
|
||||
onSwitch: () => void | Promise<void>;
|
||||
};
|
||||
|
||||
type RpcHandlerManagerLike = {
|
||||
registerHandler<TRequest = unknown, TResponse = unknown>(
|
||||
method: string,
|
||||
handler: (params: TRequest) => Promise<TResponse> | TResponse
|
||||
): void;
|
||||
};
|
||||
|
||||
export abstract class RemoteLauncherBase {
|
||||
protected readonly messageBuffer: MessageBuffer;
|
||||
protected readonly hasTTY: boolean;
|
||||
protected readonly logPath?: string;
|
||||
protected exitReason: RemoteLauncherExitReason | null = null;
|
||||
protected shouldExit: boolean = false;
|
||||
private inkInstance: ReturnType<typeof render> | null = null;
|
||||
|
||||
protected constructor(logPath?: string) {
|
||||
this.logPath = logPath;
|
||||
this.hasTTY = Boolean(process.stdout.isTTY && process.stdin.isTTY);
|
||||
this.messageBuffer = new MessageBuffer();
|
||||
}
|
||||
|
||||
protected abstract createDisplay(context: RemoteLauncherDisplayContext): ReactElement;
|
||||
|
||||
protected abstract runMainLoop(): Promise<void>;
|
||||
|
||||
protected abstract cleanup(): Promise<void>;
|
||||
|
||||
protected setupTerminal(handlers: RemoteLauncherTerminalHandlers): void {
|
||||
if (this.hasTTY) {
|
||||
console.clear();
|
||||
this.inkInstance = render(this.createDisplay({
|
||||
messageBuffer: this.messageBuffer,
|
||||
logPath: this.logPath,
|
||||
onExit: handlers.onExit,
|
||||
onSwitchToLocal: handlers.onSwitchToLocal
|
||||
}), {
|
||||
exitOnCtrlC: false,
|
||||
patchConsole: false
|
||||
});
|
||||
}
|
||||
|
||||
if (this.hasTTY) {
|
||||
process.stdin.resume();
|
||||
if (process.stdin.isTTY) {
|
||||
process.stdin.setRawMode(true);
|
||||
}
|
||||
process.stdin.setEncoding('utf8');
|
||||
}
|
||||
}
|
||||
|
||||
protected setupAbortHandlers(
|
||||
rpcHandlerManager: RpcHandlerManagerLike,
|
||||
handlers: RemoteLauncherAbortHandlers
|
||||
): void {
|
||||
rpcHandlerManager.registerHandler('abort', async () => {
|
||||
await handlers.onAbort();
|
||||
});
|
||||
|
||||
rpcHandlerManager.registerHandler('switch', async () => {
|
||||
await handlers.onSwitch();
|
||||
});
|
||||
}
|
||||
|
||||
protected clearAbortHandlers(rpcHandlerManager: RpcHandlerManagerLike): void {
|
||||
rpcHandlerManager.registerHandler('abort', async () => {});
|
||||
rpcHandlerManager.registerHandler('switch', async () => {});
|
||||
}
|
||||
|
||||
protected async requestExit(
|
||||
reason: RemoteLauncherExitReason,
|
||||
handler: () => void | Promise<void>
|
||||
): Promise<void> {
|
||||
if (!this.exitReason) {
|
||||
this.exitReason = reason;
|
||||
}
|
||||
this.shouldExit = true;
|
||||
await handler();
|
||||
}
|
||||
|
||||
protected finalizeTerminal(): void {
|
||||
restoreTerminalState();
|
||||
if (this.hasTTY) {
|
||||
try {
|
||||
process.stdin.pause();
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
if (this.inkInstance) {
|
||||
this.inkInstance.unmount();
|
||||
}
|
||||
this.messageBuffer.clear();
|
||||
}
|
||||
|
||||
protected async start(handlers: RemoteLauncherTerminalHandlers): Promise<RemoteLauncherExitReason> {
|
||||
this.setupTerminal(handlers);
|
||||
try {
|
||||
await this.runMainLoop();
|
||||
} finally {
|
||||
await this.cleanup();
|
||||
this.finalizeTerminal();
|
||||
}
|
||||
|
||||
return this.exitReason || 'exit';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user