// // Copyright © 2020, 2021 Anticrm Platform Contributors. // // Licensed under the Eclipse Public License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. You may // obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // // See the License for the specific language governing permissions and // limitations under the License. // import platform, { PlatformError, Severity, Status } from '@hcengineering/platform' import { Packr } from 'msgpackr' const packr = new Packr({ structuredClone: true, bundleStrings: true, copyBuffers: true }) /** * @public */ export type ReqId = string | number /** * @public */ export interface Request

{ id?: ReqId method: string params: P time?: number // Server time to perform operation } /** * @public */ export interface HelloRequest extends Request { binary?: boolean compression?: boolean } /** * @public */ export interface HelloResponse extends Response { binary: boolean reconnect?: boolean } /** * Response object define a server response on transaction request. * Also used to inform other clients about operations being performed by server. * * @public */ export interface Response { result?: R id?: ReqId error?: Status chunk?: { index: number final: boolean } time?: number // Server time to perform operation bfst?: number // Server time to perform operation queue?: number } /** * @public * @param object - * @returns */ export function protoSerialize (object: object, binary: boolean): any { if (!binary) { return JSON.stringify(object, replacer) } return new Uint8Array(packr.pack(object)) } /** * @public * @param data - * @returns */ export function protoDeserialize (data: any, binary: boolean): any { if (!binary) { let _data = data if (_data instanceof ArrayBuffer) { const decoder = new TextDecoder() _data = decoder.decode(_data) } return JSON.parse(_data.toString(), receiver) } return packr.unpack(new Uint8Array(data)) } /** * @public * @param object - * @returns */ export function serialize (object: Request | Response, binary: boolean): any { if ((object as any).result !== undefined) { ;(object as any).result = replacer('result', (object as any).result) } return protoSerialize(object, binary) } /** * @public * @param response - * @returns */ export function readResponse (response: any, binary: boolean): Response { const data = protoDeserialize(response, binary) if (data.result !== undefined) { data.result = receiver('result', data.result) } return data } function replacer (key: string, value: any): any { if (Array.isArray(value) && ((value as any).total !== undefined || (value as any).lookupMap !== undefined)) { return { dataType: 'TotalArray', total: (value as any).total, lookupMap: (value as any).lookupMap, value: [...value] } } else { return value ?? null } } function receiver (key: string, value: any): any { if (typeof value === 'object' && value !== null) { if (value.dataType === 'TotalArray') { return Object.assign(value.value, { total: value.total, lookupMap: value.lookupMap }) } } return value } /** * @public * @param request - * @returns */ export function readRequest

(request: any, binary: boolean): Request

{ const result: Request

= protoDeserialize(request, binary) if (typeof result.method !== 'string') { throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {})) } return result } /** * @public * @param status - * @param id - * @returns */ export function fromStatus (status: Status, id?: ReqId): Response { return { id, error: status } }