Skip to content

Commit

Permalink
[INS-1810] close connection on response change (#5104)
Browse files Browse the repository at this point in the history
* close ws connection when response is changed

* add delete logic for the queue mapg

* set error response to active response

* useRef for CodeEditor

* extract closeRequest

* use requestId to eliminate inconsistencies

* refactor extract clean up methods

* timeline feedback

* change type annotation

* fix type

* Revert "use requestId to eliminate inconsistencies"

This reverts commit 98335a9.

Co-authored-by: Mark Kim <[email protected]>
  • Loading branch information
2 people authored and filfreire committed Sep 6, 2022
1 parent da2d3b4 commit 9ad0ce7
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 48 deletions.
70 changes: 31 additions & 39 deletions packages/insomnia/src/main/network/websocket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,13 +244,9 @@ async function createWebSocketConnection(
timestamp: Date.now(),
};

eventLogFileStreams.get(options.requestId)?.write(JSON.stringify(closeEvent) + '\n');
eventLogFileStreams.get(options.requestId)?.end();
eventLogFileStreams.delete(options.requestId);
timelineFileStreams.get(options.requestId)?.write(JSON.stringify({ value: `Closing connection with code ${code}`, name: 'Text', timestamp: Date.now() }) + '\n');
timelineFileStreams.get(options.requestId)?.end();
timelineFileStreams.delete(options.requestId);
WebSocketConnections.delete(options.requestId);
sendQueueMap.delete(eventChannel);
const message = `Closing connection with code ${code}`;
deleteRequestMaps(request._id, message, closeEvent);

dispatchWebSocketEvent(event.sender, eventChannel, closeEvent);
event.sender.send(readyStateChannel, ws.readyState);
Expand All @@ -268,48 +264,44 @@ async function createWebSocketConnection(
timestamp: Date.now(),
};

eventLogFileStreams.get(options.requestId)?.write(JSON.stringify(errorEvent) + '\n');
eventLogFileStreams.get(options.requestId)?.end();
eventLogFileStreams.delete(options.requestId);
timelineFileStreams.get(options.requestId)?.write(JSON.stringify({ value: message, name: 'Text', timestamp: Date.now() }) + '\n');
timelineFileStreams.get(options.requestId)?.end();
timelineFileStreams.delete(options.requestId);
WebSocketConnections.delete(options.requestId);
deleteRequestMaps(request._id, message, errorEvent);

dispatchWebSocketEvent(event.sender, eventChannel, errorEvent);
event.sender.send(readyStateChannel, ws.readyState);

const responsePatch = {
_id: responseId,
parentId: request._id,
timelinePath,
statusMessage: 'Error',
error: message || 'Something went wrong',
};
const settings = await models.settings.getOrCreate();
models.response.create(responsePatch, settings.maxHistoryResponses);
createErrorResponse(responseId, request._id, timelinePath, message || 'Something went wrong');
});
} catch (e) {
console.error('unhandled error:', e);
const error = e.message || 'Something went wrong';

eventLogFileStreams.get(options.requestId)?.end();
eventLogFileStreams.delete(options.requestId);
timelineFileStreams.get(options.requestId)?.write(JSON.stringify({ value: error, name: 'Text', timestamp: Date.now() }) + '\n');
timelineFileStreams.get(options.requestId)?.end();
timelineFileStreams.delete(options.requestId);
WebSocketConnections.delete(options.requestId);
deleteRequestMaps(request._id, e.message || 'Something went wrong');
createErrorResponse(responseId, request._id, timelinePath, e.message || 'Something went wrong');
}
}

const settings = await models.settings.getOrCreate();
const responsePatch = {
_id: responseId,
parentId: request._id,
timelinePath,
statusMessage: 'Error',
error,
};
models.response.create(responsePatch, settings.maxHistoryResponses);
async function createErrorResponse(responseId: string, requestId: string, timelinePath: string, message: string) {
const settings = await models.settings.getOrCreate();
const responsePatch = {
_id: responseId,
parentId: requestId,
timelinePath,
statusMessage: 'Error',
error: message,
};
models.response.create(responsePatch, settings.maxHistoryResponses);
models.requestMeta.updateOrCreateByParentId(requestId, { activeResponseId: null });
}

