mirror of
https://github.com/denoland/deno.git
synced 2024-11-29 16:30:56 -05:00
148 lines
4.7 KiB
TypeScript
148 lines
4.7 KiB
TypeScript
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
|
|
import { Signal } from "./process.ts";
|
|
import * as dispatch from "./dispatch.ts";
|
|
import { sendSync, sendAsync } from "./dispatch_json.ts";
|
|
import { build } from "./build.ts";
|
|
|
|
/**
|
|
* Returns the stream of the given signal number. You can use it as an async
|
|
* iterator.
|
|
*
|
|
* for await (const _ of Deno.signal(Deno.Signal.SIGTERM)) {
|
|
* console.log("got SIGTERM!");
|
|
* }
|
|
*
|
|
* You can also use it as a promise. In this case you can only receive the
|
|
* first one.
|
|
*
|
|
* await Deno.signal(Deno.Signal.SIGTERM);
|
|
* console.log("SIGTERM received!")
|
|
*
|
|
* If you want to stop receiving the signals, you can use .dispose() method
|
|
* of the signal stream object.
|
|
*
|
|
* const sig = Deno.signal(Deno.Signal.SIGTERM);
|
|
* setTimeout(() => { sig.dispose(); }, 5000);
|
|
* for await (const _ of sig) {
|
|
* console.log("SIGTERM!")
|
|
* }
|
|
*
|
|
* The above for-await loop exits after 5 seconds when sig.dispose() is called.
|
|
*/
|
|
export function signal(signo: number): SignalStream {
|
|
if (build.os === "win") {
|
|
throw new Error("not implemented!");
|
|
}
|
|
return new SignalStream(signo);
|
|
}
|
|
|
|
export const signals = {
|
|
/** Returns the stream of SIGALRM signals.
|
|
* This method is the shorthand for Deno.signal(Deno.Signal.SIGALRM). */
|
|
alarm(): SignalStream {
|
|
return signal(Signal.SIGALRM);
|
|
},
|
|
/** Returns the stream of SIGCHLD signals.
|
|
* This method is the shorthand for Deno.signal(Deno.Signal.SIGCHLD). */
|
|
child(): SignalStream {
|
|
return signal(Signal.SIGCHLD);
|
|
},
|
|
/** Returns the stream of SIGHUP signals.
|
|
* This method is the shorthand for Deno.signal(Deno.Signal.SIGHUP). */
|
|
hungup(): SignalStream {
|
|
return signal(Signal.SIGHUP);
|
|
},
|
|
/** Returns the stream of SIGINT signals.
|
|
* This method is the shorthand for Deno.signal(Deno.Signal.SIGINT). */
|
|
interrupt(): SignalStream {
|
|
return signal(Signal.SIGINT);
|
|
},
|
|
/** Returns the stream of SIGIO signals.
|
|
* This method is the shorthand for Deno.signal(Deno.Signal.SIGIO). */
|
|
io(): SignalStream {
|
|
return signal(Signal.SIGIO);
|
|
},
|
|
/** Returns the stream of SIGPIPE signals.
|
|
* This method is the shorthand for Deno.signal(Deno.Signal.SIGPIPE). */
|
|
pipe(): SignalStream {
|
|
return signal(Signal.SIGPIPE);
|
|
},
|
|
/** Returns the stream of SIGQUIT signals.
|
|
* This method is the shorthand for Deno.signal(Deno.Signal.SIGQUIT). */
|
|
quit(): SignalStream {
|
|
return signal(Signal.SIGQUIT);
|
|
},
|
|
/** Returns the stream of SIGTERM signals.
|
|
* This method is the shorthand for Deno.signal(Deno.Signal.SIGTERM). */
|
|
terminate(): SignalStream {
|
|
return signal(Signal.SIGTERM);
|
|
},
|
|
/** Returns the stream of SIGUSR1 signals.
|
|
* This method is the shorthand for Deno.signal(Deno.Signal.SIGUSR1). */
|
|
userDefined1(): SignalStream {
|
|
return signal(Signal.SIGUSR1);
|
|
},
|
|
/** Returns the stream of SIGUSR2 signals.
|
|
* This method is the shorthand for Deno.signal(Deno.Signal.SIGUSR2). */
|
|
userDefined2(): SignalStream {
|
|
return signal(Signal.SIGUSR2);
|
|
},
|
|
/** Returns the stream of SIGWINCH signals.
|
|
* This method is the shorthand for Deno.signal(Deno.Signal.SIGWINCH). */
|
|
windowChange(): SignalStream {
|
|
return signal(Signal.SIGWINCH);
|
|
}
|
|
};
|
|
|
|
/** SignalStream represents the stream of signals, implements both
|
|
* AsyncIterator and PromiseLike */
|
|
export class SignalStream implements AsyncIterator<void>, PromiseLike<void> {
|
|
private rid: number;
|
|
/** The promise of polling the signal,
|
|
* resolves with false when it receives signal,
|
|
* Resolves with true when the signal stream is disposed. */
|
|
private pollingPromise: Promise<boolean> = Promise.resolve(false);
|
|
/** The flag, which is true when the stream is disposed. */
|
|
private disposed = false;
|
|
constructor(signo: number) {
|
|
this.rid = sendSync(dispatch.OP_SIGNAL_BIND, { signo }).rid;
|
|
this.loop();
|
|
}
|
|
|
|
private async pollSignal(): Promise<boolean> {
|
|
return (
|
|
await sendAsync(dispatch.OP_SIGNAL_POLL, {
|
|
rid: this.rid
|
|
})
|
|
).done;
|
|
}
|
|
|
|
private async loop(): Promise<void> {
|
|
do {
|
|
this.pollingPromise = this.pollSignal();
|
|
} while (!(await this.pollingPromise) && !this.disposed);
|
|
}
|
|
|
|
then<T, S>(
|
|
f: (v: void) => T | Promise<T>,
|
|
g?: (v: Error) => S | Promise<S>
|
|
): Promise<T | S> {
|
|
return this.pollingPromise.then((_): void => {}).then(f, g);
|
|
}
|
|
|
|
async next(): Promise<IteratorResult<void>> {
|
|
return { done: await this.pollingPromise, value: undefined };
|
|
}
|
|
|
|
[Symbol.asyncIterator](): AsyncIterator<void> {
|
|
return this;
|
|
}
|
|
|
|
dispose(): void {
|
|
if (this.disposed) {
|
|
throw new Error("The stream has already been disposed.");
|
|
}
|
|
this.disposed = true;
|
|
sendSync(dispatch.OP_SIGNAL_UNBIND, { rid: this.rid });
|
|
}
|
|
}
|