server: use unzipped plugin path where possible

This commit is contained in:
Koushik Dutta
2022-01-06 21:19:29 -08:00
parent 27ead61c3a
commit d3638dce37
4 changed files with 39 additions and 20 deletions

View File

@@ -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',

View File

@@ -28,8 +28,8 @@ export abstract class PluginHttp<T> {
});
}
abstract handleEngineIOEndpoint(req: Request, res: ServerResponse, endpointRequest: HttpRequest, pluginData: T): Promise<void>;
abstract handleRequestEndpoint(req: Request, res: Response, endpointRequest: HttpRequest, pluginData: T): Promise<void>;
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<T>;
abstract handleWebSocket(endpoint: string, httpRequest: HttpRequest, ws: WebSocket, pluginData: T): Promise<void>;

View File

@@ -308,13 +308,15 @@ export interface WebSocketCustomHandler {
methods: WebSocketMethods;
}
export type PluginReader = (name: string) => Buffer;
export interface PluginRemoteAttachOptions {
createMediaManager?: (systemManager: SystemManager) => Promise<MediaManager>;
getServicePort?: (name: string, ...args: any[]) => Promise<number>;
getDeviceConsole?: (nativeId?: ScryptedNativeId) => Console;
getPluginConsole?: () => Console;
getMixinConsole?: (id: string, nativeId?: ScryptedNativeId) => Console;
onLoadZip?: (zip: AdmZip, packageJson: any) => Promise<void>;
onLoadZip?: (pluginReader: PluginReader, packageJson: any) => Promise<void>;
onGetRemote?: (api: PluginAPI, pluginId: string) => Promise<void>;
onPluginReady?: (scrypted: ScryptedStatic, params: any, plugin: any) => Promise<void>;
}
@@ -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://')) {

View File

@@ -313,7 +313,7 @@ export class ScryptedRuntime extends PluginHttp<HttpPluginData> {
}
}
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<HttpPluginData> {
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<HttpRequestHandler>(pluginDevice._id);
if (handler.interfaces.includes(ScryptedInterface.EngineIOHandler) && req.headers.connection === 'upgrade' && req.headers.upgrade?.toLowerCase() === 'websocket') {