feat: implement naive client ping

This commit is contained in:
Carlos Valente
2024-11-17 13:57:34 +01:00
committed by Carlos Valente
parent d87542dcf7
commit 8dd448db44
8 changed files with 74 additions and 7 deletions
@@ -230,3 +230,11 @@ export const useTimelineStatus = () => {
return useRuntimeStore(featureSelector); return useRuntimeStore(featureSelector);
}; };
export const usePing = () => {
const featureSelector = (state: RuntimeStore) => ({
ping: state.ping,
});
return useRuntimeStore(featureSelector);
};
+17 -3
View File
@@ -1,9 +1,17 @@
import { Log, RundownCached, RuntimeStore } from 'ontime-types'; import { Log, RundownCached, RuntimeStore } from 'ontime-types';
import { isProduction, websocketUrl } from '../../externals'; import { isProduction, websocketUrl } from '../../externals';
import { CLIENT_LIST, CUSTOM_FIELDS, RUNDOWN, RUNTIME } from '../api/constants';
import { invalidateAllCaches } from '../api/utils'; import { invalidateAllCaches } from '../api/utils';
import { ontimeQueryClient } from '../queryClient'; import { ontimeQueryClient } from '../queryClient';
import { getClientId, getClientName, setClientId, setClientName, setClients } from '../stores/clientStore'; import {
getClientId,
getClientName,
setClientId,
setClientName,
setClientRedirect,
setClients,
} from '../stores/clientStore';
import { addLog } from '../stores/logger'; import { addLog } from '../stores/logger';
import { patchRuntime, runtimeStore } from '../stores/runtime'; import { patchRuntime, runtimeStore } from '../stores/runtime';
@@ -62,6 +70,12 @@ export const connectSocket = () => {
} }
switch (type) { switch (type) {
case 'pong': {
const offset = (new Date().getTime() - new Date(payload).getTime()) * 0.5;
patchRuntime('ping', offset);
updateDevTools({ ping: offset }, ['PING']);
break;
}
case 'client-id': { case 'client-id': {
if (typeof payload === 'string') { if (typeof payload === 'string') {
setClientId(payload); setClientId(payload);
@@ -210,9 +224,9 @@ export const socketSendJson = (type: string, payload?: unknown) => {
); );
}; };
function updateDevTools(newData: Partial<RuntimeStore>) { function updateDevTools(newData: Partial<RuntimeStore>, store = RUNTIME) {
if (!isProduction) { if (!isProduction) {
ontimeQueryClient.setQueryData(RUNTIME, (oldData: RuntimeStore) => ({ ontimeQueryClient.setQueryData(store, (oldData: RuntimeStore) => ({
...oldData, ...oldData,
...newData, ...newData,
})); }));
@@ -3,7 +3,7 @@ import { IoArrowUp } from '@react-icons/all-files/io5/IoArrowUp';
import CopyTag from '../../../../common/components/copy-tag/CopyTag'; import CopyTag from '../../../../common/components/copy-tag/CopyTag';
import useInfo from '../../../../common/hooks-query/useInfo'; import useInfo from '../../../../common/hooks-query/useInfo';
import { openLink } from '../../../../common/utils/linkUtils'; import { openLink } from '../../../../common/utils/linkUtils';
import { serverPort } from '../../../../externals'; import { isLocalhost, serverPort } from '../../../../externals';
import style from './NetworkInterfaces.module.scss'; import style from './NetworkInterfaces.module.scss';
@@ -14,9 +14,11 @@ export default function InfoNif() {
return ( return (
<div className={style.interfaces}> <div className={style.interfaces}>
{data?.networkInterfaces?.map((nif) => { {data.networkInterfaces?.map((nif) => {
const address = `http://${nif.address}:${serverPort}`; // interfaces outside localhost wont have access
if (nif.name === 'localhost' && !isLocalhost) return null;
const address = `http://${nif.address}:${serverPort}`;
return ( return (
<CopyTag <CopyTag
key={nif.name} key={nif.name}
@@ -1,4 +1,8 @@
import { useEffect } from 'react';
import useScrollIntoView from '../../../../common/hooks/useScrollIntoView'; import useScrollIntoView from '../../../../common/hooks/useScrollIntoView';
import { usePing } from '../../../../common/hooks/useSocket';
import { socketSendJson } from '../../../../common/utils/socket';
import { isOntimeCloud } from '../../../../externals'; import { isOntimeCloud } from '../../../../externals';
import type { PanelBaseProps } from '../../panel-list/PanelList'; import type { PanelBaseProps } from '../../panel-list/PanelList';
import * as Panel from '../../panel-utils/PanelUtils'; import * as Panel from '../../panel-utils/PanelUtils';
@@ -15,7 +19,7 @@ export default function NetworkLogPanel({ location }: PanelBaseProps) {
<> <>
<Panel.Header>Network</Panel.Header> <Panel.Header>Network</Panel.Header>
<Panel.Section> <Panel.Section>
{isOntimeCloud && <Panel.SubHeader>Ontime cloud</Panel.SubHeader>} {isOntimeCloud && <OntimeCloudStats />}
<Panel.Paragraph>Ontime is streaming on the following network interfaces</Panel.Paragraph> <Panel.Paragraph>Ontime is streaming on the following network interfaces</Panel.Paragraph>
</Panel.Section> </Panel.Section>
<InfoNif /> <InfoNif />
@@ -28,3 +32,29 @@ export default function NetworkLogPanel({ location }: PanelBaseProps) {
</> </>
); );
} }
function OntimeCloudStats() {
const { ping } = usePing();
/**
* Send immediate ping request, and keep sending on an interval
*/
useEffect(() => {
socketSendJson('ping', new Date());
const doPing = setInterval(() => {
socketSendJson('ping', new Date());
}, 5000);
return () => {
clearInterval(doPing);
};
}, []);
return (
<Panel.SubHeader>
Ontime cloud
<Panel.Description>Current ping: {ping}ms</Panel.Description>
</Panel.SubHeader>
);
}
@@ -100,6 +100,16 @@ export class SocketServer implements IAdapter {
const message = JSON.parse(data); const message = JSON.parse(data);
const { type, payload } = message; const { type, payload } = message;
if (type === 'ping') {
ws.send(
JSON.stringify({
type: 'pong',
payload,
}),
);
return;
}
if (type === 'get-client-name') { if (type === 'get-client-name') {
ws.send( ws.send(
JSON.stringify({ JSON.stringify({
+1
View File
@@ -188,6 +188,7 @@ export const startServer = async (
direction: SimpleDirection.CountDown, direction: SimpleDirection.CountDown,
}, },
frozen: false, frozen: false,
ping: -1,
}); });
// initialise logging service, escalateErrorFn is only exists in electron // initialise logging service, escalateErrorFn is only exists in electron
@@ -52,4 +52,5 @@ export const runtimeStorePlaceholder: RuntimeStore = {
playback: SimplePlayback.Stop, playback: SimplePlayback.Stop,
}, },
frozen: false, frozen: false,
ping: -1,
}; };
@@ -27,4 +27,5 @@ export type RuntimeStore = {
// flags // flags
frozen: boolean; frozen: boolean;
ping: number;
}; };