new(basic.gblib): API online for GB.

This commit is contained in:
Rodrigo Rodriguez 2024-01-16 23:32:04 -03:00
parent f520c69f3f
commit adac385b5a
13 changed files with 3168 additions and 164 deletions

14
api-template.json Normal file
View file

@ -0,0 +1,14 @@
{
"openapi": "3.0.0",
"info": {
"title": "General Bots API",
"description": "General Bots API description in Swagger format",
"version": "1.0"
},
"servers": [
{
"url": "https://gb.pragmatismo.com.br/api",
"description": "General Bots Online"
}
]
}

View file

@ -74,6 +74,7 @@
"@nosferatu500/textract": "3.1.2",
"@push-rpc/core": "1.8.2",
"@push-rpc/http": "1.8.2",
"@push-rpc/openapi": "^1.9.0",
"@push-rpc/websocket": "1.8.2",
"@semantic-release/changelog": "5.0.1",
"@semantic-release/exec": "5.0.0",
@ -176,6 +177,7 @@
"ssr-for-bots": "1.0.1-c",
"strict-password-generator": "1.1.2",
"swagger-client": "3.18.5",
"swagger-ui-dist": "^5.11.0",
"tabulator-tables": "5.4.2",
"tedious": "15.1.2",
"textract": "2.5.0",

View file

