diff --git a/server/src/plugin/plugin-host.ts b/server/src/plugin/plugin-host.ts index 59242e3c6..7adf1893c 100644 --- a/server/src/plugin/plugin-host.ts +++ b/server/src/plugin/plugin-host.ts @@ -4,7 +4,7 @@ import { SystemManager, DeviceManager, ScryptedNativeId, Device, EventListenerRe import { ScryptedRuntime } from '../runtime'; import { Plugin } from '../db-types'; import io, { Socket } from 'engine.io'; -import { attachPluginRemote, setupPluginRemote } from './plugin-remote'; +import { attachPluginRemote, PluginReader, setupPluginRemote } from './plugin-remote'; import { PluginAPI, PluginAPIProxy, PluginRemote, PluginRemoteLoadZipOptions } from './plugin-api'; import { Logger } from '../logger'; import { MediaManagerHostImpl, MediaManagerImpl } from './media'; @@ -560,9 +560,9 @@ export function startPluginRemote() { } throw new Error(`unknown service ${name}`); }, - async onLoadZip(zip: AdmZip, packageJson: any) { - const entry = zip.getEntry('main.nodejs.js.map') - const map = entry?.getData().toString(); + async onLoadZip(pluginReader: PluginReader, packageJson: any) { + const entry = pluginReader('main.nodejs.js.map') + const map = entry?.toString(); installSourceMapSupport({ environment: 'node', diff --git a/server/src/plugin/plugin-http.ts b/server/src/plugin/plugin-http.ts index d1a4f2a5d..63b30432d 100644 --- a/server/src/plugin/plugin-http.ts +++ b/server/src/plugin/plugin-http.ts @@ -28,8 +28,8 @@ export abstract class PluginHttp { }); } - abstract handleEngineIOEndpoint(req: Request, res: ServerResponse, endpointRequest: HttpRequest, pluginData: T): Promise; - abstract handleRequestEndpoint(req: Request, res: Response, endpointRequest: HttpRequest, pluginData: T): Promise; + abstract handleEngineIOEndpoint(req: Request, res: ServerResponse, endpointRequest: HttpRequest, pluginData: T): void; + abstract handleRequestEndpoint(req: Request, res: Response, endpointRequest: HttpRequest, pluginData: T): void; abstract getEndpointPluginData(endpoint: string, isUpgrade: boolean, isEngineIOEndpoint: boolean): Promise; abstract handleWebSocket(endpoint: string, httpRequest: HttpRequest, ws: WebSocket, pluginData: T): Promise; diff --git a/server/src/plugin/plugin-remote.ts b/server/src/plugin/plugin-remote.ts index 77112dc54..fbd666c79 100644 --- a/server/src/plugin/plugin-remote.ts +++ b/server/src/plugin/plugin-remote.ts @@ -308,13 +308,15 @@ export interface WebSocketCustomHandler { methods: WebSocketMethods; } +export type PluginReader = (name: string) => Buffer; + export interface PluginRemoteAttachOptions { createMediaManager?: (systemManager: SystemManager) => Promise; getServicePort?: (name: string, ...args: any[]) => Promise; getDeviceConsole?: (nativeId?: ScryptedNativeId) => Console; getPluginConsole?: () => Console; getMixinConsole?: (id: string, nativeId?: ScryptedNativeId) => Console; - onLoadZip?: (zip: AdmZip, packageJson: any) => Promise; + onLoadZip?: (pluginReader: PluginReader, packageJson: any) => Promise; onGetRemote?: (api: PluginAPI, pluginId: string) => Promise; onPluginReady?: (scrypted: ScryptedStatic, params: any, plugin: any) => Promise; } @@ -438,21 +440,22 @@ export function attachPluginRemote(peer: RpcPeer, options?: PluginRemoteAttachOp async loadZip(packageJson: any, zipData: Buffer | string, zipOptions?: PluginRemoteLoadZipOptions) { const pluginConsole = getPluginConsole?.(); - let zip = new AdmZip(zipData); - zipData = undefined; - await options?.onLoadZip?.(zip, packageJson); - const main = zip.getEntry('main.nodejs.js'); - const script = main.getData().toString(); - const window: any = {}; - const exports: any = window; - window.exports = exports; let volume: any; - if (zipOptions?.unzippedPath && fs.existsSync(path.join(zipOptions.unzippedPath, 'fs'))) { + let pluginReader: PluginReader; + if (zipOptions?.unzippedPath && fs.existsSync(zipOptions?.unzippedPath)) { volume = link(fs, ['', path.join(zipOptions.unzippedPath, 'fs')]); + pluginReader = name => { + const filename = path.join(zipOptions.unzippedPath, name); + if (!fs.existsSync(filename)) + return; + return fs.readFileSync(filename); + }; } else { - for (const entry of zip.getEntries()) { + const admZip = new AdmZip(zipData); + volume = new Volume(); + for (const entry of admZip.getEntries()) { if (entry.isDirectory) continue; if (!entry.entryName.startsWith('fs/')) @@ -462,8 +465,24 @@ export function attachPluginRemote(peer: RpcPeer, options?: PluginRemoteAttachOp const data = entry.getData(); volume.writeFileSync(name, data); } + + pluginReader = name => { + const entry = admZip.getEntry(name); + if (!entry) + return; + return entry.getData(); + } } - zip = undefined; + zipData = undefined; + + await options?.onLoadZip?.(pluginReader, packageJson); + const main = pluginReader('main.nodejs.js'); + pluginReader = undefined; + const script = main.toString(); + const window: any = {}; + const exports: any = window; + window.exports = exports; + function websocketConnect(url: string, protocols: any, callbacks: WebSocketConnectCallbacks) { if (url.startsWith('io://') || url.startsWith('ws://')) { diff --git a/server/src/runtime.ts b/server/src/runtime.ts index dc51bb7f3..8d64fdec5 100644 --- a/server/src/runtime.ts +++ b/server/src/runtime.ts @@ -313,7 +313,7 @@ export class ScryptedRuntime extends PluginHttp { } } - async handleEngineIOEndpoint(req: Request, res: ServerResponse, endpointRequest: HttpRequest, pluginData: HttpPluginData) { + handleEngineIOEndpoint(req: Request, res: ServerResponse, endpointRequest: HttpRequest, pluginData: HttpPluginData) { const { pluginHost, pluginDevice } = pluginData; (req as any).scrypted = { @@ -326,7 +326,7 @@ export class ScryptedRuntime extends PluginHttp { pluginHost.io.handleRequest(req, res); } - async handleRequestEndpoint(req: Request, res: Response, endpointRequest: HttpRequest, pluginData: HttpPluginData) { + handleRequestEndpoint(req: Request, res: Response, endpointRequest: HttpRequest, pluginData: HttpPluginData) { const { pluginHost, pluginDevice } = pluginData; const handler = this.getDevice(pluginDevice._id); if (handler.interfaces.includes(ScryptedInterface.EngineIOHandler) && req.headers.connection === 'upgrade' && req.headers.upgrade?.toLowerCase() === 'websocket') {