mirror of
https://github.com/usebruno/bruno.git
synced 2024-11-25 17:33:28 +01:00
feat: scripting support almost done
This commit is contained in:
parent
4a403a253e
commit
b1d2b798ba
@ -7,7 +7,8 @@ import {
|
||||
collectionUnlinkFileEvent,
|
||||
collectionUnlinkDirectoryEvent,
|
||||
collectionUnlinkEnvFileEvent,
|
||||
requestSentEvent
|
||||
requestSentEvent,
|
||||
scriptEnvironmentUpdateEvent
|
||||
} from 'providers/ReduxStore/slices/collections';
|
||||
import toast from 'react-hot-toast';
|
||||
import { openCollectionEvent, collectionAddEnvFileEvent } from 'providers/ReduxStore/slices/collections/actions';
|
||||
@ -85,6 +86,10 @@ const useCollectionTreeSync = () => {
|
||||
dispatch(requestSentEvent(val));
|
||||
};
|
||||
|
||||
const _scriptEnvironmentUpdate = (val) => {
|
||||
dispatch(scriptEnvironmentUpdateEvent(val));
|
||||
};
|
||||
|
||||
ipcRenderer.invoke('renderer:ready');
|
||||
|
||||
const removeListener1 = ipcRenderer.on('main:collection-opened', _openCollection);
|
||||
@ -92,6 +97,7 @@ const useCollectionTreeSync = () => {
|
||||
const removeListener3 = ipcRenderer.on('main:collection-already-opened', _collectionAlreadyOpened);
|
||||
const removeListener4 = ipcRenderer.on('main:display-error', _displayError);
|
||||
const removeListener5 = ipcRenderer.on('main:http-request-sent', _httpRequestSent);
|
||||
const removeListener6 = ipcRenderer.on('main:script-environment-update', _scriptEnvironmentUpdate);
|
||||
|
||||
return () => {
|
||||
removeListener1();
|
||||
@ -99,6 +105,7 @@ const useCollectionTreeSync = () => {
|
||||
removeListener3();
|
||||
removeListener4();
|
||||
removeListener5();
|
||||
removeListener6();
|
||||
};
|
||||
}, [isElectron]);
|
||||
};
|
||||
|
@ -2,6 +2,7 @@ import path from 'path';
|
||||
import { uuid } from 'utils/common';
|
||||
import find from 'lodash/find';
|
||||
import map from 'lodash/map';
|
||||
import forOwn from 'lodash/forOwn';
|
||||
import concat from 'lodash/concat';
|
||||
import filter from 'lodash/filter';
|
||||
import each from 'lodash/each';
|
||||
@ -161,6 +162,25 @@ export const collectionsSlice = createSlice({
|
||||
}
|
||||
}
|
||||
},
|
||||
scriptEnvironmentUpdateEvent: (state, action) => {
|
||||
const { collectionUid, environment } = action.payload;
|
||||
const collection = findCollectionByUid(state.collections, collectionUid);
|
||||
|
||||
if (collection) {
|
||||
const activeEnvironmentUid = collection.activeEnvironmentUid;
|
||||
const activeEnvironment = findEnvironmentInCollection(collection, activeEnvironmentUid);
|
||||
|
||||
if (activeEnvironment) {
|
||||
forOwn(environment, (value, key) => {
|
||||
const variable = find(activeEnvironment.variables, (v) => v.name === key);
|
||||
|
||||
if (variable) {
|
||||
variable.value = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
requestCancelled: (state, action) => {
|
||||
const { itemUid, collectionUid } = action.payload;
|
||||
const collection = findCollectionByUid(state.collections, collectionUid);
|
||||
@ -796,6 +816,7 @@ export const {
|
||||
renameItem,
|
||||
cloneItem,
|
||||
requestSentEvent,
|
||||
scriptEnvironmentUpdateEvent,
|
||||
requestCancelled,
|
||||
responseReceived,
|
||||
saveRequest,
|
||||
|
@ -1,13 +1,35 @@
|
||||
const axios = require('axios');
|
||||
const Mustache = require('mustache');
|
||||
const FormData = require('form-data');
|
||||
const { ipcMain } = require('electron');
|
||||
const { forOwn, extend } = require('lodash');
|
||||
const { forOwn, extend, each } = require('lodash');
|
||||
const { ScriptRuntime } = require('@usebruno/js');
|
||||
const prepareRequest = require('./prepare-request');
|
||||
const { cancelTokens, saveCancelToken, deleteCancelToken } = require('../../utils/cancel-token');
|
||||
const { uuid } = require('../../utils/common');
|
||||
const interpolateVars = require('./interpolate-vars');
|
||||
|
||||
// override the default escape function to prevent escaping
|
||||
Mustache.escape = function (value) {
|
||||
return value;
|
||||
};
|
||||
|
||||
const getEnvVars = (environment = {}) => {
|
||||
const variables = environment.variables;
|
||||
if (!variables || !variables.length) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const envVars = {};
|
||||
each(variables, (variable) => {
|
||||
if(variable.enabled) {
|
||||
envVars[variable.name] = Mustache.escape(variable.value);
|
||||
}
|
||||
});
|
||||
|
||||
return envVars;
|
||||
};
|
||||
|
||||
const registerNetworkIpc = (mainWindow, watcher, lastOpenedCollections) => {
|
||||
// handler for sending http request
|
||||
ipcMain.handle('send-http-request', async (event, item, collectionUid, environment) => {
|
||||
@ -15,7 +37,7 @@ const registerNetworkIpc = (mainWindow, watcher, lastOpenedCollections) => {
|
||||
|
||||
try {
|
||||
const _request = item.draft ? item.draft.request : item.request;
|
||||
const request = prepareRequest(_request, environment);
|
||||
const request = prepareRequest(_request);
|
||||
|
||||
// make axios work in node using form data
|
||||
// reference: https://github.com/axios/axios/issues/1006#issuecomment-320165427
|
||||
@ -32,10 +54,17 @@ const registerNetworkIpc = (mainWindow, watcher, lastOpenedCollections) => {
|
||||
request.cancelToken = cancelToken.token;
|
||||
saveCancelToken(cancelTokenUid, cancelToken);
|
||||
|
||||
const envVars = getEnvVars(environment);
|
||||
|
||||
if(request.script && request.script.length) {
|
||||
request.script = request.script += '\n onRequest(brunoRequest);';
|
||||
let script = request.script + '\n if (typeof onRequest === "function") {onRequest(brunoRequest);}';
|
||||
const scriptRuntime = new ScriptRuntime();
|
||||
scriptRuntime.run(request.script, request, environment);
|
||||
const res = scriptRuntime.runRequestScript(script, request, envVars);
|
||||
|
||||
mainWindow.webContents.send('main:script-environment-update', {
|
||||
environment: res.environment,
|
||||
collectionUid
|
||||
});
|
||||
}
|
||||
|
||||
mainWindow.webContents.send('main:http-request-sent', {
|
||||
@ -50,10 +79,21 @@ const registerNetworkIpc = (mainWindow, watcher, lastOpenedCollections) => {
|
||||
cancelTokenUid
|
||||
});
|
||||
|
||||
interpolateVars(request, environment);
|
||||
interpolateVars(request, envVars);
|
||||
|
||||
const result = await axios(request);
|
||||
|
||||
if(request.script && request.script.length) {
|
||||
let script = request.script + '\n if (typeof onResponse === "function") {onResponse(brunoResponse);}';
|
||||
const scriptRuntime = new ScriptRuntime();
|
||||
const res = scriptRuntime.runResponseScript(script, result, envVars);
|
||||
|
||||
mainWindow.webContents.send('main:script-environment-update', {
|
||||
environment: res.environment,
|
||||
collectionUid
|
||||
});
|
||||
}
|
||||
|
||||
deleteCancelToken(cancelTokenUid);
|
||||
|
||||
return {
|
||||
|
@ -6,21 +6,7 @@ Mustache.escape = function (value) {
|
||||
return value;
|
||||
};
|
||||
|
||||
const interpolateVars = (request, environment) => {
|
||||
if(!environment) {
|
||||
return request;
|
||||
}
|
||||
|
||||
const variables = environment.variables;
|
||||
if(!variables || !variables.length) {
|
||||
return request;
|
||||
}
|
||||
|
||||
const envVars = {};
|
||||
each(variables, (variable) => {
|
||||
envVars[variable.name] = Mustache.escape(variable.value);
|
||||
});
|
||||
|
||||
const interpolateVars = (request, envVars = {}) => {
|
||||
const interpolate = (str) => {
|
||||
if(!str || !str.length || typeof str !== "string") {
|
||||
return str;
|
||||
|
@ -1,7 +1,7 @@
|
||||
const { get, each, filter } = require('lodash');
|
||||
const qs = require('qs');
|
||||
|
||||
const prepareRequest = (request, environment) => {
|
||||
const prepareRequest = (request) => {
|
||||
const headers = {};
|
||||
each(request.headers, (h) => {
|
||||
if (h.enabled) {
|
||||
|
@ -3,7 +3,21 @@ class Bru {
|
||||
this._environment = environment;
|
||||
}
|
||||
|
||||
setVar(key, value) {
|
||||
getEnvVar(key) {
|
||||
return this._environment[key];
|
||||
}
|
||||
|
||||
setEnvVar(key, value) {
|
||||
if(!key) {
|
||||
throw new Error('Key is required');
|
||||
}
|
||||
|
||||
// gracefully ignore if key is not present in environment
|
||||
if(!this._environment.hasOwnProperty(key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._environment[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
23
packages/bruno-js/src/scripts/bruno-response.js
Normal file
23
packages/bruno-js/src/scripts/bruno-response.js
Normal file
@ -0,0 +1,23 @@
|
||||
class BrunoResponse {
|
||||
constructor(response) {
|
||||
this._response = response;
|
||||
}
|
||||
|
||||
getStatus() {
|
||||
return this._response.status;
|
||||
}
|
||||
|
||||
getHeader(name) {
|
||||
return this._response.header[name];
|
||||
}
|
||||
|
||||
getHeaders() {
|
||||
return this._response.headers;
|
||||
}
|
||||
|
||||
getData() {
|
||||
return this._response.data;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BrunoResponse;
|
@ -1,12 +1,13 @@
|
||||
const { NodeVM } = require('vm2');
|
||||
const Bru = require('./bru');
|
||||
const BrunoRequest = require('./bruno-request');
|
||||
const BrunoResponse = require('./bruno-response');
|
||||
|
||||
class ScriptRuntime {
|
||||
constructor() {
|
||||
}
|
||||
|
||||
run(script, request, environment) {
|
||||
runRequestScript(script, request, environment) {
|
||||
const bru = new Bru(environment);
|
||||
const brunoRequest = new BrunoRequest(request);
|
||||
|
||||
@ -20,7 +21,30 @@ class ScriptRuntime {
|
||||
|
||||
vm.run(script);
|
||||
|
||||
return request;
|
||||
return {
|
||||
request,
|
||||
environment
|
||||
};
|
||||
}
|
||||
|
||||
runResponseScript(script, response, environment) {
|
||||
const bru = new Bru(environment);
|
||||
const brunoResponse = new BrunoResponse(response);
|
||||
|
||||
const context = {
|
||||
bru,
|
||||
brunoResponse
|
||||
};
|
||||
const vm = new NodeVM({
|
||||
sandbox: context
|
||||
});
|
||||
|
||||
vm.run(script);
|
||||
|
||||
return {
|
||||
response,
|
||||
environment
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user