Skip to content
This repository was archived by the owner on Apr 2, 2024. It is now read-only.

Commit 61a7b1a

Browse files
authored
Add ping pong mechanic to websocket service to keep connection healthy (#253)
* Add ping pong mechanic to websocket service to keep connection healthy * Add divider into custom-example auto field loader * Change WS_PING_INTERVAL_IN_SECONDS to actual seconds
1 parent 00bb233 commit 61a7b1a

File tree

3 files changed

+32
-19
lines changed

3 files changed

+32
-19
lines changed

src/custom-example/uniforms/AutoFieldLoader.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
AcceptField,
33
BoolField,
44
DateField,
5+
DividerField,
56
LabelField,
67
ListField,
78
LocationCodeField,
@@ -49,6 +50,8 @@ export function autoFieldFunction(props: GuaranteedProps<unknown> & Record<strin
4950
return LongTextField;
5051
case "label":
5152
return LabelField;
53+
case "divider":
54+
return DividerField;
5255
case "summary":
5356
return SummaryField;
5457
case "subscription":

src/env.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ interface Env {
3333
GITLAB_URL: string;
3434
CI_PROJECT_PATH: string;
3535
LOCALE: string;
36+
WS_PING_INTERVAL_IN_SECONDS: number;
3637
}
3738

3839
// We normally load env from window.__env__ as defined in public/env.js which
@@ -63,4 +64,5 @@ export const ENV: Env = window.__env__ || {
6364
GITLAB_URL: process.env.REACT_APP_GITLAB_URL,
6465
CI_PROJECT_PATH: process.env.REACT_APP_CI_PROJECT_PATH,
6566
LOCALE: process.env.REACT_APP_LOCALE || "en-GB",
67+
WS_PING_INTERVAL_IN_SECONDS: parseInt(process.env.WS_PING_INTERVAL_IN_SECONDS || "30"),
6668
};

src/websocketService/index.ts

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,10 @@
1-
/*
2-
* Copyright 2019-2023 SURF.
3-
* Licensed under the Apache License, Version 2.0 (the "License");
4-
* you may not use this file except in compliance with the License.
5-
* You may obtain a copy of the License at
6-
* http://www.apache.org/licenses/LICENSE-2.0
7-
*
8-
* Unless required by applicable law or agreed to in writing, software
9-
* distributed under the License is distributed on an "AS IS" BASIS,
10-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11-
* See the License for the specific language governing permissions and
12-
* limitations under the License.
13-
*
14-
*/
15-
161
import { useAuth } from "oidc-react";
172
import { useEffect, useState } from "react";
183
import useWebSocket, { Options, ReadyState } from "react-use-websocket";
194

205
import { ENV } from "../env";
216

227
const isSecure = !!ENV.BACKEND_URL.includes("https");
23-
248
const wsProtocol = isSecure ? "wss" : "ws";
259
const websocketUrl = `${wsProtocol}${ENV.BACKEND_URL.replace(/(^\w+|^)/, "")}`;
2610

@@ -30,6 +14,9 @@ export interface SurfWebSocket<T> {
3014
useFallback: boolean;
3115
}
3216

17+
const pingMessage = "__ping__";
18+
const pingintervalInMilliseconds = ENV.WS_PING_INTERVAL_IN_SECONDS * 1000;
19+
3320
const websocketSettings: Options = {
3421
retryOnError: true,
3522
reconnectAttempts: 10,
@@ -46,7 +33,7 @@ const useWebsocketServiceWithAuth = <T extends object>(endpoint: string): SurfWe
4633
const baseUrl = `${websocketUrl}/${endpoint}?token=`;
4734
const [url, setUrl] = useState<string>("");
4835

49-
const { lastJsonMessage, readyState } = useWebSocket(url, websocketSettings, !!url);
36+
const { lastJsonMessage, readyState, sendMessage, lastMessage } = useWebSocket(url, websocketSettings, !!url);
5037
const [useFallback, setUsefallback] = useState<boolean>(false);
5138

5239
useEffect(() => {
@@ -57,23 +44,44 @@ const useWebsocketServiceWithAuth = <T extends object>(endpoint: string): SurfWe
5744
setUrl(`${baseUrl}${auth.userData?.access_token}`);
5845
}, [baseUrl, auth.userData?.access_token]);
5946

47+
useEffect(() => {
48+
const pingInterval = setInterval(() => sendMessage(pingMessage), pingintervalInMilliseconds);
49+
return () => clearInterval(pingInterval);
50+
}, [sendMessage]);
51+
52+
useEffect(() => {
53+
if (lastMessage && lastMessage.data === "__pong__") {
54+
// handle pong...
55+
}
56+
}, [lastMessage]);
57+
6058
return { lastMessage: lastJsonMessage, readyState, useFallback };
6159
};
6260

6361
const useWebsocketServiceWithoutAuth = <T extends object>(endpoint: string): SurfWebSocket<T> => {
6462
const baseUrl = `${websocketUrl}/${endpoint}?token=`;
65-
const { lastJsonMessage, readyState } = useWebSocket(baseUrl, websocketSettings);
63+
const { lastJsonMessage, readyState, sendMessage, lastMessage } = useWebSocket(baseUrl, websocketSettings);
6664
const [useFallback, setUsefallback] = useState<boolean>(false);
6765

6866
useEffect(() => {
69-
console.log(readyState);
7067
if (readyState === ReadyState.CLOSED) {
7168
setUsefallback(true);
7269
} else {
7370
setUsefallback(false);
7471
}
7572
}, [readyState]);
7673

74+
useEffect(() => {
75+
const pingInterval = setInterval(() => sendMessage(pingMessage), pingintervalInMilliseconds);
76+
return () => clearInterval(pingInterval);
77+
}, [sendMessage]);
78+
79+
useEffect(() => {
80+
if (lastMessage && lastMessage.data === "__pong__") {
81+
// handle pong...
82+
}
83+
}, [lastMessage]);
84+
7785
return { lastMessage: lastJsonMessage, readyState, useFallback };
7886
};
7987

0 commit comments

Comments
 (0)