1.6 KB66 lines
Blame
1/**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8import {useEffect, useState} from 'react';
9import {randomId} from 'shared/utils';
10import clientToServerAPI from './ClientToServerAPI';
11
12export type Heartbeat =
13 | {
14 type: 'waiting';
15 }
16 | {
17 type: 'timeout';
18 }
19 | {
20 type: 'success' | 'slow';
21 /** Round trip time between sending the heartbeat and getting the response */
22 rtt: number;
23 };
24
25export const DEFAULT_HEARTBEAT_TIMEOUT_MS = 1500;
26
27/**
28 * Ping the server
29 */
30export function useHeartbeat(timeoutMs = DEFAULT_HEARTBEAT_TIMEOUT_MS) {
31 const [state, setState] = useState<Heartbeat>({type: 'waiting'});
32
33 useEffect(() => {
34 const id = randomId();
35 const start = Date.now();
36 clientToServerAPI.postMessage({type: 'heartbeat', id});
37 clientToServerAPI
38 .nextMessageMatching('heartbeat', message => message.id === id)
39 .then(() => {
40 setState(val => {
41 if (val.type === 'waiting') {
42 return {type: 'success', rtt: Date.now() - start};
43 } else if (val.type === 'timeout') {
44 return {type: 'slow', rtt: Date.now() - start};
45 }
46 return val;
47 });
48 });
49
50 const timeout = setTimeout(() => {
51 setTimeout(() => {
52 setState(val => {
53 if (val.type === 'waiting') {
54 return {type: 'timeout'};
55 }
56 return val;
57 });
58 });
59 }, timeoutMs);
60
61 return () => clearTimeout(timeout);
62 }, [setState, timeoutMs]);
63
64 return state;
65}
66