91 lines
2.6 KiB
TypeScript
91 lines
2.6 KiB
TypeScript
import { parentPort } from 'electron';
|
|
import {
|
|
prepareProjectReleaseSummary,
|
|
ProjectReleaseBuildError,
|
|
type ReleaseBuildRuntimeContext,
|
|
} from './project-release-builder';
|
|
|
|
type StartMessage = {
|
|
type: 'start';
|
|
jobId: string;
|
|
projectPath: string;
|
|
clientVersion: string;
|
|
runtimeContext: ReleaseBuildRuntimeContext;
|
|
};
|
|
|
|
type CancelMessage = {
|
|
type: 'cancel';
|
|
jobId: string;
|
|
};
|
|
|
|
type WorkerMessage = StartMessage | CancelMessage;
|
|
|
|
const controllers = new Map<string, AbortController>();
|
|
|
|
function readMessage(value: unknown): WorkerMessage | null {
|
|
const candidate = value && typeof value === 'object' && 'data' in value
|
|
? (value as { data?: unknown }).data
|
|
: value;
|
|
if (!candidate || typeof candidate !== 'object') return null;
|
|
const message = candidate as Partial<WorkerMessage>;
|
|
if (message.type !== 'start' && message.type !== 'cancel') return null;
|
|
return message as WorkerMessage;
|
|
}
|
|
|
|
function post(message: unknown): void {
|
|
parentPort?.postMessage(message);
|
|
}
|
|
|
|
async function run(message: StartMessage): Promise<void> {
|
|
const controller = new AbortController();
|
|
controllers.set(message.jobId, controller);
|
|
try {
|
|
const prepared = await prepareProjectReleaseSummary({
|
|
projectPath: message.projectPath,
|
|
clientVersion: message.clientVersion,
|
|
runtimeContext: message.runtimeContext,
|
|
signal: controller.signal,
|
|
onProgress: (progress) => post({ type: 'progress', jobId: message.jobId, progress }),
|
|
});
|
|
try {
|
|
if (controller.signal.aborted) {
|
|
throw new ProjectReleaseBuildError('LOCAL_BUILD_CANCELLED');
|
|
}
|
|
post({
|
|
type: 'complete',
|
|
jobId: message.jobId,
|
|
packageSummary: prepared.sourceArchive.summary,
|
|
contract: prepared.contract,
|
|
});
|
|
} finally {
|
|
await prepared.dispose();
|
|
}
|
|
} catch (error) {
|
|
const code = error instanceof ProjectReleaseBuildError
|
|
? error.code
|
|
: 'LOCAL_BUILD_FAILED';
|
|
post({
|
|
type: 'error',
|
|
jobId: message.jobId,
|
|
code,
|
|
message: error instanceof Error ? error.message : String(error),
|
|
});
|
|
} finally {
|
|
controllers.delete(message.jobId);
|
|
// The worker is single-job by design. Exiting here releases any native
|
|
// module state and makes the process count observable and bounded.
|
|
setImmediate(() => process.exit(0));
|
|
}
|
|
}
|
|
|
|
parentPort?.on('message', (value) => {
|
|
const message = readMessage(value);
|
|
if (!message) return;
|
|
if (message.type === 'cancel') {
|
|
controllers.get(message.jobId)?.abort();
|
|
return;
|
|
}
|
|
if (controllers.has(message.jobId)) return;
|
|
void run(message);
|
|
});
|