UNPKG

rxdb

Version:

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

118 lines (108 loc) 3.9 kB
import { Subject } from 'rxjs'; import type { WebSocket } from 'ws'; import { PROMISE_RESOLVE_VOID, getFromMapOrThrow } from '../../plugins/utils/index.ts'; import { createWebSocketClient, startSocketServer } from '../replication-websocket/index.ts'; import { exposeRxStorageRemote } from '../storage-remote/remote.ts'; import { getRxStorageRemote } from '../storage-remote/rx-storage-remote.ts'; import { createErrorAnswer } from '../storage-remote/storage-remote-helpers.ts'; import type { MessageFromRemote, MessageToRemote, RxStorageRemoteExposeSettings } from '../storage-remote/storage-remote-types.ts'; import type { RxStorageRemoteWebsocketClient, RxStorageRemoteWebsocketClientOptions, RxStorageRemoteWebsocketServerOptions, RxStorageRemoteWebsocketServerState } from './types.ts'; export function startRxStorageRemoteWebsocketServer( options: RxStorageRemoteWebsocketServerOptions ): RxStorageRemoteWebsocketServerState { (options as any).perMessageDeflate = true; const serverState = startSocketServer(options); const websocketByConnectionId = new Map<string, WebSocket>(); const messages$ = new Subject<MessageToRemote>(); const exposeSettings: RxStorageRemoteExposeSettings = { messages$: messages$.asObservable(), storage: options.storage as any, database: options.database as any, customRequestHandler: options.customRequestHandler, send(msg) { const ws = getFromMapOrThrow(websocketByConnectionId, msg.connectionId); ws.send(JSON.stringify(msg)); }, fakeVersion: options.fakeVersion }; const exposeState = exposeRxStorageRemote(exposeSettings); serverState.onConnection$.subscribe(ws => { const onCloseHandlers: Function[] = []; ws.onclose = () => { onCloseHandlers.map(fn => fn()); }; ws.on('message', (messageString: string) => { const message: MessageToRemote = JSON.parse(messageString); const connectionId = message.connectionId; if (!websocketByConnectionId.has(connectionId)) { /** * If first message is not 'create', * it is an error. */ if ( message.method !== 'create' && message.method !== 'custom' ) { ws.send( JSON.stringify( createErrorAnswer(message, new Error('First call must be a create call but is: ' + JSON.stringify(message))) ) ); return; } websocketByConnectionId.set(connectionId, ws); } messages$.next(message); }); }); return { serverState, exposeState }; } export function getRxStorageRemoteWebsocket( options: RxStorageRemoteWebsocketClientOptions ): RxStorageRemoteWebsocketClient { const identifier = [ options.url, 'rx-remote-storage-websocket' ].join(''); const storage = getRxStorageRemote({ identifier, mode: options.mode, async messageChannelCreator() { const messages$ = new Subject<MessageFromRemote>(); const websocketClient = await createWebSocketClient(options as any); websocketClient.message$.subscribe(msg => messages$.next(msg)); return { messages$, send(msg) { return websocketClient.socket.send(JSON.stringify(msg)); }, close() { websocketClient.socket.close(); return PROMISE_RESOLVE_VOID; } }; } }); return storage; } export * from './types.ts';