UNPKG

@itwin/core-common

Version:

iTwin.js components common to frontend and backend

153 lines • 6.02 kB
/*--------------------------------------------------------------------------------------------- * 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