|
1 | 1 | import fetch from 'isomorphic-fetch'; |
2 | 2 | import { ThunkAction as ReduxThunkAction } from 'redux-thunk'; |
3 | 3 | import url, { UrlObject } from 'url'; |
| 4 | +import { z } from 'zod'; |
4 | 5 |
|
5 | 6 | import { |
6 | 7 | clippyRequestSelector, |
7 | 8 | formatRequestSelector, |
8 | 9 | getCrateType, |
9 | 10 | isAutoBuildSelector, |
10 | 11 | runAsTest, |
| 12 | + useWebsocketSelector, |
11 | 13 | } from './selectors'; |
12 | 14 | import State from './state'; |
13 | 15 | import { |
@@ -128,7 +130,27 @@ export enum ActionType { |
128 | 130 | NotificationSeen = 'NOTIFICATION_SEEN', |
129 | 131 | BrowserWidthChanged = 'BROWSER_WIDTH_CHANGED', |
130 | 132 | SplitRatioChanged = 'SPLIT_RATIO_CHANGED', |
131 | | -} |
| 133 | + WebSocketError = 'WEBSOCKET_ERROR', |
| 134 | + WebSocketConnected = 'WEBSOCKET_CONNECTED', |
| 135 | + WebSocketDisconnected = 'WEBSOCKET_DISCONNECTED', |
| 136 | + WebSocketFeatureFlagEnabled = 'WEBSOCKET_FEATURE_FLAG_ENABLED', |
| 137 | + WSExecuteRequest = 'WS_EXECUTE_REQUEST', |
| 138 | + WSExecuteResponse = 'WS_EXECUTE_RESPONSE', |
| 139 | +} |
| 140 | + |
| 141 | +const ExecuteExtra = z.object({ |
| 142 | + isAutoBuild: z.boolean(), |
| 143 | +}); |
| 144 | +type ExecuteExtra = z.infer<typeof ExecuteExtra>; |
| 145 | + |
| 146 | +export const WSExecuteResponse = z.object({ |
| 147 | + type: z.literal(ActionType.WSExecuteResponse), |
| 148 | + success: z.boolean(), |
| 149 | + stdout: z.string(), |
| 150 | + stderr: z.string(), |
| 151 | + extra: ExecuteExtra, |
| 152 | +}); |
| 153 | +export type WSExecuteResponse = z.infer<typeof WSExecuteResponse>; |
132 | 154 |
|
133 | 155 | export const initializeApplication = () => createAction(ActionType.InitializeApplication); |
134 | 156 |
|
@@ -284,18 +306,23 @@ interface ExecuteRequestBody { |
284 | 306 | } |
285 | 307 |
|
286 | 308 | const performCommonExecute = (crateType: string, tests: boolean): ThunkAction => (dispatch, getState) => { |
287 | | - dispatch(requestExecute()); |
288 | | - |
289 | 309 | const state = getState(); |
290 | 310 | const { code, configuration: { channel, mode, edition } } = state; |
291 | 311 | const backtrace = state.configuration.backtrace === Backtrace.Enabled; |
292 | 312 | const isAutoBuild = isAutoBuildSelector(state); |
293 | 313 |
|
294 | | - const body: ExecuteRequestBody = { channel, mode, edition, crateType, tests, code, backtrace }; |
295 | 314 |
|
296 | | - return jsonPost<ExecuteResponseBody>(routes.execute, body) |
297 | | - .then(json => dispatch(receiveExecuteSuccess({ ...json, isAutoBuild }))) |
298 | | - .catch(json => dispatch(receiveExecuteFailure({ ...json, isAutoBuild }))); |
| 315 | + if (useWebsocketSelector(state)) { |
| 316 | + return dispatch(wsExecuteRequest(channel, mode, edition, crateType, tests, code, backtrace, { isAutoBuild })); |
| 317 | + } else { |
| 318 | + dispatch(requestExecute()); |
| 319 | + |
| 320 | + const body: ExecuteRequestBody = { channel, mode, edition, crateType, tests, code, backtrace }; |
| 321 | + |
| 322 | + return jsonPost<ExecuteResponseBody>(routes.execute, body) |
| 323 | + .then(json => dispatch(receiveExecuteSuccess({ ...json, isAutoBuild }))) |
| 324 | + .catch(json => dispatch(receiveExecuteFailure({ ...json, isAutoBuild }))); |
| 325 | + } |
299 | 326 | }; |
300 | 327 |
|
301 | 328 | function performAutoOnly(): ThunkAction { |
@@ -476,6 +503,17 @@ const PRIMARY_ACTIONS: { [index in PrimaryAction]: () => ThunkAction } = { |
476 | 503 | [PrimaryActionCore.Wasm]: performCompileToNightlyWasmOnly, |
477 | 504 | }; |
478 | 505 |
|
| 506 | +const wsExecuteRequest = ( |
| 507 | + channel: Channel, |
| 508 | + mode: Mode, |
| 509 | + edition: Edition, |
| 510 | + crateType: string, |
| 511 | + tests: boolean, |
| 512 | + code: string, |
| 513 | + backtrace: boolean, |
| 514 | + extra: ExecuteExtra, |
| 515 | +) => createAction(ActionType.WSExecuteRequest, { channel, mode, edition, crateType, tests, code, backtrace, extra }); |
| 516 | + |
479 | 517 | export const performPrimaryAction = (): ThunkAction => (dispatch, getState) => { |
480 | 518 | const state = getState(); |
481 | 519 | const primaryAction = PRIMARY_ACTIONS[state.configuration.primaryAction]; |
@@ -813,6 +851,11 @@ export const browserWidthChanged = (isSmall: boolean) => |
813 | 851 | export const splitRatioChanged = () => |
814 | 852 | createAction(ActionType.SplitRatioChanged); |
815 | 853 |
|
| 854 | +export const websocketError = () => createAction(ActionType.WebSocketError); |
| 855 | +export const websocketConnected = () => createAction(ActionType.WebSocketConnected); |
| 856 | +export const websocketDisconnected = () => createAction(ActionType.WebSocketDisconnected); |
| 857 | +export const websocketFeatureFlagEnabled = () => createAction(ActionType.WebSocketFeatureFlagEnabled); |
| 858 | + |
816 | 859 | function parseChannel(s?: string): Channel | null { |
817 | 860 | switch (s) { |
818 | 861 | case 'stable': |
@@ -966,4 +1009,10 @@ export type Action = |
966 | 1009 | | ReturnType<typeof notificationSeen> |
967 | 1010 | | ReturnType<typeof browserWidthChanged> |
968 | 1011 | | ReturnType<typeof splitRatioChanged> |
| 1012 | + | ReturnType<typeof websocketError> |
| 1013 | + | ReturnType<typeof websocketConnected> |
| 1014 | + | ReturnType<typeof websocketDisconnected> |
| 1015 | + | ReturnType<typeof websocketFeatureFlagEnabled> |
| 1016 | + | ReturnType<typeof wsExecuteRequest> |
| 1017 | + | WSExecuteResponse |
969 | 1018 | ; |
0 commit comments