@itwin/core-common
Version:
iTwin.js components common to frontend and backend
153 lines • 6.02 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
* @module RpcInterface
*/
import { BentleyStatus } from "@itwin/core-bentley";
import { IModelError } from "../../IModelError";
// cspell:ignore unmarshal
/* eslint-disable @typescript-eslint/no-deprecated */
function isBuffer(val) {
return val && typeof (val.constructor) !== "undefined" && typeof (val.constructor.isBuffer) === "function" && val.constructor.isBuffer(val);
}
let marshalingTarget;
let chunkThreshold = 0;
/** @internal */
export var MarshalingBinaryMarker;
(function (MarshalingBinaryMarker) {
function createDefault() {
return { isBinary: true, index: 0, size: -1, chunks: 1 };
}
MarshalingBinaryMarker.createDefault = createDefault;
})(MarshalingBinaryMarker || (MarshalingBinaryMarker = {}));
/** @internal */
export var RpcSerializedValue;
(function (RpcSerializedValue) {
function create(objects = "", data = []) {
return { objects, data };
}
RpcSerializedValue.create = create;
})(RpcSerializedValue || (RpcSerializedValue = {}));
/** @internal */
export class RpcMarshaling {
constructor() { }
/** Serializes a value. */
static serialize(protocol, value) {
const serialized = RpcSerializedValue.create();
if (value === undefined)
return serialized;
marshalingTarget = serialized;
chunkThreshold = protocol ? protocol.transferChunkThreshold : 0;
serialized.objects = JSON.stringify(value, (_key, _value) => WireFormat.marshal(_key, _value));
marshalingTarget = undefined;
chunkThreshold = 0;
return serialized;
}
/** Deserializes a value. */
static deserialize(protocol, value) {
if (value.objects === "") {
return undefined;
}
marshalingTarget = value;
chunkThreshold = protocol ? protocol.transferChunkThreshold : 0;
let result;
try {
result = JSON.parse(value.objects, (_key, _value) => WireFormat.unmarshal(_key, _value));
}
catch (error) {
if (error instanceof SyntaxError)
throw new IModelError(BentleyStatus.ERROR, `Invalid JSON: "${value.objects}"`);
throw error;
}
marshalingTarget = undefined;
chunkThreshold = 0;
return result;
}
}
class WireFormat {
/** JSON.stringify replacer callback. */
static marshal(_key, value) {
const asBinary = WireFormat.marshalBinary(value);
if (asBinary) {
return asBinary;
}
const asError = WireFormat.marshalError(value);
if (asError) {
return asError;
}
return value;
}
/** JSON.parse reviver callback. */
static unmarshal(_key, value) {
if (typeof (value) === "object" && value !== null && value.hasOwnProperty("isBinary") && value.isBinary) {
return WireFormat.unmarshalBinary(value);
}
return value;
}
static marshalBinary(value) {
if (value instanceof Uint8Array || isBuffer(value)) {
const marker = { isBinary: true, index: -1, size: value.byteLength, chunks: 1 };
if (chunkThreshold && value.byteLength > chunkThreshold) {
marker.index = marshalingTarget.data.length;
marker.chunks = 0;
let cursor = value.byteOffset;
const end = cursor + value.byteLength;
let chunk = chunkThreshold;
for (;;) {
if (cursor >= end) {
break;
}
marshalingTarget.data.push(new Uint8Array(value.buffer, cursor, chunk));
++marker.chunks;
cursor += chunk;
const consumed = cursor - value.byteOffset;
const remaining = value.byteLength - consumed;
chunk = Math.min(chunkThreshold, remaining);
}
}
else {
marker.index = marshalingTarget.data.push(value) - 1;
}
return marker;
}
else {
return undefined;
}
}
static unmarshalBinary(value) {
if (value.index >= marshalingTarget.data.length) {
throw new IModelError(BentleyStatus.ERROR, `Cannot unmarshal missing binary value.`);
}
if (value.chunks === 0) {
return new Uint8Array();
}
else if (value.chunks === 1) {
return new Uint8Array(marshalingTarget.data[value.index]);
}
else {
const buffer = new ArrayBuffer(value.size);
const view = new Uint8Array(buffer);
let cursor = 0;
for (let c = 0; c !== value.chunks; ++c) {
const chunk = marshalingTarget.data[value.index + c];
view.set(chunk, cursor);
cursor += chunk.byteLength;
}
return view;
}
}
static marshalError(value) {
if (value instanceof Error) {
const props = Object.getOwnPropertyDescriptors(value);
props.isError = { configurable: true, enumerable: true, writable: true, value: true };
props.name = { configurable: true, enumerable: true, writable: true, value: value.name };
props.message = { configurable: true, enumerable: true, writable: true, value: value.message };
props.stack = { configurable: true, enumerable: true, writable: true, value: value.stack };
return Object.create(Object.prototype, props);
}
return undefined;
}
}
//# sourceMappingURL=RpcMarshaling.js.map