Skip to content

Commit b565c11

Browse files
authored
Merge pull request #71 from yeuai/dev-context
Wrap code for browser
2 parents f8c8afc + 344e604 commit b565c11

File tree

6 files changed

+72
-4
lines changed

6 files changed

+72
-4
lines changed

src/engine/context.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Struct } from './struct';
44
import { IActivator } from '../interfaces/activator';
55
import { Logger } from '../lib/logger';
66
import { Trigger } from './trigger';
7-
import { wrapCode } from '../plugins/built-in';
7+
import { wrapCode, wrapCodeBrowser } from '../plugins/built-in';
88
import * as utils from '../lib/utils';
99

1010
/**
@@ -161,6 +161,7 @@ export class Context {
161161
} else if (/^plugin/.test(item)) {
162162
const vPlugin = this.directives.get(item) as Struct;
163163
const vCode = wrapCode(vPlugin.value);
164+
const vCodeBrowser = wrapCodeBrowser(vPlugin.value);
164165
const vName = vPlugin.name.replace(/^plugin:/, '');
165166
// this.this.logger.debug(`javascript code: /plugin: ${vName} => ${vCode}`);
166167
this.logger.debug(`add custom plugin & save handler in it own directive: /${vPlugin.name}`);
@@ -177,7 +178,7 @@ export class Context {
177178
} else {
178179
this.logger.debug(`Execute /plugin: ${vName} in browser!`);
179180
const { VmRunner } = await import('../lib/vm');
180-
const vPreProcess = await VmRunner.run(vCode, { req, ctx, utils, logger });
181+
const vPreProcess = await VmRunner.run(vCodeBrowser, { req, ctx, utils, logger });
181182
const vPostProcessingCallback = await vPreProcess();
182183
// support post-processing
183184
this.logger.debug(`Plugin [${vName}] has pre-processed!`);

src/interfaces/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Request, Context } from '../engine';
22

33
export type TestConditionalCallback = (data: string, ...args: any[]) => boolean | void;
44
export type PluginCallback = (req: Request, ctx: Context) => void | Promise<any> | PluginCallback;
5+
export type PluginWrapperCallback = () => PluginCallback;
56

67
/**
78
* Dialogue struct types

src/lib/vm.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Script } from 'vm';
2+
import { PluginWrapperCallback } from '../interfaces/types';
23

34
export class VmRunner {
45
runInVm(code: string, sandbox: any, path?: string) {
@@ -26,7 +27,7 @@ export class VmRunner {
2627
* @param sandbox
2728
* @returns
2829
*/
29-
static run(code: string, sandbox: any): () => void {
30+
static run(code: string, sandbox: any): PluginWrapperCallback {
3031
const script = new Script(code, { timeout: 5000 });
3132
const retValue = script.runInNewContext(sandbox);
3233
return retValue;

src/lib/vm2.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { NodeVM, VMScript } from 'vm2';
2+
import { PluginWrapperCallback } from '../interfaces/types';
23

34
export class VmRunner {
45
/**
@@ -23,7 +24,7 @@ export class VmRunner {
2324
* @param sandbox
2425
* @returns
2526
*/
26-
static run(code: string, sandbox: any): () => void {
27+
static run(code: string, sandbox: any): PluginWrapperCallback {
2728
const vm = new NodeVM({
2829
wrapper: 'none',
2930
sandbox,

src/plugins/built-in.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,23 @@ export function wrapCode(plugin: string): string {
6565
}
6666
})({req, ctx, utils, logger})`;
6767
}
68+
69+
/**
70+
* Extract plugin code & wrap it for Browser!
71+
* @param plugin
72+
* @returns
73+
*/
74+
export function wrapCodeBrowser(plugin: string): string {
75+
const vCode = plugin
76+
.replace(/```js([^`]*)```/, (m: string, code: string) => code)
77+
.replace(/~~~js([^~]*)~~~/, (m: string, code: string) => code);
78+
79+
return `
80+
() => (async ({req, ctx, utils, logger}) => {
81+
try {
82+
${vCode}
83+
} catch (error) {
84+
logger.error('Execute error!', error);
85+
}
86+
})({req, ctx, utils, logger})`;
87+
}

test/lib/vm.spec.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { expect } from 'chai';
2+
import { Context, Request } from '../../src/common';
3+
import { VmRunner as VmRunnerBrowser } from '../../src/lib/vm';
4+
import { VmRunner as VmRunnerNode } from '../../src/lib/vm2';
5+
import { wrapCode as wrapCodeNode, wrapCodeBrowser } from '../../src/plugins/built-in';
6+
import * as utils from '../../src/lib/utils';
7+
import { Logger } from '../../src/lib/logger';
8+
9+
describe('VmRunner', () => {
10+
11+
describe('VM for Browser', () => {
12+
it('should run the code', async () => {
13+
const vCode = wrapCodeBrowser(`logger.info('Ok'); return () => {req.message = 123}`);
14+
15+
const req = new Request();
16+
const ctx = new Context();
17+
const logger = new Logger('TESTER');
18+
const vPreProcess = await VmRunnerBrowser.run(vCode, { req, ctx, utils, logger });
19+
const vPostProcessingCallback = await vPreProcess();
20+
expect(vPreProcess).not.eq(undefined);
21+
expect(req.message).not.eq(123);
22+
23+
vPostProcessingCallback(req, ctx);
24+
expect(req.message).eq(123);
25+
});
26+
});
27+
28+
describe('VM for Node', () => {
29+
it('should run the code', async () => {
30+
const vCode = wrapCodeNode(`logger.info('Ok'); return () => {req.message = 123}`);
31+
32+
const req = new Request();
33+
const ctx = new Context();
34+
const logger = new Logger('TESTER');
35+
const vPreProcess = await VmRunnerNode.run(vCode, { req, ctx, utils, logger });
36+
const vPostProcessingCallback = await vPreProcess();
37+
expect(vPreProcess).not.eq(undefined);
38+
expect(req.message).not.eq(123);
39+
40+
vPostProcessingCallback(req, ctx);
41+
expect(req.message).eq(123);
42+
});
43+
});
44+
});

0 commit comments

Comments
 (0)