@freemework/hosting
Version:
Hosting library of the Freemework Project.
68 lines (55 loc) • 2.22 kB
text/typescript
import { FCancellationToken, FException, FCancellationException, FExceptionAggregate } from "@freemework/common";
import * as http from "http";
export class FHttpRequestCancellationToken implements FCancellationToken {
private readonly _onClientDisconnectBound: () => void;
private readonly _cancelListeners: Array<Function> = [];
private readonly _request: http.IncomingMessage;
private _isCancellationRequested: boolean;
public constructor(request: http.IncomingMessage) {
this._isCancellationRequested = false;
this._onClientDisconnectBound = this._onClientDisconnect.bind(this);
this._request = request;
// According to https://nodejs.org/api/http.html
// v16.0.0 The close event is now emitted when the request has been completed and not when the underlying socket is closed.
//
// So We switch to listen "close" event on underlying socket
this._request.socket.on("close", this._onClientDisconnectBound);
// this._request.on("end", this._onClientDisconnectBound);
}
public get isCancellationRequested(): boolean { return this._isCancellationRequested; }
public addCancelListener(cb: Function): void {
this._cancelListeners.push(cb);
}
public removeCancelListener(cb: Function): void {
const cbIndex = this._cancelListeners.indexOf(cb);
if (cbIndex !== -1) {
this._cancelListeners.splice(cbIndex, 1);
}
}
public throwIfCancellationRequested(): void {
if (this.isCancellationRequested) {
throw new FCancellationException();
}
}
private _onClientDisconnect() {
this._request.socket.removeListener("close", this._onClientDisconnectBound);
// this._request.removeListener("end", this._onClientDisconnectBound);
this._isCancellationRequested = true;
let errors: Array<FException> | null = null;
if (this._cancelListeners.length > 0) {
// Release callback. We do not need its anymore
const cancelListeners = this._cancelListeners.splice(0);
for (const cancelListener of cancelListeners) {
try {
cancelListener();
} catch (e) {
if (errors === null) { errors = []; }
errors.push(FException.wrapIfNeeded(e));
}
}
}
if (errors !== null && errors.length > 0) {
throw new FExceptionAggregate(errors);
}
}
}