From cb3591e6136ac14713e63ea0141f58dcef24906f Mon Sep 17 00:00:00 2001 From: Koushik Dutta Date: Sat, 25 Jun 2022 14:17:24 -0700 Subject: [PATCH] core: add script default export support --- common/src/eval/monaco/script-device.ts | 4 +++ common/src/eval/scrypted-eval.ts | 9 +++++-- .../fs/examples/chromecast-view-camera.ts | 2 +- .../fs/examples/switch-trigger-webhook.ts | 2 +- .../core/fs/examples/webhook-motion-sensor.ts | 3 ++- .../core/fs/examples/webhook-thermometer.ts | 5 ++-- plugins/core/src/automation.ts | 2 +- plugins/core/src/builtins/javascript.ts | 4 +-- plugins/core/src/script.ts | 27 +++++++++++++------ .../core/ui/src/interfaces/CameraViewer.vue | 2 +- 10 files changed, 41 insertions(+), 19 deletions(-) diff --git a/common/src/eval/monaco/script-device.ts b/common/src/eval/monaco/script-device.ts index 72612ca7c..fdb175cd0 100644 --- a/common/src/eval/monaco/script-device.ts +++ b/common/src/eval/monaco/script-device.ts @@ -1,4 +1,8 @@ export interface ScriptDevice { + /** + * @deprecated Use export default instead. + * @param handler + */ handle(handler?: T & object): void; handleTypes(...interfaces: string[]): void; } diff --git a/common/src/eval/scrypted-eval.ts b/common/src/eval/scrypted-eval.ts index 0f5149686..6a62de50f 100644 --- a/common/src/eval/scrypted-eval.ts +++ b/common/src/eval/scrypted-eval.ts @@ -82,7 +82,7 @@ export async function scryptedEval(device: ScryptedDeviceBase, script: string, e console: device.console, localStorage: device.storage, device, - exports: {}, + exports: {} as any, ScryptedInterface, ScryptedDeviceType, }); @@ -102,7 +102,12 @@ export async function scryptedEval(device: ScryptedDeviceBase, script: string, e } try { - return await asyncFunction(); + const value = await asyncFunction(); + const defaultExport = allParams.exports.default; + return { + value, + defaultExport, + }; } catch (e) { device.log.e('Error running script.'); diff --git a/plugins/core/fs/examples/chromecast-view-camera.ts b/plugins/core/fs/examples/chromecast-view-camera.ts index 836ee6447..436049edb 100644 --- a/plugins/core/fs/examples/chromecast-view-camera.ts +++ b/plugins/core/fs/examples/chromecast-view-camera.ts @@ -33,4 +33,4 @@ class ChromecastViewCameraExample implements StartStop { } } -device.handle(new ChromecastViewCameraExample()); +export default ChromecastViewCameraExample; diff --git a/plugins/core/fs/examples/switch-trigger-webhook.ts b/plugins/core/fs/examples/switch-trigger-webhook.ts index 165c161b8..b83c800d2 100644 --- a/plugins/core/fs/examples/switch-trigger-webhook.ts +++ b/plugins/core/fs/examples/switch-trigger-webhook.ts @@ -17,4 +17,4 @@ class SwitchWebhookExample implements OnOff { } } -device.handle(new SwitchWebhookExample()); +export default SwitchWebhookExample; diff --git a/plugins/core/fs/examples/webhook-motion-sensor.ts b/plugins/core/fs/examples/webhook-motion-sensor.ts index 6982ceb2e..3adab6d66 100644 --- a/plugins/core/fs/examples/webhook-motion-sensor.ts +++ b/plugins/core/fs/examples/webhook-motion-sensor.ts @@ -15,8 +15,9 @@ class WebhookExample implements HttpRequestHandler { } } -device.handle(new WebhookExample()); device.handleTypes(ScryptedInterface.MotionSensor); endpointManager.getInsecurePublicLocalEndpoint(device.nativeId) .then(endpoint => console.log('motion webhook:', endpoint)); + +export default WebhookExample; diff --git a/plugins/core/fs/examples/webhook-thermometer.ts b/plugins/core/fs/examples/webhook-thermometer.ts index 2db4e7a6a..d562c27f4 100644 --- a/plugins/core/fs/examples/webhook-thermometer.ts +++ b/plugins/core/fs/examples/webhook-thermometer.ts @@ -9,11 +9,10 @@ class WebhookExample implements HttpRequestHandler { async onRequest(request: HttpRequest, response: HttpResponse) { response.send('OK'); // scrpyted uses metric for all units, so this must be celsius - device.temperature = parseFloat(request.body); + device.temperature = parseFloat(request.body!); } } -device.handle(new WebhookExample()); device.handleTypes(ScryptedInterface.Thermometer); endpointManager.getInsecurePublicLocalEndpoint(device.nativeId) @@ -22,3 +21,5 @@ endpointManager.getInsecurePublicLocalEndpoint(device.nativeId) console.log('example:'); console.log(' curl -H "Content-Type: text/plain" --data 25 ', endpoint); }); + +export default WebhookExample; diff --git a/plugins/core/src/automation.ts b/plugins/core/src/automation.ts index 128b45b98..925104d9f 100644 --- a/plugins/core/src/automation.ts +++ b/plugins/core/src/automation.ts @@ -55,7 +55,7 @@ export class Automation extends ScryptedDeviceBase implements OnOff, Settings { } async eval(script: string, variables: { [name: string]: any }) { - return scryptedEval(this, script, variables); + return (await scryptedEval(this, script, variables)).value; } async turnOff() { diff --git a/plugins/core/src/builtins/javascript.ts b/plugins/core/src/builtins/javascript.ts index 779e38536..88eb024b8 100644 --- a/plugins/core/src/builtins/javascript.ts +++ b/plugins/core/src/builtins/javascript.ts @@ -15,10 +15,10 @@ export class AutomationJavascript { } async run(script: string) { - return scryptedEval(this.automation, script, { + return (await scryptedEval(this.automation, script, { eventDetails: this.eventDetails, eventData: this.eventData, eventSource: this.eventSource, - }) + })).value; } } diff --git a/plugins/core/src/script.ts b/plugins/core/src/script.ts index 78af8fbd1..1ddec4921 100644 --- a/plugins/core/src/script.ts +++ b/plugins/core/src/script.ts @@ -42,7 +42,18 @@ export class Script extends ScryptedDeviceBase implements Scriptable, Program, S } } - async postRunScript() { + async postRunScript(defaultExport: any) { + if (defaultExport) { + let deviceInstance = defaultExport; + // support exporting a plugin class, plugin main function, + // or a plugin instance + if (deviceInstance.toString().startsWith('class ')) + deviceInstance = new deviceInstance(this.nativeId); + if (typeof deviceInstance === 'function') + deviceInstance = await deviceInstance(); + this.handle(deviceInstance); + } + const allInterfaces = this.mergeHandler(this); if (allInterfaces.length !== 2) { await deviceManager.onDeviceDiscovered({ @@ -60,7 +71,7 @@ export class Script extends ScryptedDeviceBase implements Scriptable, Program, S ScryptedInterface.Scriptable, ScryptedInterface.Program, ])); - } + } async run(variables?: { [name: string]: any; }): Promise { this.prepareScript(); @@ -68,12 +79,12 @@ export class Script extends ScryptedDeviceBase implements Scriptable, Program, S try { const data = JSON.parse(this.storage.getItem('data')); - const ret = await scryptedEval(this, data['script.ts'], Object.assign({ + const { value, defaultExport } = await scryptedEval(this, data['script.ts'], Object.assign({ device: this, }, variables)); - await this.postRunScript(); - return ret; + await this.postRunScript(defaultExport); + return value; } catch (e) { this.console.error('error loading script', e); @@ -84,12 +95,12 @@ export class Script extends ScryptedDeviceBase implements Scriptable, Program, S async eval(source: ScriptSource, variables: { [name: string]: any }) { this.prepareScript(); - const ret = await scryptedEval(this, source.script, Object.assign({ + const { value, defaultExport } = await scryptedEval(this, source.script, Object.assign({ device: this, }, variables)); - await this.postRunScript(); - return ret; + await this.postRunScript(defaultExport); + return value; } // will be done at runtime diff --git a/plugins/core/ui/src/interfaces/CameraViewer.vue b/plugins/core/ui/src/interfaces/CameraViewer.vue index e50ee0f6d..4eb626b1d 100644 --- a/plugins/core/ui/src/interfaces/CameraViewer.vue +++ b/plugins/core/ui/src/interfaces/CameraViewer.vue @@ -237,7 +237,7 @@ export default { this.adjustingTime = setTimeout(() => { this.adjustingTime = null; this.streamRecorder(this.startTime); - }, 2500); + }, 10); }, cleanupConnection() { console.log("control cleanup");