Files
ToolsRtmpPush/src/implementations/ProcessManager.ts

86 lines
2.2 KiB
TypeScript

import {ChildProcess} from 'node:child_process';
import type {IProcessManager, ProcessManagerEvents} from '../interfaces/IProcessManager.js';
import type {IProcessSpawner} from '../interfaces/IProcessSpawner.js';
import type {ILogger} from '../interfaces/ILogger.js';
import {EventEmitter} from 'node:events';
/**
* Manages process lifecycle
* Single Responsibility: Process management only
* Open/Closed: Can be extended without modification
*/
export class ProcessManager extends EventEmitter implements IProcessManager {
private activeProcess: ChildProcess | null = null;
constructor(
private readonly processSpawner: IProcessSpawner,
private readonly logger: ILogger
) {
super();
}
start(command: string, args: string[]): void {
if (this.isRunning()) {
throw new Error('Process is already running');
}
if (!command) {
throw new Error('Invalid command: command cannot be empty');
}
try {
this.activeProcess = this.processSpawner.spawn(command, args);
if (!this.activeProcess) {
throw new Error('Failed to spawn process');
}
this.setupEventHandlers();
} catch (error) {
this.logger.error('Failed to start process:', error);
this.activeProcess = null;
throw error;
}
}
stop(): void {
if (this.activeProcess) {
this.activeProcess.kill();
this.activeProcess = null;
}
}
isRunning(): boolean {
return this.activeProcess !== null && !this.activeProcess.killed;
}
private setupEventHandlers(): void {
if (!this.activeProcess) {
return;
}
this.activeProcess.stdout?.on('data', (data: Buffer) => {
this.logger.log(`stdout: ${data}`);
this.emit('data', data);
});
this.activeProcess.stderr?.on('data', (data: Buffer) => {
this.logger.log(`stderr: ${data}`);
this.emit('data', data);
});
this.activeProcess.on('close', (code: number | null) => {
this.logger.log(`child process exited with code ${code}`);
this.activeProcess = null;
this.emit('close', code);
});
this.activeProcess.on('error', (error: Error) => {
this.logger.error('Process error:', error);
this.activeProcess = null;
this.emit('error', error);
});
}
}