import { EventEmitter } from 'ws'; import { listenZero } from './listen-zero'; import { Server } from 'net'; import { once } from 'events'; import repl from 'repl'; import { ScryptedStatic } from '@scrypted/sdk'; export async function createREPLServer(scrypted: ScryptedStatic, params: any, plugin: any): Promise { const { deviceManager, systemManager } = scrypted; const server = new Server(async (socket) => { let [filter] = await once(socket, 'data'); filter = filter.toString().trim(); if (filter === 'undefined') filter = undefined; const chain: string[] = []; const nativeIds: Map = (deviceManager as any).nativeIds; const reversed = new Map(); for (const nativeId of nativeIds.keys()) { reversed.set(nativeIds.get(nativeId).id, nativeId); } while (filter) { const { id } = nativeIds.get(filter); const d = await systemManager.getDeviceById(id); chain.push(filter); filter = reversed.get(d.providerId); } chain.reverse(); let device = plugin; for (const c of chain) { device = await device.getDevice(c); } const ctx = Object.assign(params, { device }); delete ctx.console; delete ctx.window; delete ctx.WebSocket; delete ctx.pluginHostAPI; const replFilter = new Set(['require', 'localStorage']) const replVariables = Object.keys(ctx).filter(key => !replFilter.has(key)); const welcome = `JavaScript REPL variables:\n${replVariables.map(key => ' ' + key).join('\n')}\n\n`; socket.write(welcome); const r = repl.start({ terminal: true, input: socket, output: socket, // writer(this: REPLServer, obj: any) { // const ret = util.inspect(obj, { // colors: true, // }); // return ret;//.replaceAll('\n', '\r\n'); // }, preview: false, }); Object.assign(r.context, ctx); const cleanup = () => { r.close(); }; socket.on('close', cleanup); socket.on('error', cleanup); socket.on('end', cleanup); }); return listenZero(server); }