Skip to content

Commit 163b715

Browse files
committed
Rewrite websocket reducer with RTK
1 parent c6191cf commit 163b715

File tree

7 files changed

+61
-45
lines changed

7 files changed

+61
-45
lines changed

ui/frontend/.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ module.exports = {
6868
'reducers/output/execute.ts',
6969
'reducers/output/format.ts',
7070
'reducers/output/gist.ts',
71+
'reducers/websocket.ts',
7172
'websocketActions.ts',
7273
'websocketMiddleware.ts',
7374
],

ui/frontend/.prettierignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,6 @@ node_modules
1717
!reducers/output/execute.ts
1818
!reducers/output/format.ts
1919
!reducers/output/gist.ts
20+
!reducers/websocket.ts
2021
!websocketActions.ts
2122
!websocketMiddleware.ts

ui/frontend/actions.ts

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import fetch from 'isomorphic-fetch';
22
import { ThunkAction as ReduxThunkAction, AnyAction } from '@reduxjs/toolkit';
3-
import { z } from 'zod';
43

54
import {
65
codeSelector,
@@ -120,18 +119,8 @@ export enum ActionType {
120119
NotificationSeen = 'NOTIFICATION_SEEN',
121120
BrowserWidthChanged = 'BROWSER_WIDTH_CHANGED',
122121
SplitRatioChanged = 'SPLIT_RATIO_CHANGED',
123-
WebSocketError = 'WEBSOCKET_ERROR',
124-
WebSocketConnected = 'WEBSOCKET_CONNECTED',
125-
WebSocketDisconnected = 'WEBSOCKET_DISCONNECTED',
126-
WebSocketFeatureFlagEnabled = 'WEBSOCKET_FEATURE_FLAG_ENABLED',
127122
}
128123

129-
export const WebSocketError = z.object({
130-
type: z.literal(ActionType.WebSocketError),
131-
error: z.string(),
132-
});
133-
export type WebSocketError = z.infer<typeof WebSocketError>;
134-
135124
export const initializeApplication = () => createAction(ActionType.InitializeApplication);
136125

137126
export const disableSyncChangesToStorage = () => createAction(ActionType.DisableSyncChangesToStorage);
@@ -675,11 +664,6 @@ export const browserWidthChanged = (isSmall: boolean) =>
675664
export const splitRatioChanged = () =>
676665
createAction(ActionType.SplitRatioChanged);
677666

678-
export const websocketError = (error: string): WebSocketError => createAction(ActionType.WebSocketError, { error });
679-
export const websocketConnected = () => createAction(ActionType.WebSocketConnected);
680-
export const websocketDisconnected = () => createAction(ActionType.WebSocketDisconnected);
681-
export const websocketFeatureFlagEnabled = () => createAction(ActionType.WebSocketFeatureFlagEnabled);
682-
683667
function parseChannel(s?: string): Channel | null {
684668
switch (s) {
685669
case 'stable':
@@ -821,9 +805,5 @@ export type Action =
821805
| ReturnType<typeof notificationSeen>
822806
| ReturnType<typeof browserWidthChanged>
823807
| ReturnType<typeof splitRatioChanged>
824-
| ReturnType<typeof websocketError>
825-
| ReturnType<typeof websocketConnected>
826-
| ReturnType<typeof websocketDisconnected>
827-
| ReturnType<typeof websocketFeatureFlagEnabled>
828808
| ReturnType<typeof wsExecuteRequest>
829809
;

ui/frontend/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ import {
1919
performVersionsLoad,
2020
reExecuteWithBacktrace,
2121
browserWidthChanged,
22-
websocketFeatureFlagEnabled,
2322
} from './actions';
2423
import { configureRustErrors } from './highlighting';
2524
import PageSwitcher from './PageSwitcher';
2625
import playgroundApp from './reducers';
26+
import { websocketFeatureFlagEnabled } from './reducers/websocket';
2727
import Router from './Router';
2828
import configureStore from './configureStore';
2929

ui/frontend/reducers/websocket.ts

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,57 @@
1-
import { Action, ActionType } from '../actions';
1+
import { PayloadAction, createSlice } from '@reduxjs/toolkit';
2+
import z from 'zod';
3+
4+
import { createWebsocketResponseSchema } from '../websocketActions';
25

36
export type State = {
47
connected: boolean;
58
error?: string;
69
featureFlagEnabled: boolean;
710
};
811

9-
const DEFAULT: State = {
12+
const initialState: State = {
1013
connected: false,
1114
featureFlagEnabled: false,
1215
};
1316

14-
export default function websocket(state = DEFAULT, action: Action): State {
15-
switch (action.type) {
16-
case ActionType.WebSocketConnected:
17-
return { ...state, connected: true, error: undefined };
17+
const websocketErrorPayloadSchema = z.object({
18+
error: z.string(),
19+
});
20+
type websocketErrorPayload = z.infer<typeof websocketErrorPayloadSchema>;
21+
22+
const slice = createSlice({
23+
name: 'websocket',
24+
initialState,
25+
reducers: {
26+
connected: (state) => {
27+
state.connected = true;
28+
delete state.error;
29+
},
30+
31+
disconnected: (state) => {
32+
state.connected = false;
33+
},
34+
35+
error: (state, action: PayloadAction<websocketErrorPayload>) => {
36+
state.error = action.payload.error;
37+
},
1838

19-
case ActionType.WebSocketDisconnected:
20-
return { ...state, connected: false };
39+
featureFlagEnabled: (state) => {
40+
state.featureFlagEnabled = true;
41+
},
42+
},
43+
});
2144

22-
case ActionType.WebSocketError:
23-
return { ...state, error: action.error };
45+
export const {
46+
connected: websocketConnected,
47+
disconnected: websocketDisconnected,
48+
error: websocketError,
49+
featureFlagEnabled: websocketFeatureFlagEnabled,
50+
} = slice.actions;
2451

25-
case ActionType.WebSocketFeatureFlagEnabled:
26-
return { ...state, featureFlagEnabled: true };
52+
export const websocketErrorSchema = createWebsocketResponseSchema(
53+
websocketError,
54+
websocketErrorPayloadSchema,
55+
);
2756

28-
default:
29-
return state;
30-
}
31-
}
57+
export default slice.reducer;

ui/frontend/websocketMiddleware.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
import { AnyAction, Middleware } from '@reduxjs/toolkit';
22
import { z } from 'zod';
33

4+
import { wsExecuteResponseSchema } from './reducers/output/execute';
45
import {
5-
WebSocketError,
66
websocketConnected,
77
websocketDisconnected,
88
websocketError,
9-
} from './actions';
10-
import { wsExecuteResponseSchema } from './reducers/output/execute';
9+
websocketErrorSchema,
10+
} from './reducers/websocket';
1111

12-
const WSMessageResponse = z.discriminatedUnion('type', [WebSocketError, wsExecuteResponseSchema]);
12+
const WSMessageResponse = z.discriminatedUnion('type', [
13+
websocketErrorSchema,
14+
wsExecuteResponseSchema,
15+
]);
1316

1417
const reportWebSocketError = async (error: string) => {
1518
try {
@@ -93,7 +96,7 @@ export const websocketMiddleware =
9396
// We cannot get detailed information about the failure
9497
// https://stackoverflow.com/a/31003057/155423
9598
const error = 'Generic WebSocket Error';
96-
store.dispatch(websocketError(error));
99+
store.dispatch(websocketError({ error }));
97100
reportWebSocketError(error);
98101
});
99102

ui/src/server_axum/websocket.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ impl TryFrom<ExecuteRequest> for sandbox::ExecuteRequest {
6363
#[derive(Debug, serde::Serialize)]
6464
#[serde(tag = "type")]
6565
enum MessageResponse {
66-
#[serde(rename = "WEBSOCKET_ERROR")]
67-
Error(WSError),
66+
#[serde(rename = "websocket/error")]
67+
Error { payload: WSError, meta: Meta },
6868

6969
#[serde(rename = "output/execute/wsExecuteResponse")]
7070
ExecuteResponse {
@@ -174,7 +174,12 @@ pub async fn handle(mut socket: WebSocket) {
174174

175175
fn error_to_response(error: Error) -> MessageResponse {
176176
let error = error.to_string();
177-
MessageResponse::Error(WSError { error })
177+
// TODO: thread through the Meta from the originating request
178+
let meta = serde_json::json!({ "sequenceNumber": -1 });
179+
MessageResponse::Error {
180+
payload: WSError { error },
181+
meta,
182+
}
178183
}
179184

180185
fn response_to_message(response: MessageResponse) -> Message {

0 commit comments

Comments
 (0)