33 lines
1.8 KiB
JavaScript
33 lines
1.8 KiB
JavaScript
// A gentle stop for s3d on Windows. child.kill() there is TerminateProcess:
|
|
// s3d dies wherever it is, and one stopped in the middle of an upload had
|
|
// lost buffered files whose database rows still said "waiting". s3d shuts
|
|
// down cleanly on an interrupt, so this attaches a short PowerShell to s3d's
|
|
// own (hidden) console and sends Ctrl+Break there.
|
|
//
|
|
// Ctrl+Break, not Ctrl+C: Windows disables Ctrl+C for a process started in
|
|
// a new process group, and Go reads both as os.Interrupt. A spawned console
|
|
// program gets a console of its own (Node passes CREATE_NO_WINDOW), so the
|
|
// event reaches s3d and not Pithos. It ends the PowerShell too, which is
|
|
// why only "could not attach" (2) and "could not send" (3) count as failure.
|
|
|
|
import { execFile } from 'node:child_process';
|
|
|
|
const SCRIPT = (pid) => [
|
|
"Add-Type -Name K -Namespace PithosCtrl -MemberDefinition '",
|
|
'[DllImport("kernel32.dll")] public static extern bool FreeConsole();',
|
|
'[DllImport("kernel32.dll")] public static extern bool AttachConsole(uint pid);',
|
|
'[DllImport("kernel32.dll")] public static extern bool GenerateConsoleCtrlEvent(uint ev, uint group);',
|
|
"';",
|
|
'[PithosCtrl.K]::FreeConsole() | Out-Null;',
|
|
`if (-not [PithosCtrl.K]::AttachConsole(${Number(pid) >>> 0})) { exit 2 };`,
|
|
'if ([PithosCtrl.K]::GenerateConsoleCtrlEvent(1, 0)) { exit 0 } else { exit 3 }',
|
|
].join(' ');
|
|
|
|
// Resolves true when Ctrl+Break was sent to the console of `pid`.
|
|
export function sendBreak(pid) {
|
|
if (process.platform !== 'win32' || !pid) return Promise.resolve(false);
|
|
return new Promise((resolve) => {
|
|
execFile('powershell.exe', ['-NoLogo', '-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-Command', SCRIPT(pid)],
|
|
{ windowsHide: true, timeout: 20_000 }, (err) => resolve(!err || (err.code !== 2 && err.code !== 3 && !err.killed)));
|
|
});
|
|
}
|