From 3d63db806dd3761ce0e22482e9516ceff4e1c5b5 Mon Sep 17 00:00:00 2001 From: Anoop M D Date: Tue, 24 Jan 2023 19:34:06 +0530 Subject: [PATCH] feat: moved prepare request logic to electron --- .../providers/App/useCollectionTreeSync.js | 9 ++- .../ReduxStore/slices/collections/actions.js | 15 +--- .../ReduxStore/slices/collections/index.js | 4 +- packages/bruno-app/src/utils/network/index.js | 77 +------------------ .../src/ipc/{network.js => network/index.js} | 41 ++++++---- .../src/ipc/network/prepare-request.js | 69 +++++++++++++++++ 6 files changed, 111 insertions(+), 104 deletions(-) rename packages/bruno-electron/src/ipc/{network.js => network/index.js} (66%) create mode 100644 packages/bruno-electron/src/ipc/network/prepare-request.js diff --git a/packages/bruno-app/src/providers/App/useCollectionTreeSync.js b/packages/bruno-app/src/providers/App/useCollectionTreeSync.js index e408c7d01..34faf8cef 100644 --- a/packages/bruno-app/src/providers/App/useCollectionTreeSync.js +++ b/packages/bruno-app/src/providers/App/useCollectionTreeSync.js @@ -6,7 +6,8 @@ import { collectionChangeFileEvent, collectionUnlinkFileEvent, collectionUnlinkDirectoryEvent, - collectionUnlinkEnvFileEvent + collectionUnlinkEnvFileEvent, + requestSentEvent } from 'providers/ReduxStore/slices/collections'; import toast from 'react-hot-toast'; import { openCollectionEvent, collectionAddEnvFileEvent } from 'providers/ReduxStore/slices/collections/actions'; @@ -80,18 +81,24 @@ const useCollectionTreeSync = () => { toast.error(message || 'Something went wrong!'); }; + const _httpRequestSent = (val) => { + dispatch(requestSentEvent(val)); + }; + ipcRenderer.invoke('renderer:ready'); const removeListener1 = ipcRenderer.on('main:collection-opened', _openCollection); const removeListener2 = ipcRenderer.on('main:collection-tree-updated', _collectionTreeUpdated); 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); return () => { removeListener1(); removeListener2(); removeListener3(); removeListener4(); + removeListener5(); }; }, [isElectron]); }; diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js index f8053be87..67b27e2cc 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js @@ -25,7 +25,6 @@ import { saveCollectionToIdb } from 'utils/idb'; import { sendNetworkRequest, cancelNetworkRequest } from 'utils/network'; import { - requestSent, requestCancelled, responseReceived, newItem as _newItem, @@ -100,24 +99,12 @@ export const saveRequest = (itemUid, collectionUid) => (dispatch, getState) => { export const sendRequest = (item, collectionUid) => (dispatch, getState) => { const state = getState(); const collection = findCollectionByUid(state.collections.collections, collectionUid); - const cancelTokenUid = uuid(); return new Promise((resolve, reject) => { if (!collection) { return reject(new Error('Collection not found')); } - const onRequestSent = (req) => { - dispatch( - requestSent({ - requestSent: req, - itemUid: item.uid, - collectionUid: collectionUid, - cancelTokenUid: cancelTokenUid - }) - ); - }; - const itemCopy = cloneDeep(item); const collectionCopy = cloneDeep(collection); @@ -128,7 +115,7 @@ export const sendRequest = (item, collectionUid) => (dispatch, getState) => { } } - sendNetworkRequest(itemCopy, { cancelTokenUid: cancelTokenUid }, onRequestSent) + sendNetworkRequest(itemCopy, collectionUid) .then((response) => { return dispatch( responseReceived({ diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js index 382ba0288..80d25b9ad 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js @@ -147,7 +147,7 @@ export const collectionsSlice = createSlice({ } } }, - requestSent: (state, action) => { + requestSentEvent: (state, action) => { const { itemUid, collectionUid, cancelTokenUid, requestSent } = action.payload; const collection = findCollectionByUid(state.collections, collectionUid); @@ -795,7 +795,7 @@ export const { deleteItem, renameItem, cloneItem, - requestSent, + requestSentEvent, requestCancelled, responseReceived, saveRequest, diff --git a/packages/bruno-app/src/utils/network/index.js b/packages/bruno-app/src/utils/network/index.js index c46876f57..d8c989fda 100644 --- a/packages/bruno-app/src/utils/network/index.js +++ b/packages/bruno-app/src/utils/network/index.js @@ -1,13 +1,8 @@ -import get from 'lodash/get'; -import each from 'lodash/each'; -import filter from 'lodash/filter'; -import qs from 'qs'; - -export const sendNetworkRequest = async (item, options, onRequestSent) => { +export const sendNetworkRequest = async (item, collectionUid) => { return new Promise((resolve, reject) => { if (['http-request', 'graphql-request'].includes(item.type)) { const timeStart = Date.now(); - sendHttpRequest(item.draft ? item.draft.request : item.request, options, onRequestSent) + sendHttpRequest(item, collectionUid) .then((response) => { const timeEnd = Date.now(); resolve({ @@ -25,76 +20,12 @@ export const sendNetworkRequest = async (item, options, onRequestSent) => { }); }; -const sendHttpRequest = async (request, options, onRequestSent) => { +const sendHttpRequest = async (item, collectionUid) => { return new Promise((resolve, reject) => { const { ipcRenderer } = window; - const headers = {}; - each(request.headers, (h) => { - if (h.enabled) { - headers[h.name] = h.value; - } - }); - - let axiosRequest = { - method: request.method, - url: request.url, - headers: headers - }; - - if (request.body.mode === 'json') { - axiosRequest.headers['content-type'] = 'application/json'; - try { - axiosRequest.data = JSON.parse(request.body.json); - } catch (ex) { - axiosRequest.data = request.body.json; - } - } - - if (request.body.mode === 'text') { - axiosRequest.headers['content-type'] = 'text/plain'; - axiosRequest.data = request.body.text; - } - - if (request.body.mode === 'xml') { - axiosRequest.headers['content-type'] = 'text/xml'; - axiosRequest.data = request.body.xml; - } - - if (request.body.mode === 'formUrlEncoded') { - axiosRequest.headers['content-type'] = 'application/x-www-form-urlencoded'; - const params = {}; - const enabledParams = filter(request.body.formUrlEncoded, (p) => p.enabled); - each(enabledParams, (p) => (params[p.name] = p.value)); - axiosRequest.data = qs.stringify(params); - } - - if (request.body.mode === 'multipartForm') { - const params = {}; - const enabledParams = filter(request.body.multipartForm, (p) => p.enabled); - each(enabledParams, (p) => (params[p.name] = p.value)); - axiosRequest.headers['content-type'] = 'multipart/form-data'; - axiosRequest.data = params; - } - - if (request.body.mode === 'graphql') { - const graphqlQuery = { - query: get(request, 'body.graphql.query'), - variables: JSON.parse(get(request, 'body.graphql.variables') || '{}') - }; - axiosRequest.headers['content-type'] = 'application/json'; - axiosRequest.data = graphqlQuery; - } - - if (request.script && request.script.length) { - axiosRequest.script = request.script; - } - console.log(axiosRequest); - - onRequestSent(axiosRequest); - ipcRenderer - .invoke('send-http-request', axiosRequest, options) + .invoke('send-http-request', item, collectionUid) .then(resolve) .catch(reject); }); diff --git a/packages/bruno-electron/src/ipc/network.js b/packages/bruno-electron/src/ipc/network/index.js similarity index 66% rename from packages/bruno-electron/src/ipc/network.js rename to packages/bruno-electron/src/ipc/network/index.js index 761c4aa6c..98409472b 100644 --- a/packages/bruno-electron/src/ipc/network.js +++ b/packages/bruno-electron/src/ipc/network/index.js @@ -3,12 +3,19 @@ const FormData = require('form-data'); const { ipcMain } = require('electron'); const { forOwn, extend } = require('lodash'); const { ScriptRuntime } = require('@usebruno/js'); -const { cancelTokens, saveCancelToken, deleteCancelToken } = require('../utils/cancel-token'); +const prepareRequest = require('./prepare-request'); +const { cancelTokens, saveCancelToken, deleteCancelToken } = require('../../utils/cancel-token'); +const { uuid } = require('../../utils/common'); -const registerNetworkIpc = () => { +const registerNetworkIpc = (mainWindow, watcher, lastOpenedCollections) => { // handler for sending http request - ipcMain.handle('send-http-request', async (event, request, options) => { + ipcMain.handle('send-http-request', async (event, item, collectionUid) => { + const cancelTokenUid = uuid(); + try { + const _request = item.draft ? item.draft.request : item.request; + const request = prepareRequest(_request); + // make axios work in node using form data // reference: https://github.com/axios/axios/issues/1006#issuecomment-320165427 if(request.headers && request.headers['content-type'] === 'multipart/form-data') { @@ -20,11 +27,9 @@ const registerNetworkIpc = () => { request.data = form; } - if(options && options.cancelTokenUid) { - const cancelToken = axios.CancelToken.source(); - request.cancelToken = cancelToken.token; - saveCancelToken(options.cancelTokenUid, cancelToken); - } + const cancelToken = axios.CancelToken.source(); + request.cancelToken = cancelToken.token; + saveCancelToken(cancelTokenUid, cancelToken); if(request.script && request.script.length) { request.script = request.script += '\n onRequest(brunoRequest);'; @@ -32,11 +37,21 @@ const registerNetworkIpc = () => { scriptRuntime.run(request.script, request); } + mainWindow.webContents.send('main:http-request-sent', { + requestSent: { + url: request.url, + method: request.method, + headers: request.headers, + data: request.data + }, + collectionUid, + itemUid: item.uid, + cancelTokenUid + }); + const result = await axios(request); - if(options && options.cancelTokenUid) { - deleteCancelToken(options.cancelTokenUid); - } + deleteCancelToken(cancelTokenUid); return { status: result.status, @@ -45,9 +60,7 @@ const registerNetworkIpc = () => { data: result.data }; } catch (error) { - if(options && options.cancelTokenUid) { - deleteCancelToken(options.cancelTokenUid); - } + deleteCancelToken(cancelTokenUid); if(error.response) { return { diff --git a/packages/bruno-electron/src/ipc/network/prepare-request.js b/packages/bruno-electron/src/ipc/network/prepare-request.js new file mode 100644 index 000000000..778f89469 --- /dev/null +++ b/packages/bruno-electron/src/ipc/network/prepare-request.js @@ -0,0 +1,69 @@ +const { get, each, filter } = require('lodash'); +const qs = require('qs'); + +const prepareRequest = (request) => { + const headers = {}; + each(request.headers, (h) => { + if (h.enabled) { + headers[h.name] = h.value; + } + }); + + let axiosRequest = { + method: request.method, + url: request.url, + headers: headers + }; + + if (request.body.mode === 'json') { + axiosRequest.headers['content-type'] = 'application/json'; + try { + axiosRequest.data = JSON.parse(request.body.json); + } catch (ex) { + axiosRequest.data = request.body.json; + } + } + + if (request.body.mode === 'text') { + axiosRequest.headers['content-type'] = 'text/plain'; + axiosRequest.data = request.body.text; + } + + if (request.body.mode === 'xml') { + axiosRequest.headers['content-type'] = 'text/xml'; + axiosRequest.data = request.body.xml; + } + + if (request.body.mode === 'formUrlEncoded') { + axiosRequest.headers['content-type'] = 'application/x-www-form-urlencoded'; + const params = {}; + const enabledParams = filter(request.body.formUrlEncoded, (p) => p.enabled); + each(enabledParams, (p) => (params[p.name] = p.value)); + axiosRequest.data = qs.stringify(params); + } + + if (request.body.mode === 'multipartForm') { + const params = {}; + const enabledParams = filter(request.body.multipartForm, (p) => p.enabled); + each(enabledParams, (p) => (params[p.name] = p.value)); + axiosRequest.headers['content-type'] = 'multipart/form-data'; + axiosRequest.data = params; + } + + if (request.body.mode === 'graphql') { + const graphqlQuery = { + query: get(request, 'body.graphql.query'), + variables: JSON.parse(get(request, 'body.graphql.variables') || '{}') + }; + axiosRequest.headers['content-type'] = 'application/json'; + axiosRequest.data = graphqlQuery; + } + + if (request.script && request.script.length) { + axiosRequest.script = request.script; + } + + return axiosRequest; +}; + +module.exports = prepareRequest;