|
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 | | - isAutoBuildSelector, |
10 | 10 | runAsTest, |
| 11 | + useWebsocketSelector, |
11 | 12 | } from './selectors'; |
12 | 13 | import State from './state'; |
13 | 14 | import { |
@@ -62,6 +63,7 @@ const createAction = <T extends string, P extends {}>(type: T, props?: P) => ( |
62 | 63 |
|
63 | 64 | export enum ActionType { |
64 | 65 | InitializeApplication = 'INITIALIZE_APPLICATION', |
| 66 | + DisableSyncChangesToStorage = 'DISABLE_SYNC_CHANGES_TO_STORAGE', |
65 | 67 | SetPage = 'SET_PAGE', |
66 | 68 | ChangeEditor = 'CHANGE_EDITOR', |
67 | 69 | ChangeKeybinding = 'CHANGE_KEYBINDING', |
@@ -127,10 +129,38 @@ export enum ActionType { |
127 | 129 | NotificationSeen = 'NOTIFICATION_SEEN', |
128 | 130 | BrowserWidthChanged = 'BROWSER_WIDTH_CHANGED', |
129 | 131 | SplitRatioChanged = 'SPLIT_RATIO_CHANGED', |
| 132 | + WebSocketError = 'WEBSOCKET_ERROR', |
| 133 | + WebSocketConnected = 'WEBSOCKET_CONNECTED', |
| 134 | + WebSocketDisconnected = 'WEBSOCKET_DISCONNECTED', |
| 135 | + WebSocketFeatureFlagEnabled = 'WEBSOCKET_FEATURE_FLAG_ENABLED', |
| 136 | + WSExecuteRequest = 'WS_EXECUTE_REQUEST', |
| 137 | + WSExecuteResponse = 'WS_EXECUTE_RESPONSE', |
130 | 138 | } |
131 | 139 |
|
| 140 | +export const WebSocketError = z.object({ |
| 141 | + type: z.literal(ActionType.WebSocketError), |
| 142 | + error: z.string(), |
| 143 | +}); |
| 144 | +export type WebSocketError = z.infer<typeof WebSocketError>; |
| 145 | + |
| 146 | +const ExecuteExtra = z.object({ |
| 147 | + sequenceNumber: z.number(), |
| 148 | +}); |
| 149 | +type ExecuteExtra = z.infer<typeof ExecuteExtra>; |
| 150 | + |
| 151 | +export const WSExecuteResponse = z.object({ |
| 152 | + type: z.literal(ActionType.WSExecuteResponse), |
| 153 | + success: z.boolean(), |
| 154 | + stdout: z.string(), |
| 155 | + stderr: z.string(), |
| 156 | + extra: ExecuteExtra, |
| 157 | +}); |
| 158 | +export type WSExecuteResponse = z.infer<typeof WSExecuteResponse>; |
| 159 | + |
132 | 160 | export const initializeApplication = () => createAction(ActionType.InitializeApplication); |
133 | 161 |
|
| 162 | +export const disableSyncChangesToStorage = () => createAction(ActionType.DisableSyncChangesToStorage); |
| 163 | + |
134 | 164 | const setPage = (page: Page) => |
135 | 165 | createAction(ActionType.SetPage, { page }); |
136 | 166 |
|
@@ -192,22 +222,14 @@ interface ExecuteResponseBody { |
192 | 222 | stderr: string; |
193 | 223 | } |
194 | 224 |
|
195 | | -interface ExecuteSuccess extends ExecuteResponseBody { |
196 | | - isAutoBuild: boolean; |
197 | | -} |
198 | | - |
199 | 225 | const requestExecute = () => |
200 | 226 | createAction(ActionType.ExecuteRequest); |
201 | 227 |
|
202 | | -const receiveExecuteSuccess = ({ stdout, stderr, isAutoBuild }: ExecuteSuccess) => |
203 | | - createAction(ActionType.ExecuteSucceeded, { stdout, stderr, isAutoBuild }); |
| 228 | +const receiveExecuteSuccess = ({ stdout, stderr }: ExecuteResponseBody) => |
| 229 | + createAction(ActionType.ExecuteSucceeded, { stdout, stderr }); |
204 | 230 |
|
205 | | -const receiveExecuteFailure = ({ |
206 | | - error, isAutoBuild, |
207 | | -}: { |
208 | | - error?: string, isAutoBuild: boolean, |
209 | | -}) => |
210 | | - createAction(ActionType.ExecuteFailed, { error, isAutoBuild }); |
| 231 | +const receiveExecuteFailure = ({ error }: { error?: string }) => |
| 232 | + createAction(ActionType.ExecuteFailed, { error }); |
211 | 233 |
|
212 | 234 | function jsonGet(urlObj: string | UrlObject) { |
213 | 235 | const urlStr = url.format(urlObj); |
@@ -281,18 +303,21 @@ interface ExecuteRequestBody { |
281 | 303 | } |
282 | 304 |
|
283 | 305 | const performCommonExecute = (crateType: string, tests: boolean): ThunkAction => (dispatch, getState) => { |
284 | | - dispatch(requestExecute()); |
285 | | - |
286 | 306 | const state = getState(); |
287 | 307 | const { code, configuration: { channel, mode, edition } } = state; |
288 | 308 | const backtrace = state.configuration.backtrace === Backtrace.Enabled; |
289 | | - const isAutoBuild = isAutoBuildSelector(state); |
290 | 309 |
|
291 | | - const body: ExecuteRequestBody = { channel, mode, edition, crateType, tests, code, backtrace }; |
| 310 | + if (useWebsocketSelector(state)) { |
| 311 | + return dispatch(wsExecuteRequest(channel, mode, edition, crateType, tests, code, backtrace)); |
| 312 | + } else { |
| 313 | + dispatch(requestExecute()); |
| 314 | + |
| 315 | + const body: ExecuteRequestBody = { channel, mode, edition, crateType, tests, code, backtrace }; |
292 | 316 |
|
293 | | - return jsonPost<ExecuteResponseBody>(routes.execute, body) |
294 | | - .then(json => dispatch(receiveExecuteSuccess({ ...json, isAutoBuild }))) |
295 | | - .catch(json => dispatch(receiveExecuteFailure({ ...json, isAutoBuild }))); |
| 317 | + return jsonPost<ExecuteResponseBody>(routes.execute, body) |
| 318 | + .then(json => dispatch(receiveExecuteSuccess(json))) |
| 319 | + .catch(json => dispatch(receiveExecuteFailure(json))); |
| 320 | + } |
296 | 321 | }; |
297 | 322 |
|
298 | 323 | function performAutoOnly(): ThunkAction { |
@@ -473,6 +498,32 @@ const PRIMARY_ACTIONS: { [index in PrimaryAction]: () => ThunkAction } = { |
473 | 498 | [PrimaryActionCore.Wasm]: performCompileToNightlyWasmOnly, |
474 | 499 | }; |
475 | 500 |
|
| 501 | +let sequenceNumber = 0; |
| 502 | +const nextSequenceNumber = () => sequenceNumber++; |
| 503 | +const makeExtra = (): ExecuteExtra => ({ |
| 504 | + sequenceNumber: nextSequenceNumber(), |
| 505 | +}); |
| 506 | + |
| 507 | +const wsExecuteRequest = ( |
| 508 | + channel: Channel, |
| 509 | + mode: Mode, |
| 510 | + edition: Edition, |
| 511 | + crateType: string, |
| 512 | + tests: boolean, |
| 513 | + code: string, |
| 514 | + backtrace: boolean |
| 515 | +) => |
| 516 | + createAction(ActionType.WSExecuteRequest, { |
| 517 | + channel, |
| 518 | + mode, |
| 519 | + edition, |
| 520 | + crateType, |
| 521 | + tests, |
| 522 | + code, |
| 523 | + backtrace, |
| 524 | + extra: makeExtra(), |
| 525 | + }); |
| 526 | + |
476 | 527 | export const performPrimaryAction = (): ThunkAction => (dispatch, getState) => { |
477 | 528 | const state = getState(); |
478 | 529 | const primaryAction = PRIMARY_ACTIONS[state.configuration.primaryAction]; |
@@ -810,6 +861,11 @@ export const browserWidthChanged = (isSmall: boolean) => |
810 | 861 | export const splitRatioChanged = () => |
811 | 862 | createAction(ActionType.SplitRatioChanged); |
812 | 863 |
|
| 864 | +export const websocketError = (error: string): WebSocketError => createAction(ActionType.WebSocketError, { error }); |
| 865 | +export const websocketConnected = () => createAction(ActionType.WebSocketConnected); |
| 866 | +export const websocketDisconnected = () => createAction(ActionType.WebSocketDisconnected); |
| 867 | +export const websocketFeatureFlagEnabled = () => createAction(ActionType.WebSocketFeatureFlagEnabled); |
| 868 | + |
813 | 869 | function parseChannel(s?: string): Channel | null { |
814 | 870 | switch (s) { |
815 | 871 | case 'stable': |
@@ -897,6 +953,7 @@ export function showExample(code: string): ThunkAction { |
897 | 953 |
|
898 | 954 | export type Action = |
899 | 955 | | ReturnType<typeof initializeApplication> |
| 956 | + | ReturnType<typeof disableSyncChangesToStorage> |
900 | 957 | | ReturnType<typeof setPage> |
901 | 958 | | ReturnType<typeof changePairCharacters> |
902 | 959 | | ReturnType<typeof changeAssemblyFlavor> |
@@ -962,4 +1019,10 @@ export type Action = |
962 | 1019 | | ReturnType<typeof notificationSeen> |
963 | 1020 | | ReturnType<typeof browserWidthChanged> |
964 | 1021 | | ReturnType<typeof splitRatioChanged> |
| 1022 | + | ReturnType<typeof websocketError> |
| 1023 | + | ReturnType<typeof websocketConnected> |
| 1024 | + | ReturnType<typeof websocketDisconnected> |
| 1025 | + | ReturnType<typeof websocketFeatureFlagEnabled> |
| 1026 | + | ReturnType<typeof wsExecuteRequest> |
| 1027 | + | WSExecuteResponse |
965 | 1028 | ; |
0 commit comments