Skip to content

Commit e2e18ed

Browse files
committed
Send http requests via main proess for graph run
1 parent 3b91b7c commit e2e18ed

File tree

4 files changed

+104
-60
lines changed

4 files changed

+104
-60
lines changed

packages/flowtest-electron/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
},
1717
"dependencies": {
1818
"@apidevtools/swagger-parser": "^10.1.0",
19+
"axios": "^1.6.7",
1920
"chokidar": "^3.6.0",
2021
"dotenv": "^16.4.5",
2122
"electron-store": "^8.1.0",

packages/flowtest-electron/src/ipc/collection.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const fs = require('fs');
22
const path = require('path');
3+
const axios = require('axios');
34
const { ipcMain, shell, dialog, app } = require('electron');
45
const SwaggerParser = require('@apidevtools/swagger-parser');
56
const JsonRefs = require('json-refs');
@@ -17,6 +18,22 @@ const readFile = require('../utils/filemanager/readfile');
1718

1819
const collectionStore = new Collections();
1920

21+
const timeout = 60000;
22+
23+
const newAbortSignal = () => {
24+
const abortController = new AbortController();
25+
setTimeout(() => abortController.abort(), timeout || 0);
26+
27+
return abortController.signal;
28+
};
29+
30+
/** web platform: blob. */
31+
const convertBase64ToBlob = async (base64) => {
32+
const response = await fetch(base64);
33+
const blob = await response.blob();
34+
return blob;
35+
};
36+
2037
const registerRendererEventHandlers = (mainWindow, watcher) => {
2138
ipcMain.handle('renderer:open-directory-selection-dialog', async (event, arg) => {
2239
try {
@@ -189,6 +206,47 @@ const registerRendererEventHandlers = (mainWindow, watcher) => {
189206
return Promise.reject(error);
190207
}
191208
});
209+
210+
ipcMain.handle('renderer:run-http-request', async (event, request) => {
211+
try {
212+
if (request.headers['Content-type'] === 'multipart/form-data') {
213+
const requestData = new FormData();
214+
const file = await convertBase64ToBlob(request.data.value);
215+
requestData.append(request.data.key, file, request.data.name);
216+
217+
request.data = requestData;
218+
}
219+
220+
// assuming 'application/json' type
221+
const options = {
222+
...request,
223+
signal: newAbortSignal(),
224+
};
225+
226+
const result = await axios(options);
227+
return {
228+
status: result.status,
229+
statusText: result.statusText,
230+
data: result.data,
231+
};
232+
} catch (error) {
233+
if (error?.response) {
234+
return {
235+
error: {
236+
status: error.response.status,
237+
statusText: error.response.statusText,
238+
data: error.response.data,
239+
},
240+
};
241+
} else {
242+
return {
243+
error: {
244+
message: 'An unknown error occurred while running the request',
245+
},
246+
};
247+
}
248+
}
249+
});
192250
};
193251

194252
module.exports = registerRendererEventHandlers;

src/components/molecules/flow/graph/Graph.js

Lines changed: 44 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,15 @@ import Operators from '../constants/operators.js';
33
// assumption is that apis are giving json as output
44

55
class Graph {
6-
constructor(nodes, edges, onGraphComplete, authKey, runRequest) {
6+
constructor(nodes, edges, onGraphComplete) {
77
this.nodes = nodes;
88
this.edges = edges;
99
this.onGraphComplete = onGraphComplete;
10-
this.authKey = authKey;
11-
this.runRequest = runRequest;
1210
this.logs = [];
1311
this.timeout = 60000; // 1m timeout
1412
this.startTime = Date.now();
1513
this.graphRunNodeOutput = {};
14+
this.auth = undefined;
1615
}
1716

1817
#checkTimeout() {
@@ -54,12 +53,14 @@ class Graph {
5453
'Content-type': contentType,
5554
},
5655
data: requestData,
57-
auth: {
58-
username: this.authKey ? this.authKey.accessId : '',
59-
password: this.authKey ? this.authKey.accessKey : '',
60-
},
6156
};
6257

58+
if (this.auth.type === 'basic-auth') {
59+
options.auth = {};
60+
options.auth.username = this.auth.username;
61+
options.auth.password = this.auth.password;
62+
}
63+
6364
this.logs.push(`${restMethod} ${finalUrl}`);
6465
return options;
6566
}
@@ -115,55 +116,41 @@ class Graph {
115116
return evalVariables;
116117
}
117118

119+
#runHttpRequest(request) {
120+
const { ipcRenderer } = window;
121+
122+
return new Promise((resolve, reject) => {
123+
ipcRenderer.invoke('renderer:run-http-request', request).then(resolve).catch(reject);
124+
});
125+
}
126+
118127
async #computeRequestNode(node, prevNodeOutputData) {
119-
try {
120-
// step1 evaluate variables of this node
121-
const evalVariables = this.#computeNodeVariables(node.data.variables, prevNodeOutputData);
128+
// step1 evaluate variables of this node
129+
const evalVariables = this.#computeNodeVariables(node.data.variables, prevNodeOutputData);
122130

123-
// step2 replace variables in url with value
124-
let finalUrl = node.data.url;
125-
Object.entries(evalVariables).map(([vname, vvalue], index) => {
126-
finalUrl = finalUrl.replace(`{${vname}}`, vvalue);
127-
});
131+
// step2 replace variables in url with value
132+
let finalUrl = node.data.url;
133+
Object.entries(evalVariables).map(([vname, vvalue], index) => {
134+
finalUrl = finalUrl.replace(`{${vname}}`, vvalue);
135+
});
128136

129-
// step 3
130-
const options = this.#formulateRequest(node, finalUrl);
137+
// step 3
138+
const options = this.#formulateRequest(node, finalUrl);
131139

132-
console.debug('Evaluated variables: ', evalVariables);
133-
console.debug('Evaluated Url: ', finalUrl);
134-
//const res = await axios(options);
135-
const res = await this.runRequest(JSON.stringify(options));
136-
this.logs.push(`Request successful: ${JSON.stringify(res.data)}`);
137-
console.debug('Response: ', res);
138-
return ['Success', node, res];
139-
} catch (error) {
140+
console.debug('Evaluated variables: ', evalVariables);
141+
console.debug('Evaluated Url: ', finalUrl);
142+
143+
const res = await this.#runHttpRequest(options);
144+
145+
if (res.error) {
140146
console.debug('Failure at node: ', node);
141-
console.debug('Error encountered: ', error);
142-
if (error.response) {
143-
// The request was made and the server responded with a status code
144-
// that falls out of the range of 2xx
145-
console.debug(error.response.data);
146-
console.debug(error.response.status);
147-
console.debug(error.response.headers);
148-
this.logs.push(
149-
`Request failed. Status: ${error.response.status}, Data: ${JSON.stringify(error.response.data)}`,
150-
);
151-
} else if (error.request) {
152-
// The request was made but no response was received
153-
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
154-
// http.ClientRequest in node.js
155-
console.debug('Response: ', error.request);
156-
this.logs.push(`Request failed: ${error.request}`);
157-
} else if (error.message) {
158-
// Something happened in setting up the request that triggered an Error
159-
console.debug('Response: ', error.message);
160-
this.logs.push(`Request failed: ${error.message}`);
161-
} else {
162-
// Something not related to axios request
163-
console.debug('Failure: ', error);
164-
this.logs.push(`Request failed: ${error}`);
165-
}
166-
return ['Failed', node, error];
147+
console.debug('Error encountered: ', JSON.stringify(res.error));
148+
this.logs.push(`Request failed: ${JSON.stringify(res.error)}`);
149+
return ['Failed', node, res.error];
150+
} else {
151+
this.logs.push(`Request successful: ${JSON.stringify(res)}`);
152+
console.debug('Response: ', JSON.stringify(res));
153+
return ['Success', node, res];
167154
}
168155
}
169156

@@ -257,6 +244,11 @@ class Graph {
257244
result = ['Success', node, prevNodeOutput];
258245
}
259246

247+
if (node.type === 'authNode') {
248+
this.auth = node.data.auth;
249+
result = ['Success', node, prevNodeOutput];
250+
}
251+
260252
if (node.type === 'requestNode') {
261253
result = await this.#computeRequestNode(node, prevNodeOutputData);
262254
}
@@ -278,7 +270,7 @@ class Graph {
278270
if (connectingEdge != undefined) {
279271
const nextNode = this.nodes.find(
280272
(node) =>
281-
['requestNode', 'outputNode', 'evaluateNode', 'delayNode'].includes(node.type) &&
273+
['requestNode', 'outputNode', 'evaluateNode', 'delayNode', 'authNode'].includes(node.type) &&
282274
node.id === connectingEdge.target,
283275
);
284276
this.graphRunNodeOutput[node.id] = result[2] && result[2].data ? result[2].data : {};
@@ -298,7 +290,6 @@ class Graph {
298290
});
299291
this.graphRunNodeOutput = {};
300292

301-
console.debug('Using authkey: ', this.authKey);
302293
this.logs.push('Start Flowtest');
303294
const startNode = this.nodes.find((node) => node.type === 'startNode');
304295
if (startNode == undefined) {

src/components/molecules/flow/index.js

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -260,13 +260,7 @@ const Flow = ({ tabId, collectionId, flowData }) => {
260260
<ControlButton
261261
onClick={() => {
262262
runnableEdges(true);
263-
const g = new Graph(
264-
reactFlowInstance.getNodes(),
265-
reactFlowInstance.getEdges(),
266-
onGraphComplete,
267-
{ accessId: '', accessKey: '' },
268-
undefined,
269-
);
263+
const g = new Graph(reactFlowInstance.getNodes(), reactFlowInstance.getEdges(), onGraphComplete);
270264
g.run();
271265
}}
272266
title='run'

0 commit comments

Comments
 (0)