@softchef/cdk-iot-device-management
Version:
IoT device management is composed of things, thing types, thing groups, jobs, files API services. The constructs can be used independently, that are based on full-managed service to create an API Gateway & Lambda function.
144 lines (143 loc) • 6.65 kB
JavaScript
import { __assign, __values } from "tslib";
import { HttpResponse } from "@aws-sdk/protocol-http";
import { buildQueryString } from "@aws-sdk/querystring-builder";
import { connect, constants } from "http2";
import { getTransformedHeaders } from "./get-transformed-headers";
import { writeRequestBody } from "./write-request-body";
var NodeHttp2Handler = (function () {
function NodeHttp2Handler(_a) {
var _b = _a === void 0 ? {} : _a, requestTimeout = _b.requestTimeout, sessionTimeout = _b.sessionTimeout, disableConcurrentStreams = _b.disableConcurrentStreams;
this.metadata = { handlerProtocol: "h2" };
this.requestTimeout = requestTimeout;
this.sessionTimeout = sessionTimeout;
this.disableConcurrentStreams = disableConcurrentStreams;
this.sessionCache = new Map();
}
NodeHttp2Handler.prototype.destroy = function () {
var e_1, _a;
var _this = this;
try {
for (var _b = __values(this.sessionCache.values()), _c = _b.next(); !_c.done; _c = _b.next()) {
var sessions = _c.value;
sessions.forEach(function (session) { return _this.destroySession(session); });
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_1) throw e_1.error; }
}
this.sessionCache.clear();
};
NodeHttp2Handler.prototype.handle = function (request, _a) {
var _this = this;
var _b = _a === void 0 ? {} : _a, abortSignal = _b.abortSignal;
return new Promise(function (resolve, rejectOriginal) {
var _a;
var fulfilled = false;
if (abortSignal === null || abortSignal === void 0 ? void 0 : abortSignal.aborted) {
fulfilled = true;
var abortError = new Error("Request aborted");
abortError.name = "AbortError";
rejectOriginal(abortError);
return;
}
var hostname = request.hostname, method = request.method, port = request.port, protocol = request.protocol, path = request.path, query = request.query;
var authority = protocol + "//" + hostname + (port ? ":" + port : "");
var session = _this.getSession(authority, _this.disableConcurrentStreams || false);
var reject = function (err) {
if (_this.disableConcurrentStreams) {
_this.destroySession(session);
}
fulfilled = true;
rejectOriginal(err);
};
var queryString = buildQueryString(query || {});
var req = session.request(__assign(__assign({}, request.headers), (_a = {}, _a[constants.HTTP2_HEADER_PATH] = queryString ? path + "?" + queryString : path, _a[constants.HTTP2_HEADER_METHOD] = method, _a)));
req.on("response", function (headers) {
var httpResponse = new HttpResponse({
statusCode: headers[":status"] || -1,
headers: getTransformedHeaders(headers),
body: req,
});
fulfilled = true;
resolve({ response: httpResponse });
if (_this.disableConcurrentStreams) {
session.close();
_this.deleteSessionFromCache(authority, session);
}
});
var requestTimeout = _this.requestTimeout;
if (requestTimeout) {
req.setTimeout(requestTimeout, function () {
req.close();
var timeoutError = new Error("Stream timed out because of no activity for " + requestTimeout + " ms");
timeoutError.name = "TimeoutError";
reject(timeoutError);
});
}
if (abortSignal) {
abortSignal.onabort = function () {
req.close();
var abortError = new Error("Request aborted");
abortError.name = "AbortError";
reject(abortError);
};
}
req.on("frameError", function (type, code, id) {
reject(new Error("Frame type id " + type + " in stream id " + id + " has failed with code " + code + "."));
});
req.on("error", reject);
req.on("aborted", function () {
reject(new Error("HTTP/2 stream is abnormally aborted in mid-communication with result code " + req.rstCode + "."));
});
req.on("close", function () {
if (_this.disableConcurrentStreams) {
session.destroy();
}
if (!fulfilled) {
reject(new Error("Unexpected error: http2 request did not get a response"));
}
});
writeRequestBody(req, request);
});
};
NodeHttp2Handler.prototype.getSession = function (authority, disableConcurrentStreams) {
var _this = this;
var sessionCache = this.sessionCache;
var existingSessions = sessionCache.get(authority) || [];
if (existingSessions.length > 0 && !disableConcurrentStreams)
return existingSessions[0];
var newSession = connect(authority);
var destroySessionCb = function () {
_this.destroySession(newSession);
_this.deleteSessionFromCache(authority, newSession);
};
newSession.on("goaway", destroySessionCb);
newSession.on("error", destroySessionCb);
newSession.on("frameError", destroySessionCb);
var sessionTimeout = this.sessionTimeout;
if (sessionTimeout) {
newSession.setTimeout(sessionTimeout, destroySessionCb);
}
existingSessions.push(newSession);
sessionCache.set(authority, existingSessions);
return newSession;
};
NodeHttp2Handler.prototype.destroySession = function (session) {
if (!session.destroyed) {
session.destroy();
}
};
NodeHttp2Handler.prototype.deleteSessionFromCache = function (authority, session) {
var existingSessions = this.sessionCache.get(authority) || [];
if (!existingSessions.includes(session)) {
return;
}
this.sessionCache.set(authority, existingSessions.filter(function (s) { return s !== session; }));
};
return NodeHttp2Handler;
}());
export { NodeHttp2Handler };