UNPKG

@electric-sql/pglite-socket

Version:

A socket implementation for PGlite enabling remote connections

1 lines 30.2 kB
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { PGlite } from '@electric-sql/pglite'\nimport { createServer, Server, Socket } from 'net'\n\n// Connection queue timeout in milliseconds\nexport const CONNECTION_QUEUE_TIMEOUT = 60000 // 60 seconds\n\n/**\n * Options for creating a PGLiteSocketHandler\n */\nexport interface PGLiteSocketHandlerOptions {\n /** The PGlite database instance */\n db: PGlite\n /** Whether to close the socket when detached (default: false) */\n closeOnDetach?: boolean\n /** Print the incoming and outgoing data to the console in hex and ascii */\n inspect?: boolean\n /** Enable debug logging of method calls */\n debug?: boolean\n}\n\n/**\n * Low-level handler for a single socket connection to PGLite\n * Handles the raw protocol communication between a socket and PGLite\n */\nexport class PGLiteSocketHandler extends EventTarget {\n readonly db: PGlite\n private socket: Socket | null = null\n private active = false\n private closeOnDetach: boolean\n private resolveLock?: () => void\n private rejectLock?: (err: Error) => void\n private inspect: boolean\n private debug: boolean\n private readonly id: number\n\n // Static counter for generating unique handler IDs\n private static nextHandlerId = 1\n\n /**\n * Create a new PGLiteSocketHandler\n * @param options Options for the handler\n */\n constructor(options: PGLiteSocketHandlerOptions) {\n super()\n this.db = options.db\n this.closeOnDetach = options.closeOnDetach ?? false\n this.inspect = options.inspect ?? false\n this.debug = options.debug ?? false\n this.id = PGLiteSocketHandler.nextHandlerId++\n\n this.log('constructor: created new handler')\n }\n\n /**\n * Get the unique ID of this handler\n */\n public get handlerId(): number {\n return this.id\n }\n\n /**\n * Log a message if debug is enabled\n * @private\n */\n private log(message: string, ...args: any[]): void {\n if (this.debug) {\n console.log(`[PGLiteSocketHandler#${this.id}] ${message}`, ...args)\n }\n }\n\n /**\n * Attach a socket to this handler\n * @param socket The socket to attach\n * @returns this handler instance\n * @throws Error if a socket is already attached\n */\n public async attach(socket: Socket): Promise<PGLiteSocketHandler> {\n this.log(\n `attach: attaching socket from ${socket.remoteAddress}:${socket.remotePort}`,\n )\n\n if (this.socket) {\n throw new Error('Socket already attached')\n }\n\n this.socket = socket\n this.active = true\n\n // Ensure the PGlite instance is ready\n this.log(`attach: waiting for PGlite to be ready`)\n await this.db.waitReady\n\n // Hold the lock on the PGlite instance\n this.log(`attach: acquiring exclusive lock on PGlite instance`)\n await new Promise<void>((resolve) => {\n this.db.runExclusive(() => {\n // Ensure we have the lock on the PGlite instance\n resolve()\n\n // Use a promise to hold the lock on the PGlite instance\n // this can be resolved or rejected by the handler to release the lock\n return new Promise<void>((resolveLock, rejectLock) => {\n this.resolveLock = resolveLock\n this.rejectLock = rejectLock\n })\n })\n })\n\n // Setup event handlers\n this.log(`attach: setting up socket event handlers`)\n socket.on('data', async (data) => {\n try {\n const result = await this.handleData(data)\n this.log(`socket on data sent: ${result} bytes`)\n } catch (err) {\n this.log('socket on data error: ', err)\n }\n })\n socket.on('error', (err) => this.handleError(err))\n socket.on('close', () => this.handleClose())\n\n return this\n }\n\n /**\n * Detach the current socket from this handler\n * @param close Whether to close the socket when detaching (overrides constructor option)\n * @returns this handler instance\n */\n public detach(close?: boolean): PGLiteSocketHandler {\n this.log(`detach: detaching socket, close=${close ?? this.closeOnDetach}`)\n\n if (!this.socket) {\n this.log(`detach: no socket attached, nothing to do`)\n return this\n }\n\n // Remove all listeners\n this.socket.removeAllListeners('data')\n this.socket.removeAllListeners('error')\n this.socket.removeAllListeners('close')\n\n // Close the socket if requested\n if (close ?? this.closeOnDetach) {\n if (this.socket.writable) {\n this.log(`detach: closing socket`)\n this.socket.end()\n this.socket.destroy()\n }\n }\n\n // Release the lock on the PGlite instance\n this.log(`detach: releasing exclusive lock on PGlite instance`)\n this.resolveLock?.()\n\n this.socket = null\n this.active = false\n return this\n }\n\n /**\n * Check if a socket is currently attached\n */\n public get isAttached(): boolean {\n return this.socket !== null\n }\n\n /**\n * Handle incoming data from the socket\n */\n private async handleData(data: Buffer): Promise<number> {\n if (!this.socket || !this.active) {\n this.log(`handleData: no active socket, ignoring data`)\n return new Promise((_, reject) => reject(`no active socket`))\n }\n\n this.log(`handleData: received ${data.length} bytes`)\n\n // Print the incoming data to the console\n this.inspectData('incoming', data)\n\n try {\n // Process the raw protocol data\n this.log(`handleData: sending data to PGlite for processing`)\n const result = await this.db.execProtocolRaw(new Uint8Array(data))\n\n this.log(`handleData: received ${result.length} bytes from PGlite`)\n\n // Print the outgoing data to the console\n this.inspectData('outgoing', result)\n\n // Send the result back if the socket is still connected\n if (this.socket && this.socket.writable && this.active) {\n if (result.length <= 0) {\n this.log(`handleData: cowardly refusing to send empty packet`)\n return new Promise((_, reject) => reject('no data'))\n }\n\n const promise = new Promise<number>((resolve, reject) => {\n this.log(`handleData: writing response to socket`)\n if (this.socket) {\n this.socket.write(Buffer.from(result), (err?: Error) => {\n if (err) {\n reject(`Error while writing to the socket ${err.toString()}`)\n } else {\n resolve(result.length)\n }\n })\n } else {\n reject(`No socket`)\n }\n })\n\n // Emit data event with byte sizes\n this.dispatchEvent(\n new CustomEvent('data', {\n detail: { incoming: data.length, outgoing: result.length },\n }),\n )\n return promise\n } else {\n this.log(\n `handleData: socket no longer writable or active, discarding response`,\n )\n return new Promise((_, reject) =>\n reject(`No socket, not active or not writeable`),\n )\n }\n } catch (err) {\n this.log(`handleData: error processing data:`, err)\n this.handleError(err as Error)\n return new Promise((_, reject) =>\n reject(`Error while processing data ${(err as Error).toString()}`),\n )\n }\n }\n\n /**\n * Handle errors from the socket\n */\n private handleError(err: Error): void {\n this.log(`handleError:`, err)\n\n // Emit error event\n this.dispatchEvent(new CustomEvent('error', { detail: err }))\n\n // Reject the lock on the PGlite instance\n this.log(`handleError: rejecting exclusive lock on PGlite instance`)\n this.rejectLock?.(err)\n this.resolveLock = undefined\n this.rejectLock = undefined\n\n // Close the connection on error\n this.detach(true)\n }\n\n /**\n * Handle socket close event\n */\n private handleClose(): void {\n this.log(`handleClose: socket closed`)\n\n this.dispatchEvent(new CustomEvent('close'))\n this.detach(false) // Already closed, just clean up\n }\n\n /**\n * Print data in hex and ascii to the console\n */\n private inspectData(\n direction: 'incoming' | 'outgoing',\n data: Buffer | Uint8Array,\n ): void {\n if (!this.inspect) return\n console.log('-'.repeat(75))\n if (direction === 'incoming') {\n console.log('-> incoming', data.length, 'bytes')\n } else {\n console.log('<- outgoing', data.length, 'bytes')\n }\n\n // Process 16 bytes per line\n for (let offset = 0; offset < data.length; offset += 16) {\n // Calculate current chunk size (may be less than 16 for the last chunk)\n const chunkSize = Math.min(16, data.length - offset)\n\n // Build the hex representation\n let hexPart = ''\n for (let i = 0; i < 16; i++) {\n if (i < chunkSize) {\n const byte = data[offset + i]\n hexPart += byte.toString(16).padStart(2, '0') + ' '\n } else {\n hexPart += ' ' // 3 spaces for missing bytes\n }\n }\n\n // Build the ASCII representation\n let asciiPart = ''\n for (let i = 0; i < chunkSize; i++) {\n const byte = data[offset + i]\n // Use printable characters (32-126), replace others with a dot\n asciiPart += byte >= 32 && byte <= 126 ? String.fromCharCode(byte) : '.'\n }\n\n // Print the line with offset in hex, hex values, and ASCII representation\n console.log(\n `${offset.toString(16).padStart(8, '0')} ${hexPart} ${asciiPart}`,\n )\n }\n }\n}\n\n/**\n * Represents a queued connection with timeout\n */\ninterface QueuedConnection {\n socket: Socket\n clientInfo: {\n clientAddress: string\n clientPort: number\n }\n timeoutId: NodeJS.Timeout\n}\n\n/**\n * Options for creating a PGLiteSocketServer\n */\nexport interface PGLiteSocketServerOptions {\n /** The PGlite database instance */\n db: PGlite\n /** The port to listen on (default: 5432) */\n port?: number\n /** The host to bind to (default: 127.0.0.1) */\n host?: string\n /** Unix socket path to bind to (default: undefined). If specified, takes precedence over host:port */\n path?: string\n /** Print the incoming and outgoing data to the console in hex and ascii */\n inspect?: boolean\n /** Connection queue timeout in milliseconds (default: 10000) */\n connectionQueueTimeout?: number\n /** Enable debug logging of method calls */\n debug?: boolean\n}\n\n/**\n * High-level server that manages socket connections to PGLite\n * Creates and manages a TCP server and handles client connections\n */\nexport class PGLiteSocketServer extends EventTarget {\n readonly db: PGlite\n private server: Server | null = null\n private port?: number\n private host?: string\n private path?: string\n private active = false\n private inspect: boolean\n private debug: boolean\n private connectionQueueTimeout: number\n private activeHandler: PGLiteSocketHandler | null = null\n private connectionQueue: QueuedConnection[] = []\n private handlerCount: number = 0\n\n /**\n * Create a new PGLiteSocketServer\n * @param options Options for the server\n */\n constructor(options: PGLiteSocketServerOptions) {\n super()\n this.db = options.db\n if (options.path) {\n this.path = options.path\n } else {\n this.port = options.port || 5432\n this.host = options.host || '127.0.0.1'\n }\n this.inspect = options.inspect ?? false\n this.debug = options.debug ?? false\n this.connectionQueueTimeout =\n options.connectionQueueTimeout ?? CONNECTION_QUEUE_TIMEOUT\n\n this.log(`constructor: created server on ${this.host}:${this.port}`)\n this.log(\n `constructor: connection queue timeout: ${this.connectionQueueTimeout}ms`,\n )\n }\n\n /**\n * Log a message if debug is enabled\n * @private\n */\n private log(message: string, ...args: any[]): void {\n if (this.debug) {\n console.log(`[PGLiteSocketServer] ${message}`, ...args)\n }\n }\n\n /**\n * Start the socket server\n * @returns Promise that resolves when the server is listening\n */\n public async start(): Promise<void> {\n this.log(`start: starting server on ${this.getServerConn()}`)\n\n if (this.server) {\n throw new Error('Socket server already started')\n }\n\n this.active = true\n this.server = createServer((socket) => this.handleConnection(socket))\n\n return new Promise<void>((resolve, reject) => {\n if (!this.server) return reject(new Error('Server not initialized'))\n\n this.server.on('error', (err) => {\n this.log(`start: server error:`, err)\n this.dispatchEvent(new CustomEvent('error', { detail: err }))\n reject(err)\n })\n\n if (this.path) {\n this.server.listen(this.path, () => {\n this.log(`start: server listening on ${this.getServerConn()}`)\n this.dispatchEvent(\n new CustomEvent('listening', {\n detail: { path: this.path },\n }),\n )\n resolve()\n })\n } else {\n this.server.listen(this.port, this.host, () => {\n this.log(`start: server listening on ${this.getServerConn()}`)\n this.dispatchEvent(\n new CustomEvent('listening', {\n detail: { port: this.port, host: this.host },\n }),\n )\n resolve()\n })\n }\n })\n }\n\n public getServerConn(): string {\n if (this.path) return this.path\n return `${this.host}:${this.port}`\n }\n\n /**\n * Stop the socket server\n * @returns Promise that resolves when the server is closed\n */\n public async stop(): Promise<void> {\n this.log(`stop: stopping server`)\n\n this.active = false\n\n // Clear connection queue\n this.log(\n `stop: clearing connection queue (${this.connectionQueue.length} connections)`,\n )\n\n this.connectionQueue.forEach((queuedConn) => {\n clearTimeout(queuedConn.timeoutId)\n if (queuedConn.socket.writable) {\n this.log(\n `stop: closing queued connection from ${queuedConn.clientInfo.clientAddress}:${queuedConn.clientInfo.clientPort}`,\n )\n queuedConn.socket.end()\n }\n })\n this.connectionQueue = []\n\n // Detach active handler if exists\n if (this.activeHandler) {\n this.log(`stop: detaching active handler #${this.activeHandlerId}`)\n this.activeHandler.detach(true)\n this.activeHandler = null\n }\n\n if (!this.server) {\n this.log(`stop: server not running, nothing to do`)\n return Promise.resolve()\n }\n\n return new Promise<void>((resolve) => {\n if (!this.server) return resolve()\n\n this.server.close(() => {\n this.log(`stop: server closed`)\n this.server = null\n this.dispatchEvent(new CustomEvent('close'))\n resolve()\n })\n })\n }\n\n /**\n * Get the active handler ID, or null if no active handler\n */\n private get activeHandlerId(): number | null {\n return this.activeHandler?.handlerId ?? null\n }\n\n /**\n * Handle a new client connection\n */\n private async handleConnection(socket: Socket): Promise<void> {\n const clientInfo = {\n clientAddress: socket.remoteAddress || 'unknown',\n clientPort: socket.remotePort || 0,\n }\n\n this.log(\n `handleConnection: new connection from ${clientInfo.clientAddress}:${clientInfo.clientPort}`,\n )\n\n // If server is not active, close the connection immediately\n if (!this.active) {\n this.log(`handleConnection: server not active, closing connection`)\n socket.end()\n return\n }\n\n // If we don't have an active handler or it's not attached, we can use this connection immediately\n if (!this.activeHandler || !this.activeHandler.isAttached) {\n this.log(`handleConnection: no active handler, attaching socket directly`)\n this.dispatchEvent(new CustomEvent('connection', { detail: clientInfo }))\n await this.attachSocketToNewHandler(socket, clientInfo)\n return\n }\n\n // Otherwise, queue the connection\n this.log(\n `handleConnection: active handler #${this.activeHandlerId} exists, queueing connection`,\n )\n this.enqueueConnection(socket, clientInfo)\n }\n\n /**\n * Add a connection to the queue\n */\n private enqueueConnection(\n socket: Socket,\n clientInfo: { clientAddress: string; clientPort: number },\n ): void {\n this.log(\n `enqueueConnection: queueing connection from ${clientInfo.clientAddress}:${clientInfo.clientPort}, timeout: ${this.connectionQueueTimeout}ms`,\n )\n\n // Set a timeout for this queued connection\n const timeoutId = setTimeout(() => {\n this.log(\n `enqueueConnection: timeout for connection from ${clientInfo.clientAddress}:${clientInfo.clientPort}`,\n )\n\n // Remove from queue\n this.connectionQueue = this.connectionQueue.filter(\n (queuedConn) => queuedConn.socket !== socket,\n )\n\n // End the connection if it's still open\n if (socket.writable) {\n this.log(`enqueueConnection: closing timed out connection`)\n socket.end()\n }\n\n this.dispatchEvent(\n new CustomEvent('queueTimeout', {\n detail: { ...clientInfo, queueSize: this.connectionQueue.length },\n }),\n )\n }, this.connectionQueueTimeout)\n\n // Add to queue\n this.connectionQueue.push({ socket, clientInfo, timeoutId })\n\n this.log(\n `enqueueConnection: connection queued, queue size: ${this.connectionQueue.length}`,\n )\n\n this.dispatchEvent(\n new CustomEvent('queuedConnection', {\n detail: { ...clientInfo, queueSize: this.connectionQueue.length },\n }),\n )\n }\n\n /**\n * Process the next connection in the queue\n */\n private processNextInQueue(): void {\n this.log(\n `processNextInQueue: processing next connection, queue size: ${this.connectionQueue.length}`,\n )\n\n // No connections in queue or server not active\n if (this.connectionQueue.length === 0 || !this.active) {\n this.log(\n `processNextInQueue: no connections in queue or server not active, nothing to do`,\n )\n return\n }\n\n // Get the next connection\n const nextConn = this.connectionQueue.shift()\n if (!nextConn) return\n\n this.log(\n `processNextInQueue: processing connection from ${nextConn.clientInfo.clientAddress}:${nextConn.clientInfo.clientPort}`,\n )\n\n // Clear the timeout\n clearTimeout(nextConn.timeoutId)\n\n // Check if the socket is still valid\n if (!nextConn.socket.writable) {\n this.log(\n `processNextInQueue: socket no longer writable, skipping to next connection`,\n )\n // Socket closed while waiting, process next in queue\n this.processNextInQueue()\n return\n }\n\n // Attach this socket to a new handler\n this.attachSocketToNewHandler(nextConn.socket, nextConn.clientInfo).catch(\n (err) => {\n this.log(`processNextInQueue: error attaching socket:`, err)\n this.dispatchEvent(new CustomEvent('error', { detail: err }))\n // Try the next connection\n this.processNextInQueue()\n },\n )\n }\n\n /**\n * Attach a socket to a new handler\n */\n private async attachSocketToNewHandler(\n socket: Socket,\n clientInfo: { clientAddress: string; clientPort: number },\n ): Promise<void> {\n this.handlerCount++\n\n this.log(\n `attachSocketToNewHandler: creating new handler for ${clientInfo.clientAddress}:${clientInfo.clientPort} (handler #${this.handlerCount})`,\n )\n\n // Create a new handler for this connection\n const handler = new PGLiteSocketHandler({\n db: this.db,\n closeOnDetach: true,\n inspect: this.inspect,\n debug: this.debug,\n })\n\n // Forward error events from the handler\n handler.addEventListener('error', (event) => {\n this.log(\n `handler #${handler.handlerId}: error from handler:`,\n (event as CustomEvent<Error>).detail,\n )\n this.dispatchEvent(\n new CustomEvent('error', {\n detail: (event as CustomEvent<Error>).detail,\n }),\n )\n })\n\n // Handle close event to process next queued connection\n handler.addEventListener('close', () => {\n this.log(`handler #${handler.handlerId}: closed`)\n\n // If this is our active handler, clear it\n if (this.activeHandler === handler) {\n this.log(\n `handler #${handler.handlerId}: was active handler, processing next connection in queue`,\n )\n this.activeHandler = null\n // Process next connection in queue\n this.processNextInQueue()\n }\n })\n\n try {\n // Set as active handler\n this.activeHandler = handler\n\n this.log(`handler #${handler.handlerId}: attaching socket`)\n\n // Attach the socket to the handler\n await handler.attach(socket)\n\n this.dispatchEvent(new CustomEvent('connection', { detail: clientInfo }))\n } catch (err) {\n // If there was an error attaching, clean up\n this.log(`handler #${handler.handlerId}: error attaching socket:`, err)\n this.activeHandler = null\n if (socket.writable) {\n socket.end()\n }\n throw err\n }\n }\n}\n"],"mappings":"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","names":["src_exports","__export","CONNECTION_QUEUE_TIMEOUT","PGLiteSocketHandler","PGLiteSocketServer","__toCommonJS","import_net","CONNECTION_QUEUE_TIMEOUT","_PGLiteSocketHandler","options","message","args","socket","resolve","resolveLock","rejectLock","data","result","err","close","_","reject","promise","direction","offset","chunkSize","hexPart","i","byte","asciiPart","PGLiteSocketHandler","PGLiteSocketServer","queuedConn","clientInfo","timeoutId","nextConn","handler","event"]}