mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-24 13:15:40 +00:00
feat: enhance WebSocket handling with redirect and upgrade events
- Added support for 'ws:redirect' and 'ws:upgrade' events in the WebSocket client. - Updated WSResponseHeaders to format headers correctly. - Modified WSResponsePane to display headers in the response. - Improved message handling in the Redux slice for WebSocket events.
This commit is contained in:
@@ -128,11 +128,9 @@ const RequestTab = ({ tab, collection, tabIndex, collectionRequestTabs, folderUi
|
||||
);
|
||||
}
|
||||
|
||||
const isGrpc = item.type === 'grpc-request';
|
||||
const isWS = item.type === 'ws-request';
|
||||
const method = getMethodText(item)
|
||||
|
||||
|
||||
return (
|
||||
<StyledWrapper className="flex items-center justify-between tab-container px-1">
|
||||
{showConfirmClose && (
|
||||
|
||||
@@ -34,7 +34,6 @@ const parseContent = (content) => {
|
||||
return {
|
||||
type: contentMeta.isJSON ? 'application/json' : 'text/plain',
|
||||
content: contentMeta.isJSON ? JSON.stringify(JSON.parse(contentMeta.content), null, 2) : contentMeta.content,
|
||||
sliced: contentMeta.content.slice(0, 30)
|
||||
};
|
||||
};
|
||||
|
||||
@@ -70,7 +69,6 @@ const WSMessageItem = ({ message, isLast }) => {
|
||||
const isIncoming = message.type === 'incoming';
|
||||
const isInfo = message.type === 'info';
|
||||
let parsedContent = parseContent(message.message);
|
||||
|
||||
const dataType = getDataTypeText(parsedContent.type);
|
||||
|
||||
return (
|
||||
@@ -88,17 +86,16 @@ const WSMessageItem = ({ message, isLast }) => {
|
||||
<div
|
||||
className={
|
||||
classnames("flex items-center justify-between",{
|
||||
'cursor-not-allowed': isInfo,
|
||||
'cursor-pointer': !isInfo
|
||||
"cursor-pointer": !isInfo,
|
||||
"cursor-not-allowed": isInfo
|
||||
})
|
||||
}
|
||||
onClick={(e) => {
|
||||
if(!isInfo){
|
||||
setIsOpen(!isOpen);
|
||||
}
|
||||
if(isInfo) return
|
||||
setIsOpen(!isOpen);
|
||||
}}
|
||||
>
|
||||
<div className="flex">
|
||||
<div className="flex min-w-0 shrink">
|
||||
<span
|
||||
className={classnames(
|
||||
'font-semibold flex items-center gap-1',
|
||||
@@ -107,9 +104,9 @@ const WSMessageItem = ({ message, isLast }) => {
|
||||
>
|
||||
<TypeIcon type={message.type} />
|
||||
</span>
|
||||
<span className="ml-3">{parsedContent.sliced}</span>
|
||||
<span className="ml-3 text-ellipsis max-w-full overflow-hidden text-nowrap">{parsedContent.content}</span>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<div className="flex shrink-0 gap-2">
|
||||
{message.timestamp && (
|
||||
<span className="text-xs text-gray-400">{new Date(message.timestamp).toISOString()}</span>
|
||||
)}
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import React from 'react';
|
||||
import StyledWrapper from './StyledWrapper';
|
||||
|
||||
const WSResponseHeaders = ({ metadata }) => {
|
||||
// Ensure headers is an array
|
||||
const metadataArray = Array.isArray(metadata) ? metadata : [];
|
||||
const WSResponseHeaders = ({ response }) => {
|
||||
const formatHeaders = (headers) => {
|
||||
if (!headers) return [];
|
||||
if (Array.isArray(headers)) return headers;
|
||||
return Object.entries(headers).map(([key, value]) => ({ name: key, value }));
|
||||
};
|
||||
|
||||
const metadataArray = formatHeaders(response.headers);
|
||||
|
||||
return (
|
||||
<StyledWrapper className="pb-4 w-full">
|
||||
|
||||
@@ -14,6 +14,7 @@ import ResponseLayoutToggle from '../ResponseLayoutToggle';
|
||||
import Tab from 'components/Tab';
|
||||
import WSMessagesList from './WSMessagesList';
|
||||
import WSResponseSortOrder from './WSResponseSortOrder';
|
||||
import WSResponseHeaders from './WSResponseHeaders';
|
||||
|
||||
const WSResult = ({ response }) => {
|
||||
return response.isError ? (
|
||||
@@ -51,6 +52,9 @@ const WSResponsePane = ({ item, collection }) => {
|
||||
case 'response': {
|
||||
return <WSResult response={response} />;
|
||||
}
|
||||
case 'headers': {
|
||||
return <WSResponseHeaders response={response} />;
|
||||
}
|
||||
case 'timeline': {
|
||||
return <Timeline collection={collection} item={item} />;
|
||||
}
|
||||
@@ -91,6 +95,11 @@ const WSResponsePane = ({ item, collection }) => {
|
||||
label: 'Messages',
|
||||
count: Array.isArray(response.responses) ? response.responses.length : 0
|
||||
},
|
||||
{
|
||||
name: 'headers',
|
||||
label: 'Metadata',
|
||||
count: response.headers ? Object.keys(response.headers).length : 0
|
||||
},
|
||||
{
|
||||
name: 'timeline',
|
||||
label: 'Timeline'
|
||||
|
||||
@@ -2817,28 +2817,33 @@ export const collectionsSlice = createSlice({
|
||||
// Process based on event type
|
||||
switch (eventType) {
|
||||
case 'message':
|
||||
const { message, type } = eventData;
|
||||
|
||||
// Add message to responses list
|
||||
updatedResponse.responses = [
|
||||
...(currentResponse?.responses || []),
|
||||
{
|
||||
message,
|
||||
type,
|
||||
timestamp: Date.now()
|
||||
}
|
||||
];
|
||||
updatedResponse.responses = (currentResponse?.responses||[]).concat(eventData)
|
||||
break;
|
||||
|
||||
case 'redirect':
|
||||
updatedResponse.requestHeaders = eventData.headers
|
||||
updatedResponse.responses ||= []
|
||||
updatedResponse.responses.push({
|
||||
message: eventData.message,
|
||||
type: eventData.type,
|
||||
timestamp: eventData.timestamp,
|
||||
})
|
||||
break
|
||||
|
||||
case 'upgrade':
|
||||
updatedResponse.headers = eventData.headers
|
||||
break
|
||||
|
||||
case 'open':
|
||||
updatedResponse.status = 'CONNECTED';
|
||||
updatedResponse.statusText = 'CONNECTED';
|
||||
updatedResponse.statusCode = 0;
|
||||
updatedResponse.responses ||= []
|
||||
updatedResponse.responses.push({
|
||||
message: "Connected",
|
||||
type: "info",
|
||||
timestamp: Date.now()
|
||||
message: `Connected to ${eventData.url}`,
|
||||
type: 'info',
|
||||
timestamp: eventData.timestamp
|
||||
})
|
||||
break;
|
||||
|
||||
|
||||
@@ -28,6 +28,30 @@ const useWsEventListeners = () => {
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
|
||||
const removeWsUpgradeListener = ipcRenderer.on('ws:upgrade', (requestId, collectionUid, eventData) => {
|
||||
dispatch(
|
||||
wsResponseReceived({
|
||||
itemUid: requestId,
|
||||
collectionUid: collectionUid,
|
||||
eventType: 'upgrade',
|
||||
eventData: eventData
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
const removeWsRedirectListener = ipcRenderer.on('ws:redirect', (requestId, collectionUid, eventData) => {
|
||||
dispatch(
|
||||
wsResponseReceived({
|
||||
itemUid: requestId,
|
||||
collectionUid: collectionUid,
|
||||
eventType: 'redirect',
|
||||
eventData: eventData
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
// Handle WebSocket message event
|
||||
const removeWsMessageListener = ipcRenderer.on('ws:message', (requestId, collectionUid, eventData) => {
|
||||
dispatch(
|
||||
@@ -94,6 +118,8 @@ const useWsEventListeners = () => {
|
||||
|
||||
return () => {
|
||||
removeWsRequestSentListener();
|
||||
removeWsUpgradeListener();
|
||||
removeWsRedirectListener();
|
||||
removeWsMessageListener();
|
||||
removeWsOpenListener();
|
||||
removeWsCloseListener();
|
||||
|
||||
@@ -40,8 +40,6 @@ const bruToJson = (fileContents) => {
|
||||
|
||||
const parsed = parser.run(fileContents).result.reduce((acc, item) => _.merge(acc, item), {});
|
||||
|
||||
console.log({ parsed });
|
||||
|
||||
const json = {
|
||||
type: parsed.type || '',
|
||||
name: parsed.name || '',
|
||||
|
||||
@@ -94,17 +94,16 @@ class WsClient {
|
||||
});
|
||||
|
||||
// Set up event handlers
|
||||
this.#setupWsEventHandlers(wsConnection, requestId, collectionUid);
|
||||
this.#setupWsEventHandlers(wsConnection, requestId, collectionUid, {
|
||||
url: parsedUrl.fullUrl,
|
||||
headers
|
||||
});
|
||||
|
||||
// Store the connection
|
||||
this.#addConnection(requestId, wsConnection);
|
||||
|
||||
// Emit connecting event
|
||||
this.eventCallback('ws:connecting', requestId, collectionUid, {
|
||||
url: parsedUrl.fullUrl,
|
||||
headers,
|
||||
timestamp: Date.now()
|
||||
});
|
||||
this.eventCallback('ws:connecting', requestId, collectionUid);
|
||||
|
||||
wsConnection.addEventListener('open', () => {
|
||||
this.#flushQueue(requestId, collectionUid);
|
||||
@@ -265,10 +264,30 @@ class WsClient {
|
||||
#setupWsEventHandlers(ws, requestId, collectionUid) {
|
||||
ws.on('open', () => {
|
||||
this.eventCallback('ws:open', requestId, collectionUid, {
|
||||
timestamp: Date.now()
|
||||
timestamp: Date.now(),
|
||||
url: ws.url
|
||||
});
|
||||
});
|
||||
|
||||
ws.on('redirect', (url, req) => {
|
||||
const headerNames = req.getHeaderNames()
|
||||
const headers = Object.fromEntries(headerNames.map(d=> [d,req.getHeader(d)]))
|
||||
this.eventCallback('ws:redirect', requestId, collectionUid, {
|
||||
message:`Redirected to ${url}`,
|
||||
type: 'info',
|
||||
timestamp: Date.now(),
|
||||
headers: headers
|
||||
});
|
||||
})
|
||||
|
||||
ws.on('upgrade', (response) => {
|
||||
this.eventCallback('ws:upgrade', requestId, collectionUid, {
|
||||
type: 'info',
|
||||
timestamp: Date.now(),
|
||||
headers: {...response.headers}
|
||||
});
|
||||
})
|
||||
|
||||
ws.on('message', (data) => {
|
||||
try {
|
||||
const message = JSON.parse(data.toString());
|
||||
|
||||
Reference in New Issue
Block a user