//
// Copyright 2020 DXOS.org
//
import React, { useContext, useRef, useEffect, useState, useCallback } from 'react';
import { useQuery } from '@apollo/react-hooks';
import useComponentSize from '@rehooks/component-size';
import moment from 'moment';
import get from 'lodash.get';
import Grid from '@material-ui/core/Grid';
import TableBody from '@material-ui/core/TableBody';
import TableContainer from '@material-ui/core/TableContainer';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import { makeStyles } from '@material-ui/core/styles';
import Table from '../../../components/Table';
import TableCell from '../../../components/TableCell';
import NetworkGraph from '../../../components/NetworkGraph';
import SIGNAL_STATUS from '../../../gql/signal_status.graphql';
import { ConsoleContext, useQueryStatusReducer } from '../../../hooks';
const NODE_ID_LENGTH = 8;
const buildDataGraph = (rootId, prevGraph, nodes) => {
const newGraph = { nodes: [], links: [] };
const rootNode = nodes.find(n => n.id === rootId);
nodes.forEach(node => {
let type = 'detach';
if (rootId === node.id) {
type = 'root';
} else {
const isAdjacent = rootNode.connections.find(conn => conn.target === node.id) || node.connections.find(conn => conn.target === rootId);
if (isAdjacent) {
type = 'adjacent';
}
}
const hostname = get(node, 'kubeStatus.system.network.hostname');
const shortId = node.id.slice(0, NODE_ID_LENGTH).toUpperCase();
const label = hostname || shortId;
const oldNode = prevGraph.nodes.find(n => n.id === node.id) || {};
const newNode = { ...oldNode, id: node.id, label, type, data: node };
if (type === 'root') {
newNode.fx = 0;
newNode.fy = 0;
}
newGraph.nodes.push(newNode);
});
nodes.forEach(node => {
node.connections.forEach(conn => {
newGraph.links.push({ id: conn.id, source: node.id, target: conn.target });
});
});
return newGraph;
};
const useDataGraph = (response) => {
const [dataGraph, setDataGraph] = useState({ updatedAt: 0, nodes: [], links: [] });
useEffect(() => {
if (!response) return;
const { id: rootId, nodes = [] } = response.signal_status;
const updatedAt = moment(response.signal_status.updatedAt).valueOf();
if (dataGraph.updatedAt >= updatedAt) return;
const graph = buildDataGraph(rootId, dataGraph, nodes);
setDataGraph({
updatedAt,
...graph
});
}, [response && response.signal_status.updatedAt]);
return dataGraph;
};
const useRowStyles = makeStyles({
root: {
'& > *': {
borderBottom: 'unset'
}
}
});
function Row (props) {
const { row } = props;
const classes = useRowStyles();
const system = row.kubeStatus.system;
return (
<>
{row.id.slice(0, NODE_ID_LENGTH).toUpperCase()}
{system?.network?.hostname}
{row.signal.topics.reduce((prev, curr) => prev + curr.peers.length, 0)}
{system?.version || '-'}
{system?.memory?.used || '-'}
{system?.memory?.total || '-'}
{system?.time?.up ? moment(system?.time?.up).format('lll') : '-'}
>
);
}
function SignalServers () {
const { config } = useContext(ConsoleContext);
const { data: response } = useQueryStatusReducer(useQuery(SIGNAL_STATUS, { fetchPolicy: 'no-cache', pollInterval: config.api.pollInterval, context: { api: 'signal' } }));
const data = useDataGraph(response);
const sizeRef = useRef(null);
const { width, height } = useComponentSize(sizeRef);
const [open, setOpen] = useState(null);
const handleOpen = useCallback(
(id) => {
if (open && open === id) {
setOpen(null);
} else {
setOpen(id);
}
},
[open]
);
return (
{
return (
<>
WebRTC Peers: {node.signal.topics.reduce((prev, curr) => prev + curr.peers.length, 0)}
{node.kubeStatus.services.map((service) => {
return {service.name}: {service.status}
;
})}
>);
}}
/>
ID
Hostname
Peers (WebRTC)
Kube version
Memory usage
Memory total
Uptime
{data && data.nodes.map(({ data }) => {
return
;
})}
);
}
export default SignalServers;