async function deleteRequestMaps(requestId: string, message: string, event?: WebSocketCloseEvent | WebSocketErrorEvent,) {
if (event) {
eventLogFileStreams.get(requestId)?.write(JSON.stringify(event) + '\n');
}
eventLogFileStreams.get(requestId)?.end();
eventLogFileStreams.delete(requestId);
timelineFileStreams.get(requestId)?.write(JSON.stringify({ value: message, name: 'Text', timestamp: Date.now() }) + '\n');
timelineFileStreams.get(requestId)?.end();
timelineFileStreams.delete(requestId);
WebSocketConnections.delete(requestId);
}

function getWebSocketReadyState(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export const ResponseDebugModal = forwardRef<ResponseDebugModalHandle, ModalProp
>
{(responseId && timeline) ? (
<ResponseTimelineViewer
responseId={responseId}
key={responseId}
timeline={timeline}
/>
) : (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ export const ResponsePane: FC<Props> = ({
<TabPanel className="react-tabs__tab-panel">
<ErrorBoundary key={response._id} errorClassName="font-error pad text-center">
<ResponseTimelineViewer
responseId={response._id}
key={response._id}
timeline={timeline}
/>
</ErrorBoundary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import React, { FC } from 'react';
import React, { FC, useEffect, useRef } from 'react';

import { clickLink } from '../../../common/electron-helpers';
import type { ResponseTimelineEntry } from '../../../main/network/libcurl-promise';
import { CodeEditor } from '../codemirror/code-editor';
import { CodeEditor, UnconnectedCodeEditor } from '../codemirror/code-editor';

interface Props {
responseId: string;
timeline: ResponseTimelineEntry[];
}

export const ResponseTimelineViewer: FC<Props> = ({ responseId, timeline }) => {
export const ResponseTimelineViewer: FC<Props> = ({ timeline }) => {
const editorRef = useRef<UnconnectedCodeEditor>(null);
const rows = timeline
.map(({ name, value }, i, all) => {
const prefixLookup: Record<ResponseTimelineEntry['name'], string> = {
Expand All @@ -34,9 +34,16 @@ export const ResponseTimelineViewer: FC<Props> = ({ responseId, timeline }) => {
.filter(r => r !== null)
.join('\n')
.trim();

useEffect(() => {
if (editorRef.current) {
editorRef.current.codeMirror?.setValue(rows);
}
}, [rows]);

return (
<CodeEditor
key={responseId + timeline.length}
ref={editorRef}
hideLineNumbers
readOnly
onClickLink={clickLink}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,20 @@ const WebSocketActiveResponsePane: FC<{ requestId: string; response: Response; h
setSelectedEvent((selected: WebSocketEvent | null) => selected?._id === event._id ? null : event);
};

const setActiveResponseAndDisconnect = (requestId: string, response: Response | null) => {
handleSetActiveResponse(requestId, response);
window.main.webSocketConnection.close({ requestId });
};

useEffect(() => {
setSelectedEvent(null);
}, [response._id]);

useEffect(() => {
let isMounted = true;
const fn = async () => {
// @TODO: this needs to fs.watch or tail the file, instead of reading the whole thing on every event.
// or alternatively a throttle to keep it from reading too frequently
const rawBuffer = await fs.promises.readFile(response.timelinePath);
const timelineString = rawBuffer.toString();
const timelineParsed = timelineString.split('\n').filter(e => e?.trim()).map(e => JSON.parse(e));
Expand All @@ -98,7 +105,7 @@ const WebSocketActiveResponsePane: FC<{ requestId: string; response: Response; h
</div>
<ResponseHistoryDropdown
activeResponse={response}
handleSetActiveResponse={handleSetActiveResponse}
handleSetActiveResponse={setActiveResponseAndDisconnect}
requestId={requestId}
className="tall pane__header__right"
/>
Expand Down Expand Up @@ -150,7 +157,7 @@ const WebSocketActiveResponsePane: FC<{ requestId: string; response: Response; h
</TabPanel>
<TabPanel className="react-tabs__tab-panel">
<ResponseTimelineViewer
responseId={response._id}
key={response._id}
timeline={timeline}
/>
</TabPanel>
Expand Down

0 comments on commit 9ad0ce7

Please sign in to comment.