@ -43,96 +43,6 @@ import { CodeServices } from '../../gpt.gblib/services/CodeServices.js';
* Web Automation services of conversation to be called by BASIC.
*/
export class DebuggerService {
static systemVariables = [
'AggregateError',
'Array',
'ArrayBuffer',
'Atomics',
'BigInt',
'BigInt64Array',
'BigUint64Array',
'Boolean',
'DataView',
'Date',
'Error',
'EvalError',
'FinalizationRegistry',
'Float32Array',
'Float64Array',
'Function',
'Headers',
'Infinity',
'Int16Array',
'Int32Array',
'Int8Array',
'Intl',
'JSON',
'Map',
'Math',
'NaN',
'Number',
'Object',
'Promise',
'Proxy',
'RangeError',
'ReferenceError',
'Reflect',
'RegExp',
'Request',
'Response',
'Set',
'SharedArrayBuffer',
'String',
'Symbol',
'SyntaxError',
'TypeError',
'URIError',
'Uint16Array',
'Uint32Array',
'Uint8Array',
'Uint8ClampedArray',
'VM2_INTERNAL_STATE_DO_NOT_USE_OR_PROGRAM_WILL_FAIL',
'WeakMap',
'WeakRef',
'WeakSet',
'WebAssembly',
'__defineGetter__',
'__defineSetter__',
'__lookupGetter__',
'__lookupSetter__',
'__proto__',
'clearImmediate',
'clearInterval',
'clearTimeout',
'console',
'constructor',
'decodeURI',
'decodeURIComponent',
'dss',
'encodeURI',
'encodeURIComponent',
'escape',
'eval',
'fetch',
'global',
'globalThis',
'hasOwnProperty',
'isFinite',
'isNaN',
'isPrototypeOf',
'parseFloat',
'parseInt',
'process',
'propertyIsEnumerable',
'setImmediate',
'setInterval',
'setTimeout',
'toLocaleString',
'toString',
'undefined',
'unescape',
'valueOf'
];
public async setBreakpoint({ botId, line }) {
GBLog.info(`BASIC: Enabled breakpoint for ${botId} on ${line}.`);

View file

@ -994,7 +994,7 @@ export class DialogKeywords {
}
} else if (kind === 'file') {
GBLog.info(`BASIC (${min.botId}): Upload done for ${answer.filename}.`);
const handle = WebAutomationServices.cyrb53(min.botId + answer.filename);
const handle = WebAutomationServices.cyrb53({pid, str: min.botId + answer.filename});
GBServer.globals.files[handle] = answer;
result = handle;
} else if (kind === 'boolean') {
@ -1115,7 +1115,7 @@ export class DialogKeywords {
} else if (kind === 'qr-scanner') {
//https://github.com/GeneralBots/BotServer/issues/171
GBLog.info(`BASIC (${min.botId}): Upload done for ${answer.filename}.`);
const handle = WebAutomationServices.cyrb53(min.botId + answer.filename);
const handle = WebAutomationServices.cyrb53({pid, str: min.botId + answer.filename});
GBServer.globals.files[handle] = answer;
QrScanner.scanImage(GBServer.globals.files[handle])
.then(result => console.log(result))

View file

@ -81,6 +81,10 @@ import { GBUtil } from '../../../src/util.js';
* BASIC system class for extra manipulation of bot behaviour.
*/
export class SystemKeywords {
/**
* @tags System
*/
public async callVM({ pid, text }) {
const { min, user } = await DialogKeywords.getProcessInfo(pid);
const step = null;
@ -2104,7 +2108,7 @@ export class SystemKeywords {
}
private cachedMerge = {};
private cachedMerge:any = {};
/**
* Merges a multi-value with a tabular file using BY field as key.

View file

@ -37,11 +37,10 @@ import Fs from 'fs';
import Path from 'path';
import url from 'url';
import { GBLog, GBMinInstance } from 'botlib';
import { GBLog } from 'botlib';
import { GBServer } from '../../../src/app.js';
import { GBAdminService } from '../../admin.gbapp/services/GBAdminService.js';
import { GBSSR } from '../../core.gbapp/services/GBSSR.js';
import { GuaribasUser } from '../../security.gbapp/models/index.js';
import { DialogKeywords } from './DialogKeywords.js';
import { GBDeployer } from '../../core.gbapp/services/GBDeployer.js';
import { Mutex } from 'async-mutex';
@ -55,10 +54,8 @@ export class WebAutomationServices {
static isSelector(name: any) {
return name.startsWith('.') || name.startsWith('#') || name.startsWith('[');
}
private debugWeb: boolean;
private lastDebugWeb: Date;
public static cyrb53 = (str, seed = 0) => {
public static cyrb53 ({pid, str, seed = 0}) {
let h1 = 0xdeadbeef ^ seed,
h2 = 0x41c6ce57 ^ seed;
for (let i = 0, ch; i < str.length; i++) {
@ -152,7 +149,7 @@ export class WebAutomationServices {
if ((!session && sessionKind === 'AS') || !sessionName) {
// A new web session is being created.
handle = WebAutomationServices.cyrb53(min.botId + url);
handle = WebAutomationServices.cyrb53({pid, str:min.botId + url});
session = {};
session.sessionName = sessionName;
@ -269,18 +266,21 @@ export class WebAutomationServices {
private async debugStepWeb(pid, page) {
const { min, user } = await DialogKeywords.getProcessInfo(pid);
let debugWeb, lastDebugWeb; // TODO: Add this to pid bag.
let refresh = true;
if (this.lastDebugWeb) {
refresh = new Date().getTime() - this.lastDebugWeb.getTime() > 5000;
if (lastDebugWeb) {
refresh = new Date().getTime() - lastDebugWeb.getTime() > 5000;
}
if (this.debugWeb && refresh) {
if (debugWeb && refresh) {
const mobile = min.core.getParam(min.instance, 'Bot Admin Number', null);
const filename = page;
if (mobile) {
await new DialogKeywords().sendFileTo({ pid: pid, mobile, filename, caption: 'General Bots Debugger' });
}
this.lastDebugWeb = new Date();
lastDebugWeb = new Date();
}
}

View file

@ -27,6 +27,98 @@ const waitUntil = condition => {
});
};
const systemVariables = [
'AggregateError',
'Array',
'ArrayBuffer',
'Atomics',
'BigInt',
'BigInt64Array',
'BigUint64Array',
'Boolean',
'DataView',
'Date',
'Error',
'EvalError',
'FinalizationRegistry',
'Float32Array',
'Float64Array',
'Function',
'Headers',
'Infinity',
'Int16Array',
'Int32Array',
'Int8Array',
'Intl',
'JSON',
'Map',
'Math',
'NaN',
'Number',
'Object',
'Promise',
'Proxy',
'RangeError',
'ReferenceError',
'Reflect',
'RegExp',
'Request',
'Response',
'Set',
'SharedArrayBuffer',
'String',
'Symbol',
'SyntaxError',
'TypeError',
'URIError',
'Uint16Array',
'Uint32Array',
'Uint8Array',
'Uint8ClampedArray',
'VM2_INTERNAL_STATE_DO_NOT_USE_OR_PROGRAM_WILL_FAIL',
'WeakMap',
'WeakRef',
'WeakSet',
'WebAssembly',
'__defineGetter__',
'__defineSetter__',
'__lookupGetter__',
'__lookupSetter__',
'__proto__',
'clearImmediate',
'clearInterval',
'clearTimeout',
'console',
'constructor',
'decodeURI',
'decodeURIComponent',
'dss',
'encodeURI',
'encodeURIComponent',
'escape',
'eval',
'fetch',
'global',
'globalThis',
'hasOwnProperty',
'isFinite',
'isNaN',
'isPrototypeOf',
'parseFloat',
'parseInt',
'process',
'propertyIsEnumerable',
'setImmediate',
'setInterval',
'setTimeout',
'toLocaleString',
'toString',
'undefined',
'unescape',
'valueOf'
];
export const createVm2Pool = ({ min, max, ...limits }) => {
limits = Object.assign(
{
@ -112,7 +204,7 @@ export const createVm2Pool = ({ min, max, ...limits }) => {
let variablesText = '';
if (variables && variables.result) {
await CollectionUtil.asyncForEach(variables.result, async v => {
if (!DebuggerService.systemVariables.filter(x => x === v.name)[0]) {
if (!systemVariables.filter(x => x === v.name)[0]) {
if (v.value.value) {
variablesText = `${variablesText} \n ${v.name}: ${v.value.value}`;
}

View file

@ -1230,7 +1230,7 @@ export class GBMinService {
const t = new SystemKeywords();
GBLog.info(`BASIC (${min.botId}): Upload done for ${attachmentData.fileName}.`);
const handle = WebAutomationServices.cyrb53(min.botId + attachmentData.fileName);
const handle = WebAutomationServices.cyrb53({pid:0, str:min.botId + attachmentData.fileName});
let data = Fs.readFileSync(attachmentData.localPath);
const gbfile = {

14
src/api.ts Normal file
View file

@ -0,0 +1,14 @@
import { ImageProcessingServices } from '../packages/basic.gblib/services/ImageProcessingServices.js';
import { SystemKeywords } from '../packages/basic.gblib/services/SystemKeywords.js';
import { WebAutomationServices } from '../packages/basic.gblib/services/WebAutomationServices.js';
import { DialogKeywords } from '../packages/basic.gblib/services/DialogKeywords.js';
import { DebuggerService } from '../packages/basic.gblib/services/DebuggerService.js';
export interface GBAPI
{
systemKeywords: SystemKeywords;
dialogKeywords: DialogKeywords;
imageProcessing: ImageProcessingServices;
webAutomation: WebAutomationServices;
debuggerService: DebuggerService;
}

View file

@ -40,7 +40,9 @@ import https from 'https';
import http from 'http';
import mkdirp from 'mkdirp';
import Path from 'path';
import * as Fs from 'fs';
import swaggerUI from 'swagger-ui-dist';
import path from 'path';
import fs from 'fs';
import { GBLog, GBMinInstance, IGBCoreService, IGBInstance, IGBPackage } from 'botlib';
import { GBAdminService } from '../packages/admin.gbapp/services/GBAdminService.js';
import { AzureDeployerService } from '../packages/azuredeployer.gbapp/services/AzureDeployerService.js';
@ -84,6 +86,7 @@ export class GBServer {
}
const server = express();
this.initEndpointsDocs(server);
GBServer.globals.server = server;
GBServer.globals.httpsServer = null;
@ -120,7 +123,7 @@ export class GBServer {
process.env.PWD = process.cwd();
const workDir = Path.join(process.env.PWD, 'work');
if (!Fs.existsSync(workDir)) {
if (!fs.existsSync(workDir)) {
mkdirp.sync(workDir);
}
@ -299,7 +302,7 @@ export class GBServer {
if (process.env.CERTIFICATE_PFX) {
const options1 = {
passphrase: process.env.CERTIFICATE_PASSPHRASE,
pfx: Fs.readFileSync(process.env.CERTIFICATE_PFX)
pfx: fs.readFileSync(process.env.CERTIFICATE_PFX)
};
const httpsServer = https.createServer(options1, server).listen(port, mainCallback);
@ -313,7 +316,7 @@ export class GBServer {
if (process.env[certPfxEnv] && process.env[certPassphraseEnv] && process.env[certDomainEnv]) {
const options = {
passphrase: process.env[certPassphraseEnv],
pfx: Fs.readFileSync(process.env[certPfxEnv])
pfx: fs.readFileSync(process.env[certPfxEnv])
};
httpsServer.addContext(process.env[certDomainEnv], options);
} else {
@ -325,4 +328,25 @@ export class GBServer {
server.listen(port, mainCallback);
}
}
public static initEndpointsDocs(app: express.Application) {
const ENDPOINT = '/docs';
const SWAGGER_FILE_NAME = 'swagger.yaml';
const swaggerUiAssetPath = swaggerUI.getAbsoluteFSPath();
// A workaround for swagger-ui-dist not being able to set custom swagger URL
const indexContent = fs
.readFileSync(path.join(swaggerUiAssetPath, 'swagger-initializer.js'))
.toString()
.replace('https://petstore.swagger.io/v2/swagger.json', `/${SWAGGER_FILE_NAME}`);
app.get(`${ENDPOINT}/swagger-initializer.js`, (req, res) => res.send(indexContent));
// Serve the swagger-ui assets
app.use(ENDPOINT, express.static(swaggerUiAssetPath));
// Serve the swagger file
app.get(`/${SWAGGER_FILE_NAME}`, (req, res) => {
res.sendFile(path.join(process.env.PWD,SWAGGER_FILE_NAME));
});
}
}

View file

@ -1,54 +0,0 @@
{
"swagger": "2.0",
"info": {
"version": "3.0.0",
"title": "General Bots API",
"description": "General Bots API definitions.",
"contact": {
"name": "Pragmatismo",
"url": "https://gb.pragmatismo.com.br",
"email": "info@pragmatismo.com.br"
},
"x-ms-api-annotation": {
"status": "Production"
}
},
"host": "f993e4828c0d50.lhr.life",
"basePath": "/",
"schemes": [
"https"
],
"consumes": [],
"produces": [],
"paths": {
"/api/v2/dev-perdomo/dialog/talk": {
"post": {
"consumes":[
"text/plain; charset=utf-8"
],
"summary": "Talk to the user.",
"description": "Talk to the user.",
"x-ms-no-generic-test": true,
"operationId": "talk",
"responses": {
"200": {
"description": "OK"
}
}
}
}
},
"definitions": {
"TalkRequest": {
"type": "object",
"properties": {
"pid": {
"type": "string"
},
"text": {
"type": "string"
}
}
}
}
}

2956
swagger.yaml Normal file

File diff suppressed because it is too large Load diff

42
tsconfig.api.json Normal file
View file

@ -0,0 +1,42 @@
{
"compilerOptions": {
"strict": false,
"allowJs": true,
"downlevelIteration": true,
"baseUrl": "./",
"declaration": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"esModuleInterop": true,
"skipLibCheck": true,
"mapRoot": "./dist/",
"moduleResolution": "Node",
"module": "ESNext",
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"outDir": "./dist",
"paths": {
"*": [
"types/*"
],
"botlib/*": [
"node_modules/botlib/*"
],
"pragmatismo-io-framework/*": [
"node_modules/pragmatismo-io-framework/*"
]
},
"sourceMap": true,
"target": "ESNext",
"typeRoots": [
"node_modules/@types"
]
},
"include": [
"src/api.ts",
],
"exclude": [
"dist",
"node_modules"
]
}