UNPKG

rxdb

Version:

A local-first realtime NoSQL Database for JavaScript applications - https://rxdb.info/

183 lines (182 loc) 6.63 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var _exportNames = { startRxStorageRemoteWebsocketServer: true, getRxStorageRemoteWebsocket: true }; exports.getRxStorageRemoteWebsocket = getRxStorageRemoteWebsocket; exports.startRxStorageRemoteWebsocketServer = startRxStorageRemoteWebsocketServer; var _rxjs = require("rxjs"); var _index = require("../../plugins/utils/index.js"); var _index2 = require("../replication-websocket/index.js"); var _remote = require("../storage-remote/remote.js"); var _rxStorageRemote = require("../storage-remote/rx-storage-remote.js"); var _storageRemoteHelpers = require("../storage-remote/storage-remote-helpers.js"); var _types = require("./types.js"); Object.keys(_types).forEach(function (key) { if (key === "default" || key === "__esModule") return; if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return; if (key in exports && exports[key] === _types[key]) return; Object.defineProperty(exports, key, { enumerable: true, get: function () { return _types[key]; } }); }); /** * WebSocket transport needs Blob<->base64 conversion at the JSON boundary. * These helpers handle the two message types that carry Blob data: * - bulkWrite request: document._attachments[id].data (Blob) * - getAttachmentData response: msg.return (Blob) */ async function serializeBlobsForWs(msg) { var msgForJson = (0, _index.clone)(msg); if (msgForJson.method === 'bulkWrite' && Array.isArray(msgForJson.params)) { var documentWrites = msgForJson.params[0]; if (Array.isArray(documentWrites)) { var toConvert = []; for (var row of documentWrites) { if (row.document?._attachments) { for (var attachment of Object.values(row.document._attachments)) { if (attachment.data instanceof Blob) { toConvert.push({ attachment, blob: attachment.data }); } } } } if (toConvert.length > 0) { var base64Results = await Promise.all(toConvert.map(entry => (0, _index.blobToBase64String)(entry.blob))); for (var i = 0; i < toConvert.length; i++) { toConvert[i].attachment.data = base64Results[i]; } } } } else if (msgForJson.method === 'getAttachmentData' && msgForJson.return instanceof Blob) { msgForJson.return = await (0, _index.blobToBase64String)(msgForJson.return); } return JSON.stringify(msgForJson); } async function deserializeBlobsFromWs(msg) { if (msg.method === 'bulkWrite' && Array.isArray(msg.params)) { var documentWrites = msg.params[0]; if (Array.isArray(documentWrites)) { for (var row of documentWrites) { if (row.document?._attachments) { for (var attachment of Object.values(row.document._attachments)) { if (typeof attachment.data === 'string') { attachment.data = await (0, _index.createBlobFromBase64)(attachment.data, attachment.type || ''); } } } } } } else if (msg.method === 'getAttachmentData' && typeof msg.return === 'string') { msg.return = await (0, _index.createBlobFromBase64)(msg.return, ''); } return msg; } function startRxStorageRemoteWebsocketServer(options) { options.perMessageDeflate = true; var serverState = (0, _index2.startSocketServer)(options); var websocketByConnectionId = new Map(); var messages$ = new _rxjs.Subject(); var exposeSettings = { messages$: messages$.asObservable(), storage: options.storage, database: options.database, customRequestHandler: options.customRequestHandler, send(msg) { var ws = websocketByConnectionId.get(msg.connectionId); if (!ws) { // client disconnected, silently drop the message return; } serializeBlobsForWs(msg).then(serialized => { try { ws.send(serialized); } catch (err) { // WebSocket might have transitioned to CLOSING or CLOSED state } }).catch(() => { // serialization error, silently drop }); }, fakeVersion: options.fakeVersion }; var exposeState = (0, _remote.exposeRxStorageRemote)(exposeSettings); serverState.onConnection$.subscribe(ws => { var onCloseHandlers = []; var connectionIds = new Set(); ws.onclose = () => { onCloseHandlers.map(fn => fn()); connectionIds.forEach(id => websocketByConnectionId.delete(id)); }; ws.on('message', messageString => { void (async () => { var message; try { message = JSON.parse(messageString); await deserializeBlobsFromWs(message); } catch (err) { console.error('RxDB WebSocket server: failed to parse or deserialize message', err); return; } var connectionId = message.connectionId; if (!websocketByConnectionId.has(connectionId)) { if (message.method !== 'create' && message.method !== 'custom') { try { ws.send(JSON.stringify((0, _storageRemoteHelpers.createErrorAnswer)(message, new Error('First call must be a create call but is: ' + JSON.stringify(message))))); } catch (err) { // WebSocket might be in CLOSING or CLOSED state } return; } websocketByConnectionId.set(connectionId, ws); connectionIds.add(connectionId); } messages$.next(message); })(); }); }); return { serverState, exposeState }; } function getRxStorageRemoteWebsocket(options) { var identifier = [options.url, 'rx-remote-storage-websocket'].join(''); var storage = (0, _rxStorageRemote.getRxStorageRemote)({ identifier, mode: options.mode, async messageChannelCreator() { var messages$ = new _rxjs.Subject(); var websocketClient = await (0, _index2.createWebSocketClient)(options); websocketClient.message$.subscribe(msg => { void deserializeBlobsFromWs(msg).then(deserialized => { messages$.next(deserialized); }).catch(err => { console.error('RxDB WebSocket client: failed to deserialize incoming message', err); }); }); return { messages$, async send(msg) { var serialized = await serializeBlobsForWs(msg); websocketClient.socket.send(serialized); }, close() { websocketClient.socket.close(); return _index.PROMISE_RESOLVE_VOID; } }; } }); return storage; } //# sourceMappingURL=index.js.map