@whisklabs/grpc
Version:
gRPC generator and http library for typescript
259 lines • 15.1 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.grpcHTTP = exports.grpcCancel = void 0;
var typeguards_1 = require("@whisklabs/typeguards");
var binary_1 = require("../binary");
var devtool_1 = require("./devtool");
var mask_1 = require("./mask");
var parser_1 = require("./parser");
var status_1 = require("./status");
var utils_1 = require("./utils");
var grpcCancel = function () {
var CancelFn = (function () {
var _a;
(_a = CancelFn.abort) === null || _a === void 0 ? void 0 : _a.call(CancelFn);
CancelFn.abort = undefined;
});
return CancelFn;
};
exports.grpcCancel = grpcCancel;
var grpcHTTP = function (_a) {
var server = _a.server, transformRequest = _a.transformRequest, transformResponse = _a.transformResponse, _b = _a.credentials, credentials = _b === void 0 ? true : _b, timeoutConfig = _a.timeout, _c = _a.devtool, devtool = _c === void 0 ? false : _c, _d = _a.debug, debug = _d === void 0 ? false : _d, logger = _a.logger;
if (!(0, typeguards_1.isText)(server)) {
throw new Error('No "server" in GRPC config');
}
var cancels = {};
return (function (field, values, _a) {
var _b;
if (values === void 0) { values = {}; }
var _c = _a === void 0 ? {} : _a, cancel = _c.cancel, onDownload = _c.onDownload, onUpload = _c.onUpload, mask = _c.mask, timeout = _c.timeout, meta = _c.meta;
if ((0, typeguards_1.isString)(cancel) && (0, typeguards_1.isFunction)(cancels[cancel])) {
cancels[cancel]();
delete cancels[cancel];
}
var method = "".concat(server, "/").concat(field.name);
var xhr = new XMLHttpRequest();
xhr.timeout = (_b = timeout !== null && timeout !== void 0 ? timeout : timeoutConfig) !== null && _b !== void 0 ? _b : 0;
var abortXHR = function () { return xhr.abort(); };
if ((0, typeguards_1.isPresent)(cancel)) {
if ((0, typeguards_1.isString)(cancel)) {
cancels[cancel] = abortXHR;
}
else {
cancel.abort = abortXHR;
}
}
var tmCancel = function () {
if ((0, typeguards_1.isPresent)(cancel)) {
if ((0, typeguards_1.isString)(cancel)) {
delete cancels[cancel];
}
else {
cancel.abort = undefined;
}
}
};
var sendData = values;
// eslint-disable-next-line @typescript-eslint/no-misused-promises, no-async-promise-executor
return new Promise(function (callback) { return __awaiter(void 0, void 0, void 0, function () {
var encoded, request;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
xhr.open('POST', method);
xhr.withCredentials = credentials;
if ('overrideMimeType' in xhr) {
xhr.overrideMimeType('text/plain; charset=x-user-defined');
}
xhr.responseType = 'arraybuffer';
xhr.setRequestHeader('content-type', 'application/grpc-web+proto');
xhr.setRequestHeader('x-grpc-web', '1');
xhr.setRequestHeader('x-user-agent', 'grpc-web-ts/1.0');
if ((0, typeguards_1.isFunction)(onDownload)) {
xhr.addEventListener('progress', onDownload);
}
if ((0, typeguards_1.isFunction)(onUpload) && (0, typeguards_1.isObject)(xhr.upload)) {
xhr.upload.addEventListener('progress', onUpload);
}
xhr.addEventListener('timeout', function () {
tmCancel();
callback({ success: false, error: { message: 'timeout', data: xhr.timeout } });
});
xhr.addEventListener('abort', function () {
tmCancel();
callback({
success: false,
error: { message: 'cancelled', httpStatus: xhr.status, grpcCode: status_1.StatusCode.CANCELLED },
});
});
xhr.addEventListener('error', function () {
tmCancel();
callback({
success: false,
error: {
message: 'XHR error',
data: (0, utils_1.bufToString)(xhr),
httpStatus: xhr.status,
grpcCode: (0, status_1.fromHttpStatus)(xhr.status),
},
});
});
xhr.addEventListener('load', function onready() {
var _a, _b, _c;
tmCancel();
if (xhr.status < 200 || xhr.status >= 300) {
return callback({
success: false,
error: {
message: 'XHR wrong status',
data: (0, utils_1.bufToString)(xhr),
httpStatus: xhr.status,
grpcCode: (0, status_1.fromHttpStatus)(xhr.status),
},
});
}
var byteSource = (0, utils_1.toInt8)(xhr);
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
if (!byteSource) {
return callback({ success: false, error: { message: 'GRPC no bytes' } });
}
var data = [];
try {
data = (0, parser_1.chunkParse)(byteSource);
}
catch (error) {
return callback({ success: false, error: { message: 'GRPC parsing error', data: error } });
}
if (data.length === 0) {
var status_2 = this.getResponseHeader(utils_1.GRPC_STATUS);
var message = (0, typeguards_1.isPresent)(status_2)
? (_a = this.getResponseHeader(utils_1.GRPC_MESSAGE)) !== null && _a !== void 0 ? _a : ''
: 'Failed to parse GRPC status';
var grpcCode = (0, typeguards_1.isPresent)(status_2) ? (_b = Number(status_2)) !== null && _b !== void 0 ? _b : 0 : undefined;
return callback({
success: false,
error: { message: message, data: (0, utils_1.safeJSON)(message), httpStatus: xhr.status, grpcCode: grpcCode },
});
}
for (var _i = 0, data_1 = data; _i < data_1.length; _i++) {
var d = data_1[_i];
if (d.chunkType === parser_1.ChunkType.MESSAGE) {
try {
if (debug) {
(0, devtool_1.send)({
method: method,
methodType: 'server_streaming',
response: [].slice.call(byteSource),
});
logger === null || logger === void 0 ? void 0 : logger.warn(method, byteSource);
}
return callback({ success: true, data: (0, binary_1.Decode)(field.decode, d.data) });
}
catch (e) {
return callback({
success: false,
error: { message: 'Decode error', data: e, httpStatus: xhr.status },
});
}
}
else if (d.chunkType === parser_1.ChunkType.TRAILERS) {
var trailers = d.trailers;
var grpcCode = status_1.StatusCode.OK;
var message = (_c = trailers[utils_1.GRPC_MESSAGE]) !== null && _c !== void 0 ? _c : '';
var status_3 = trailers === null || trailers === void 0 ? void 0 : trailers[utils_1.GRPC_STATUS];
if ((0, typeguards_1.isString)(status_3)) {
var code = Number(status_3);
grpcCode = code >= 0 ? code : (0, status_1.fromHttpStatus)(xhr.status);
}
return callback({
success: false,
error: { message: message, data: (0, utils_1.safeJSON)(message), httpStatus: xhr.status, grpcCode: grpcCode },
});
}
}
});
if (!(0, typeguards_1.isFunction)(transformRequest)) return [3 /*break*/, 2];
return [4 /*yield*/, transformRequest({ xhr: xhr, data: values, meta: meta })];
case 1:
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
sendData = (_a.sent()) || values;
_a.label = 2;
case 2:
encoded = (0, binary_1.Encode)(field.encode, mask === true
? (0, mask_1.maskWrap)(sendData)
: (0, typeguards_1.isObject)(mask) && (0, typeguards_1.isText)(mask.field)
? (0, mask_1.maskWrap)(sendData, mask.field, mask.outField)
: sendData);
request = (0, utils_1.encodeRequest)(encoded);
if (debug) {
(0, devtool_1.send)({
method: method,
methodType: 'server_streaming',
request: [].slice.call(request),
});
logger === null || logger === void 0 ? void 0 : logger.warn(method, request);
}
xhr.send(request);
return [2 /*return*/];
}
});
}); })
.then(function (data) {
if (devtool) {
(0, devtool_1.send)({
method: method,
methodType: 'unary',
request: sendData,
response: data.success ? data.data : undefined,
error: data.success ? undefined : data.error,
});
logger === null || logger === void 0 ? void 0 : logger[data.success ? 'info' : 'error'](method, sendData, data);
}
return data;
})
.then(function (data) { return ((0, typeguards_1.isFunction)(transformResponse) ? transformResponse({ xhr: xhr, data: data, meta: meta }) : data); })
.catch(function (data) {
logger === null || logger === void 0 ? void 0 : logger.error(method, data);
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
return { success: false, error: { data: data } };
});
});
};
exports.grpcHTTP = grpcHTTP;
//# sourceMappingURL=http.js.map