diff --git a/package-lock.json b/package-lock.json index ce30a336..3a5b096f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "botserver", - "version": "2.0.178", + "version": "3.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "botserver", - "version": "2.0.178", + "version": "3.0.0", "license": "AGPL-3.0", "dependencies": { "@azure/cognitiveservices-computervision": "8.1.0", @@ -59,6 +59,8 @@ "google-libphonenumber": "3.2.21", "googleapis": "75.0.0", "ibm-watson": "6.1.1", + "indent": "^0.0.2", + "indent.js": "^0.3.5", "js-beautify": "1.13.13", "keyv": "^4.5.0", "koa": "^2.13.4", @@ -16295,6 +16297,11 @@ "node": ">=0.8.19" } }, + "node_modules/indent": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/indent/-/indent-0.0.2.tgz", + "integrity": "sha512-/F1w9/msSQCfXDTvEU8rKBObcv4cBN6m8hujC/zwVc8vOuf4b76AwBVGChbg+3o0M3kp1XDjoMDQR5Nh6SAHfA==" + }, "node_modules/indent-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", @@ -16303,6 +16310,11 @@ "node": ">=8" } }, + "node_modules/indent.js": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/indent.js/-/indent.js-0.3.5.tgz", + "integrity": "sha512-wiTA5fEz0kc8tHzY6CSujl/k62WVNvTxAZzmPe5V7MYxRCeGGibPCIYWYBzPp/bcJh3CXUO/8qrTrO/x9s1i2Q==" + }, "node_modules/indexes-of": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", @@ -47128,11 +47140,21 @@ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==" }, + "indent": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/indent/-/indent-0.0.2.tgz", + "integrity": "sha512-/F1w9/msSQCfXDTvEU8rKBObcv4cBN6m8hujC/zwVc8vOuf4b76AwBVGChbg+3o0M3kp1XDjoMDQR5Nh6SAHfA==" + }, "indent-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" }, + "indent.js": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/indent.js/-/indent.js-0.3.5.tgz", + "integrity": "sha512-wiTA5fEz0kc8tHzY6CSujl/k62WVNvTxAZzmPe5V7MYxRCeGGibPCIYWYBzPp/bcJh3CXUO/8qrTrO/x9s1i2Q==" + }, "indexes-of": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", diff --git a/package.json b/package.json index 7e91358f..4a2d1c76 100644 --- a/package.json +++ b/package.json @@ -99,6 +99,7 @@ "google-libphonenumber": "3.2.21", "googleapis": "75.0.0", "ibm-watson": "6.1.1", + "indent.js": "^0.3.5", "js-beautify": "1.13.13", "keyv": "^4.5.0", "koa": "^2.13.4", diff --git a/packages/basic.gblib/index.ts b/packages/basic.gblib/index.ts index fd8a38fa..ffa08683 100644 --- a/packages/basic.gblib/index.ts +++ b/packages/basic.gblib/index.ts @@ -45,6 +45,7 @@ const Koa = require('koa'); import * as koaBody from "koa-body" import { SystemKeywords } from './services/SystemKeywords'; import { WebAutomationKeywords } from './services/WebAutomationKeywords'; +import { DebuggerService } from './services/DebuggerService'; const app = new Koa() /** @@ -80,14 +81,17 @@ export class GBBasicPackage implements IGBPackage { public async loadBot(min: GBMinInstance): Promise { const dk = new DialogKeywords(min, null, null); const wa = new WebAutomationKeywords(min, null, dk); - const sys = new SystemKeywords(min, null, dk, wa) + const sys = new SystemKeywords(min, null, dk, wa); + const dbg = new DebuggerService(min, null, dk); dk.wa = wa; wa.sys = sys; const dialogRouter = createServerRouter(`/api/v2/${min.botId}/dialog`, dk); const waRouter = createServerRouter(`/api/v2/${min.botId}/webautomation`, wa ); const sysRouter = createServerRouter(`/api/v2/${min.botId}/system`, sys); + const dbgRouter = createServerRouter(`/api/v2/${min.botId}/debugger`, dbg); app.use(dialogRouter.routes()); app.use(sysRouter.routes()); app.use(waRouter.routes()); + app.use(dbgRouter.routes()); } } diff --git a/packages/basic.gblib/services/DebuggerService.ts b/packages/basic.gblib/services/DebuggerService.ts index 15337fe6..290f77f7 100644 --- a/packages/basic.gblib/services/DebuggerService.ts +++ b/packages/basic.gblib/services/DebuggerService.ts @@ -89,7 +89,10 @@ export class DebuggerService { */ maxLines: number = 2000; - pageMap = {}; + debugMap = {}; + conversationsMap = {}; + scopeMap = {}; + watermarkMap = {}; /** * When creating this keyword facade,a bot instance is @@ -109,7 +112,7 @@ export class DebuggerService { private client; - public async setBreakPoint({ botId, botApiKey, line }) { + public async setBreakpoint({ botId, botApiKey, line }) { const client = GBServer.globals.debuggers[botId]; @@ -126,7 +129,7 @@ export class DebuggerService { const { breakpointId } = await await client.Debugger.setBreakpoint({ location: { scriptId, - lineNumber: 6 - 1 // (zero-based) + lineNumber: line - 1 } }); } @@ -135,37 +138,64 @@ export class DebuggerService { } - public async continue({ botId, botApiKey, force }) { + public async continueRun({ botId, botApiKey, force }) { const client = GBServer.globals.debuggers[botId]; client.Debugger.resume(); } - public async stopDebug({ botId, botApiKey, force }) { + public async stop({ botId, botApiKey, force }) { const client = GBServer.globals.debuggers[botId]; client.close(); } - public async stepOver({ botId, botApiKey, force }) { + public async stepOver({ botId, botApiKey }) { const client = GBServer.globals.debuggers[botId]; client.stepOver(); } + public async getExecutionContext({ botId, botApiKey, force }) { + + const client = GBServer.globals.debuggers[botId]; + const conversationId = this.conversationsMap[botId]; - public async startDebug({ botId, botApiKey, scriptName }) { + const response = await client.Conversations.Conversations_GetActivities({ + conversationId: conversationId, + watermark: this.watermarkMap[botId] + }); + this.watermarkMap[botId] = response.obj.watermark; + let activities = response.obj.activites; + let messages = []; + if (activities && activities.length) { + activities = activities.filter(m => m.from.id === botId && m.type === 'message'); + if (activities.length) { + activities.forEach(activity => { + messages.push({ text: activity.text }); + GBLog.info(`GBDEBUG: SND TO WORD ${activity.text}`); + }); + } + } + return { state:this.debugMap[botId].state, messages, scope: this.scopeMap[botId] }; + } - // TODO : Map this. - let webchatKey = null; + public async run({ botId, botApiKey, scriptName }) { + + this.debugMap[botId] = { state: 1 }; + + let min: GBMinInstance = GBServer.globals.minInstances.filter( + p => p.instance.botId === botId + )[0]; this.client = await new Swagger({ spec: JSON.parse(fs.readFileSync('directline-3.0.json', 'utf8')), usePromise: true }); this.client.clientAuthorizations.add( 'AuthorizationBotConnector', - new Swagger.ApiKeyAuthorization('Authorization', `Bearer ${webchatKey}`, 'header') + new Swagger.ApiKeyAuthorization('Authorization', `Bearer ${min.instance.webchatKey}`, 'header') ); const response = await this.client.Conversations.Conversations_StartConversation(); const conversationId = response.obj.conversationId; + this.conversationsMap[botId] = conversationId; GBServer.globals.debugConversationId = conversationId; this.client.Conversations.Conversations_PostActivity({ @@ -184,21 +214,24 @@ export class DebuggerService { // Setup debugger. const client = GBServer.globals.debuggers[botId]; - + client.Debugger.paused(({ callFrames, reason, hitBreakpoints }) => { - if (hitBreakpoints.length>1) - { - GBLog.info(`.gbdialog break at line ${callFrames[0].location.lineNumber + 1}`); // (zero-based) + const frame = callFrames[0]; + if (hitBreakpoints.length > 1) { + GBLog.info(`.gbdialog break at line ${frame.location.lineNumber + 1}`); // (zero-based) + + const scope = `${frame.scopeChain[0].name} ${frame.scopeChain[0].object}`; + + this.scopeMap[botId] = scope; } - else (reason === ''){ - GBLog.info(`.gbdialog ${reason} at line ${callFrames[0].location.lineNumber + 1}`); // (zero-based) + else if (reason === ''){ + GBLog.info(`.gbdialog ${reason} at line ${frame.location.lineNumber + 1}`); // (zero-based) } }); - + await client.Runtime.runIfWaitingForDebugger(); await client.Debugger.enable(); await client.Debugger.setPauseOnExceptions('all'); - } } \ No newline at end of file diff --git a/packages/basic.gblib/services/GBVMService.ts b/packages/basic.gblib/services/GBVMService.ts index 7d182fb7..86174b35 100644 --- a/packages/basic.gblib/services/GBVMService.ts +++ b/packages/basic.gblib/services/GBVMService.ts @@ -49,7 +49,7 @@ const textract = require('textract'); const walkPromise = require('walk-promise'); const child_process = require('child_process'); const Path = require('path'); - +const indent = require('indent.js'); /** * @fileoverview Decision was to priorize security(isolation) and debugging, * over a beautiful BASIC transpiler (to be done). @@ -200,9 +200,12 @@ export class GBVMService extends GBService { } } while (include); - const vbsCode = await this.convertGBASICToVBS(min, basicCode); + const [vbsCode, jsonMap] = await this.convertGBASICToVBS(min, basicCode); const vbsFile = `${filename}.compiled`; + const mapFile = `${filename}.map`; + fs.writeFileSync(vbsFile, vbsCode); + fs.writeFileSync(mapFile, JSON.stringify(jsonMap)); // Converts VBS into TS. @@ -226,7 +229,6 @@ export class GBVMService extends GBService { code.replace(/^.*exports.*$/gm, ''); code = ` - return (async () => { require('isomorphic-fetch'); const rest = require ('typescript-rest-rpc/lib/client'); @@ -272,14 +274,10 @@ export class GBVMService extends GBService { })(); `; - // Finds all hear calls. - - const parsedCode = beautify(code, { indent_size: 2, space_in_empty_paren: true, preserve_newlines: true, wrap_line_length: 240 }); - fs.writeFileSync(jsfile, parsedCode); - - min.sandBoxMap[mainName.toLowerCase().trim()] = parsedCode; - - GBLog.info(`[GBVMService] Finished loading of ${filename}, JavaScript from Word: \n ${parsedCode}`); + code = indent.js(code, {tabString: '\t'}); + fs.writeFileSync(jsfile, code); + min.sandBoxMap[mainName.toLowerCase().trim()] = code; + GBLog.info(`[GBVMService] Finished loading of ${filename}, JavaScript from Word: \n ${code}`); } } @@ -363,22 +361,24 @@ export class GBVMService extends GBService { `; - var matchingLines = []; var allLines = code.split("\n"); + const keywords = this.getKeywords(); + const offset = 37; + const jsonMap = {}; for (var i = 0; i < allLines.length; i++) { - if (allLines[i].match(pattern)) { - matchingLines.push(i); + for (var j = 0; j < keywords.length; j++) { + allLines[i] = allLines[i].replace(keywords[j][0], keywords[j][1]); + + // Add additional lines returned from replacement. + + let add = allLines[i].split(/\r\n|\r|\n/).length; + jsonMap[i] = (offset + i) + (add ? add : 0); } } - return matchingLines; - - - - code = `${code}\n%>`; - - return code; + code = `${allLines.join('\n')}\n%>`; + return [code, jsonMap]; } private getKeywords() { @@ -513,7 +513,7 @@ export class GBVMService extends GBService { }]; keywords[i++] = [/^\s*(wait)\s*(\d+)/gim, ($0, $1, $2) => { - return `await sys.wait({seconds:${$2})`; + return `await sys.wait({seconds:${$2}})`; }]; keywords[i++] = [/^\s*(get stock for )(.*)/gim, ($0, $1, $2) => {