mirror of
https://github.com/Kong/insomnia
synced 2024-11-08 06:39:48 +00:00
squishy squash connect and send (#5204)
Co-authored-by: jackkav <jackkav@gmail.com>
This commit is contained in:
parent
883753a7df
commit
07833abcb5
@ -91,17 +91,18 @@ const parseResponseAndBuildTimeline = (url: string, incomingMessage: IncomingMes
|
||||
];
|
||||
return { timeline, responseHeaders, statusCode, statusMessage, httpVersion };
|
||||
};
|
||||
|
||||
const createWebSocketConnection = async (
|
||||
event: Electron.IpcMainInvokeEvent,
|
||||
options: {
|
||||
interface OpenWebSocketRequestOptions {
|
||||
requestId: string;
|
||||
workspaceId: string;
|
||||
url: string;
|
||||
headers: RequestHeader[];
|
||||
authentication: RequestAuthentication;
|
||||
cookieJar: CookieJar;
|
||||
}
|
||||
initialPayload?: string;
|
||||
}
|
||||
const openWebSocketConnection = async (
|
||||
event: Electron.IpcMainInvokeEvent,
|
||||
options: OpenWebSocketRequestOptions
|
||||
): Promise<void> => {
|
||||
const existingConnection = WebSocketConnections.get(options.requestId);
|
||||
|
||||
@ -282,6 +283,10 @@ const createWebSocketConnection = async (
|
||||
eventLogFileStreams.get(options.requestId)?.write(JSON.stringify(openEvent) + '\n');
|
||||
timelineFileStreams.get(options.requestId)?.write(JSON.stringify({ value: 'WebSocket connection established', name: 'Text', timestamp: Date.now() }) + '\n');
|
||||
event.sender.send(readyStateChannel, ws.readyState);
|
||||
|
||||
if (options.initialPayload) {
|
||||
sendPayload(ws, { requestId: options.requestId, payload: options.initialPayload });
|
||||
}
|
||||
});
|
||||
|
||||
ws.addEventListener('message', ({ data }: MessageEvent) => {
|
||||
@ -369,17 +374,8 @@ const getWebSocketReadyState = async (
|
||||
return WebSocketConnections.get(options.requestId)?.readyState ?? 0;
|
||||
};
|
||||
|
||||
const sendWebSocketEvent = async (
|
||||
options: { message: string; requestId: string }
|
||||
): Promise<void> => {
|
||||
const ws = WebSocketConnections.get(options.requestId);
|
||||
|
||||
if (!ws) {
|
||||
console.warn('No websocket found for requestId: ' + options.requestId);
|
||||
return;
|
||||
}
|
||||
|
||||
ws.send(options.message, error => {
|
||||
const sendPayload = async (ws: WebSocket, options: { payload: string; requestId: string }): Promise<void> => {
|
||||
ws.send(options.payload, error => {
|
||||
// @TODO: We might want to set a status in the WebSocketMessageEvent
|
||||
// and update it here based on the error. e.g. status = 'sending' | 'sent' | 'error'
|
||||
if (error) {
|
||||
@ -392,7 +388,7 @@ const sendWebSocketEvent = async (
|
||||
const lastMessage: WebSocketMessageEvent = {
|
||||
_id: uuidV4(),
|
||||
requestId: options.requestId,
|
||||
data: options.message,
|
||||
data: options.payload,
|
||||
direction: 'OUTGOING',
|
||||
type: 'message',
|
||||
timestamp: Date.now(),
|
||||
@ -406,6 +402,19 @@ const sendWebSocketEvent = async (
|
||||
}
|
||||
};
|
||||
|
||||
const sendWebSocketEvent = async (
|
||||
options: { payload: string; requestId: string }
|
||||
): Promise<void> => {
|
||||
const ws = WebSocketConnections.get(options.requestId);
|
||||
|
||||
if (!ws) {
|
||||
console.warn('No websocket found for requestId: ' + options.requestId);
|
||||
return;
|
||||
}
|
||||
|
||||
sendPayload(ws, options);
|
||||
};
|
||||
|
||||
const closeWebSocketConnection = async (
|
||||
options: { requestId: string }
|
||||
): Promise<void> => {
|
||||
@ -436,14 +445,7 @@ const findMany = async (
|
||||
};
|
||||
|
||||
export interface WebSocketBridgeAPI {
|
||||
create: (options: {
|
||||
requestId: string;
|
||||
workspaceId: string;
|
||||
url: string;
|
||||
headers: RequestHeader[];
|
||||
authentication: RequestAuthentication;
|
||||
cookieJar: CookieJar;
|
||||
}) => void;
|
||||
open: (options: OpenWebSocketRequestOptions) => void;
|
||||
close: typeof closeWebSocketConnection;
|
||||
closeAll: typeof closeAllWebSocketConnections;
|
||||
readyState: {
|
||||
@ -451,11 +453,11 @@ export interface WebSocketBridgeAPI {
|
||||
};
|
||||
event: {
|
||||
findMany: typeof findMany;
|
||||
send: (options: { requestId: string; message: string }) => void;
|
||||
send: typeof sendWebSocketEvent;
|
||||
};
|
||||
}
|
||||
export const registerWebSocketHandlers = () => {
|
||||
ipcMain.handle('webSocket.create', createWebSocketConnection);
|
||||
ipcMain.handle('webSocket.open', openWebSocketConnection);
|
||||
ipcMain.handle('webSocket.event.send', (_, options: Parameters<typeof sendWebSocketEvent>[0]) => sendWebSocketEvent(options));
|
||||
ipcMain.handle('webSocket.close', (_, options: Parameters<typeof closeWebSocketConnection>[0]) => closeWebSocketConnection(options));
|
||||
ipcMain.handle('webSocket.closeAll', closeAllWebSocketConnections);
|
||||
|
@ -3,7 +3,7 @@ import { contextBridge, ipcRenderer } from 'electron';
|
||||
import type { WebSocketBridgeAPI } from './main/network/websocket';
|
||||
|
||||
const webSocket: WebSocketBridgeAPI = {
|
||||
create: options => ipcRenderer.invoke('webSocket.create', options),
|
||||
open: options => ipcRenderer.invoke('webSocket.open', options),
|
||||
close: options => ipcRenderer.invoke('webSocket.close', options),
|
||||
closeAll: () => ipcRenderer.invoke('webSocket.closeAll'),
|
||||
readyState: {
|
||||
|
@ -5,7 +5,7 @@ import styled from 'styled-components';
|
||||
import { hotKeyRefs } from '../../../common/hotkeys';
|
||||
import { executeHotKey } from '../../../common/hotkeys-listener';
|
||||
import { getRenderContext, render, RENDER_PURPOSE_SEND } from '../../../common/render';
|
||||
import { cookieJar } from '../../../models';
|
||||
import * as models from '../../../models';
|
||||
import { WebSocketRequest } from '../../../models/websocket-request';
|
||||
import { ReadyState } from '../../context/websocket-client/use-ws-ready-state';
|
||||
import { OneLineEditor } from '../codemirror/one-line-editor';
|
||||
@ -81,22 +81,19 @@ export const WebSocketActionBar: FC<ActionBarProps> = ({ request, workspaceId, e
|
||||
}
|
||||
try {
|
||||
const renderContext = await getRenderContext({ request, environmentId, purpose: RENDER_PURPOSE_SEND });
|
||||
const { url: rawUrl, headers, authentication, parameters } = request;
|
||||
// Render any nunjucks tags in the url/headers/authentication settings/cookies
|
||||
const workspaceCookieJar = await cookieJar.getOrCreateForParentId(workspaceId);
|
||||
const workspaceCookieJar = await models.cookieJar.getOrCreateForParentId(workspaceId);
|
||||
const rendered = await render({
|
||||
url: rawUrl,
|
||||
headers,
|
||||
authentication,
|
||||
parameters,
|
||||
url: request.url,
|
||||
headers: request.headers,
|
||||
authentication: request.authentication,
|
||||
parameters: request.parameters,
|
||||
workspaceCookieJar,
|
||||
}, renderContext);
|
||||
const queryString = buildQueryStringFromParams(rendered.parameters);
|
||||
const url = joinUrlAndQueryString(rendered.url, queryString);
|
||||
window.main.webSocket.create({
|
||||
window.main.webSocket.open({
|
||||
requestId: request._id,
|
||||
workspaceId,
|
||||
url,
|
||||
url: joinUrlAndQueryString(rendered.url, buildQueryStringFromParams(rendered.parameters)),
|
||||
headers: rendered.headers,
|
||||
authentication: rendered.authentication,
|
||||
cookieJar: rendered.workspaceCookieJar,
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, { FC, FormEvent, useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { buildQueryStringFromParams, joinUrlAndQueryString } from 'insomnia-url';
|
||||
import React, { FC, useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { Tab, TabList, TabPanel, Tabs } from 'react-tabs';
|
||||
import styled from 'styled-components';
|
||||
@ -34,20 +35,20 @@ const SendMessageForm = styled.form({
|
||||
position: 'relative',
|
||||
boxSizing: 'border-box',
|
||||
});
|
||||
const SendButton = styled.button({
|
||||
const SendButton = styled.button<{ isConnected: boolean }>(({ isConnected }) =>
|
||||
({
|
||||
padding: '0 var(--padding-md)',
|
||||
marginLeft: 'var(--padding-xs)',
|
||||
height: '100%',
|
||||
border: '1px solid var(--hl-lg)',
|
||||
borderRadius: 'var(--radius-md)',
|
||||
background: isConnected ? 'var(--color-surprise)' : 'inherit',
|
||||
color: isConnected ? 'var(--color-font-surprise)' : 'inherit',
|
||||
':hover': {
|
||||
filter: 'brightness(0.8)',
|
||||
},
|
||||
':enabled': {
|
||||
background: 'var(--color-surprise)',
|
||||
color: 'var(--color-font-surprise)',
|
||||
},
|
||||
});
|
||||
}));
|
||||
|
||||
const PaneSendButton = styled.div({
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
@ -65,6 +66,7 @@ interface FormProps {
|
||||
request: WebSocketRequest;
|
||||
previewMode: string;
|
||||
environmentId: string;
|
||||
workspaceId: string;
|
||||
}
|
||||
|
||||
const PayloadTabPanel = styled(TabPanel)({
|
||||
@ -78,29 +80,46 @@ const WebSocketRequestForm: FC<FormProps> = ({
|
||||
request,
|
||||
previewMode,
|
||||
environmentId,
|
||||
workspaceId,
|
||||
}) => {
|
||||
const editorRef = useRef<UnconnectedCodeEditor>(null);
|
||||
|
||||
useEffect(() => {
|
||||
async function initMessageText(): Promise<void> {
|
||||
const init = async () => {
|
||||
const payload = await models.webSocketPayload.getByParentId(request._id);
|
||||
const msg = payload?.value || '';
|
||||
editorRef.current?.codeMirror?.setValue(msg);
|
||||
}
|
||||
};
|
||||
|
||||
initMessageText();
|
||||
init();
|
||||
}, [request._id]);
|
||||
|
||||
const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
const message = editorRef.current?.getValue() || '';
|
||||
|
||||
// NOTE: Nunjucks interpolation can throw errors
|
||||
const interpolateOpenAndSend = async (payload: string) => {
|
||||
try {
|
||||
// Render any nunjucks tag in the message
|
||||
const renderContext = await getRenderContext({ request, environmentId, purpose: RENDER_PURPOSE_SEND });
|
||||
const renderedMessage = await render(message, renderContext);
|
||||
|
||||
window.main.webSocket.event.send({ requestId: request._id, message: renderedMessage });
|
||||
const renderedMessage = await render(payload, renderContext);
|
||||
const readyState = await window.main.webSocket.readyState.getCurrent({ requestId: request._id });
|
||||
if (readyState !== ReadyState.OPEN) {
|
||||
const workspaceCookieJar = await models.cookieJar.getOrCreateForParentId(workspaceId);
|
||||
const rendered = await render({
|
||||
url: request.url,
|
||||
headers: request.headers,
|
||||
authentication: request.authentication,
|
||||
parameters: request.parameters,
|
||||
workspaceCookieJar,
|
||||
}, renderContext);
|
||||
window.main.webSocket.open({
|
||||
requestId: request._id,
|
||||
workspaceId,
|
||||
url: joinUrlAndQueryString(rendered.url, buildQueryStringFromParams(rendered.parameters)),
|
||||
headers: rendered.headers,
|
||||
authentication: rendered.authentication,
|
||||
cookieJar: rendered.workspaceCookieJar,
|
||||
initialPayload: renderedMessage,
|
||||
});
|
||||
return;
|
||||
}
|
||||
window.main.webSocket.event.send({ requestId: request._id, payload: renderedMessage });
|
||||
} catch (err) {
|
||||
if (err.type === 'render') {
|
||||
showModal(RequestRenderErrorModal, {
|
||||
@ -140,7 +159,13 @@ const WebSocketRequestForm: FC<FormProps> = ({
|
||||
// To allow for disabling rendering of messages based on a per-request setting.
|
||||
// Same as with regular requests
|
||||
return (
|
||||
<SendMessageForm id="websocketMessageForm" onSubmit={handleSubmit}>
|
||||
<SendMessageForm
|
||||
id="websocketMessageForm"
|
||||
onSubmit={event => {
|
||||
event.preventDefault();
|
||||
interpolateOpenAndSend(editorRef.current?.getValue() || '');
|
||||
}}
|
||||
>
|
||||
<CodeEditor
|
||||
manualPrettify
|
||||
uniquenessKey={request._id}
|
||||
@ -266,7 +291,7 @@ export const WebSocketRequestPane: FC<Props> = ({ request, workspaceId, environm
|
||||
<SendButton
|
||||
type="submit"
|
||||
form="websocketMessageForm"
|
||||
disabled={readyState !== ReadyState.OPEN}
|
||||
isConnected={readyState === ReadyState.OPEN}
|
||||
>
|
||||
Send
|
||||
</SendButton>
|
||||
@ -276,6 +301,7 @@ export const WebSocketRequestPane: FC<Props> = ({ request, workspaceId, environm
|
||||
request={request}
|
||||
previewMode={previewMode}
|
||||
environmentId={environment?._id || ''}
|
||||
workspaceId={workspaceId}
|
||||
/>
|
||||
</PayloadTabPanel>
|
||||
<TabPanel className="react-tabs__tab-panel">
|
||||
|
Loading…
Reference in New Issue
Block a user