forked from cerc-io/laconic-console
More logging, and service info tab.
This commit is contained in:
parent
958821b9ae
commit
99f87336c6
@ -15,6 +15,7 @@ const useStyles = makeStyles(theme => ({
|
||||
},
|
||||
|
||||
log: {
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
// Pin to bottom (render in time order).
|
||||
flexDirection: 'column-reverse',
|
||||
|
@ -12,10 +12,20 @@ import LOGS from '../gql/logs.graphql';
|
||||
import Log from './Log';
|
||||
|
||||
const MAX_LINES = 1000;
|
||||
const logBuffer = [];
|
||||
const _logBuffers = new Map();
|
||||
|
||||
const getLogBuffer = (name) => {
|
||||
let buffer = _logBuffers.get(name);
|
||||
if (!buffer) {
|
||||
buffer = [];
|
||||
_logBuffers.set(name, buffer);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
const LogPoller = ({ service }) => {
|
||||
const { config } = useContext(ConsoleContext);
|
||||
const logBuffer = getLogBuffer(service);
|
||||
const data = useQueryStatusReducer(useQuery(LOGS, {
|
||||
pollInterval: config.api.intervalLog,
|
||||
variables: { service, incremental: logBuffer.length !== 0 }
|
||||
@ -37,7 +47,7 @@ const LogPoller = ({ service }) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<Log log={logBuffer.slice(0)} />
|
||||
<Log log={logBuffer.slice(0)}/>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -22,7 +22,7 @@ import ConsoleContextProvider from './ConsoleContextProvider';
|
||||
import AppRecords from './panels/apps/Apps';
|
||||
import Bots from './panels/bots/Bots';
|
||||
import Config from './panels/Config';
|
||||
import IPFS from './panels/ipfs/IPFS';
|
||||
import IPFSStatus from './panels/ipfs/IPFS';
|
||||
import Metadata from './panels/Metadata';
|
||||
import Signaling from './panels/signal/Signaling';
|
||||
import Status from './panels/Status';
|
||||
@ -49,7 +49,7 @@ const Main = ({ config }) => {
|
||||
<Route path='/apps' component={AppRecords} />
|
||||
<Route path='/bots' component={Bots} />
|
||||
<Route path='/config' component={Config} />
|
||||
<Route path='/ipfs' component={IPFS} />
|
||||
<Route path='/ipfs' component={IPFSStatus} />
|
||||
<Route path='/metadata' component={Metadata} />
|
||||
<Route path='/signaling' component={Signaling} />
|
||||
<Route path='/status' component={Status} />
|
||||
|
@ -2,8 +2,12 @@
|
||||
// Copyright 2020 DxOS.org
|
||||
//
|
||||
|
||||
import React, { useContext } from 'react';
|
||||
import React, { useContext, useState } from 'react';
|
||||
import { useQuery } from '@apollo/react-hooks';
|
||||
import { makeStyles } from '@material-ui/core';
|
||||
import Tab from '@material-ui/core/Tab';
|
||||
import Tabs from '@material-ui/core/Tabs';
|
||||
import TabContext from '@material-ui/lab/TabContext';
|
||||
|
||||
import Json from '../../components/Json';
|
||||
|
||||
@ -14,8 +18,31 @@ import { ConsoleContext, useQueryStatusReducer } from '../../hooks';
|
||||
import Panel from '../../components/Panel';
|
||||
import Toolbar from '../../components/Toolbar';
|
||||
|
||||
const TAB_SYSTEM = 'system';
|
||||
const TAB_SERVICES = 'services';
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
expand: {
|
||||
flex: 1
|
||||
},
|
||||
|
||||
panel: {
|
||||
display: 'flex',
|
||||
overflow: 'hidden',
|
||||
flex: 1
|
||||
},
|
||||
|
||||
paper: {
|
||||
display: 'flex',
|
||||
overflow: 'hidden',
|
||||
flex: 1
|
||||
}
|
||||
}));
|
||||
|
||||
const Status = () => {
|
||||
const classes = useStyles();
|
||||
const { config } = useContext(ConsoleContext);
|
||||
const [tab, setTab] = useState(TAB_SYSTEM);
|
||||
const systemResponse = useQueryStatusReducer(useQuery(SYSTEM_STATUS, { pollInterval: config.api.intervalQuery }));
|
||||
if (!systemResponse) {
|
||||
return null;
|
||||
@ -26,10 +53,26 @@ const Status = () => {
|
||||
return (
|
||||
<Panel
|
||||
toolbar={
|
||||
<Toolbar />
|
||||
<Toolbar>
|
||||
<Tabs value={tab} onChange={(_, value) => setTab(value)}>
|
||||
<Tab value={TAB_SYSTEM} label='System'/>
|
||||
<Tab value={TAB_SERVICES} label='Services'/>
|
||||
</Tabs>
|
||||
</Toolbar>
|
||||
}
|
||||
>
|
||||
<Json data={data} />
|
||||
<TabContext value={tab}>
|
||||
{tab === TAB_SYSTEM && (
|
||||
<div className={classes.panel}>
|
||||
<Json data={data}/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{tab === TAB_SERVICES && (
|
||||
<div className={classes.panel}>
|
||||
</div>
|
||||
)}
|
||||
</TabContext>
|
||||
</Panel>
|
||||
);
|
||||
};
|
||||
|
@ -11,8 +11,10 @@ import Panel from '../../../components/Panel';
|
||||
import Toolbar from '../../../components/Toolbar';
|
||||
|
||||
import AppRecords from './AppRecords';
|
||||
import LogPoller from "../../../components/LogPoller";
|
||||
|
||||
const TAB_RECORDS = 'records';
|
||||
const TAB_LOG = 'log';
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
root: {}
|
||||
@ -29,6 +31,7 @@ const Apps = () => {
|
||||
<Toolbar>
|
||||
<Tabs value={tab} onChange={(_, value) => setTab(value)}>
|
||||
<Tab value={TAB_RECORDS} label='Records' />
|
||||
<Tab value={TAB_LOG} label='Log' />
|
||||
</Tabs>
|
||||
</Toolbar>
|
||||
}
|
||||
@ -36,6 +39,10 @@ const Apps = () => {
|
||||
{tab === TAB_RECORDS && (
|
||||
<AppRecords />
|
||||
)}
|
||||
|
||||
{tab === TAB_LOG && (
|
||||
<LogPoller service='app-server' />
|
||||
)}
|
||||
</Panel>
|
||||
);
|
||||
};
|
||||
|
@ -29,7 +29,7 @@ const AppRecords = () => {
|
||||
return null;
|
||||
}
|
||||
|
||||
const records = data.wns_records.json;
|
||||
const records = JSON.parse(data.wns_records.json);
|
||||
|
||||
return (
|
||||
<Table>
|
||||
|
@ -3,122 +3,44 @@
|
||||
//
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import get from 'lodash.get';
|
||||
|
||||
import { useQuery } from '@apollo/react-hooks';
|
||||
import { makeStyles } from '@material-ui/core';
|
||||
import Paper from '@material-ui/core/Paper';
|
||||
import Tab from '@material-ui/core/Tab';
|
||||
import Tabs from '@material-ui/core/Tabs';
|
||||
import TableBody from '@material-ui/core/TableBody';
|
||||
import TableHead from '@material-ui/core/TableHead';
|
||||
import TableRow from '@material-ui/core/TableRow';
|
||||
import TabContext from '@material-ui/lab/TabContext';
|
||||
|
||||
import IPFS_STATUS from '../../../gql/ipfs_status.graphql';
|
||||
import WNS_RECORDS from '../../../gql/wns_records.graphql';
|
||||
|
||||
import { useQueryStatusReducer } from '../../../hooks';
|
||||
|
||||
import Json from '../../../components/Json';
|
||||
import Panel from '../../../components/Panel';
|
||||
import Table from '../../../components/Table';
|
||||
import TableCell from '../../../components/TableCell';
|
||||
import Toolbar from '../../../components/Toolbar';
|
||||
import { BooleanIcon } from '../../../components/BooleanIcon';
|
||||
|
||||
const RECORD_TYPE = 'wrn:service';
|
||||
const SERVICE_TYPE = 'ipfs';
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
tableContainer: {
|
||||
flex: 1,
|
||||
overflowY: 'scroll'
|
||||
},
|
||||
|
||||
table: {
|
||||
tableLayout: 'fixed',
|
||||
|
||||
'& th': {
|
||||
fontVariant: 'all-small-caps',
|
||||
fontSize: 18,
|
||||
cursor: 'ns-resize'
|
||||
}
|
||||
},
|
||||
|
||||
connected: {
|
||||
fontWeight: 'bold'
|
||||
},
|
||||
|
||||
disconnected: {
|
||||
fontStyle: 'italic'
|
||||
},
|
||||
|
||||
colShort: {
|
||||
width: '30%'
|
||||
},
|
||||
|
||||
colWide: {},
|
||||
|
||||
colBoolean: {
|
||||
width: '10%'
|
||||
},
|
||||
|
||||
caption: {
|
||||
backgroundColor: theme.palette.primary[500],
|
||||
color: theme.palette.primary.contrastText,
|
||||
paddingLeft: '1em',
|
||||
margin: 0
|
||||
}
|
||||
}));
|
||||
import LogPoller from '../../../components/LogPoller';
|
||||
import IPFSStatus from './IPFSStatus';
|
||||
|
||||
const TAB_STATUS = 'status';
|
||||
const TAB_LOG = 'log';
|
||||
const TAB_SWARM_LOG = 'swarm';
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
expand: {
|
||||
flex: 1
|
||||
},
|
||||
|
||||
panel: {
|
||||
display: 'flex',
|
||||
overflow: 'hidden',
|
||||
flex: 1
|
||||
},
|
||||
|
||||
paper: {
|
||||
display: 'flex',
|
||||
overflow: 'hidden',
|
||||
flex: 1
|
||||
}
|
||||
}));
|
||||
|
||||
const IPFS = () => {
|
||||
const classes = useStyles();
|
||||
const [tab, setTab] = useState(TAB_STATUS);
|
||||
|
||||
const ipfsResponse = useQueryStatusReducer(useQuery(IPFS_STATUS));
|
||||
const wnsResponse = useQueryStatusReducer(useQuery(WNS_RECORDS, {
|
||||
variables: { attributes: { type: RECORD_TYPE, service: SERVICE_TYPE } }
|
||||
}));
|
||||
|
||||
if (!wnsResponse || !ipfsResponse) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const ipfsData = JSON.parse(ipfsResponse.ipfs_status.json);
|
||||
const registeredServers = JSON.parse(wnsResponse.wns_records.json);
|
||||
|
||||
const displayServers = registeredServers.map((service) => {
|
||||
console.error(service);
|
||||
const addresses = get(service, 'attributes.ipfs.addresses');
|
||||
let connected = false;
|
||||
for (const address of addresses) {
|
||||
const parts = address.split('/');
|
||||
const nodeId = parts[parts.length - 1];
|
||||
connected = !!ipfsData.swarm.peers.find(({ peer }) => peer === nodeId);
|
||||
if (connected) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
name: get(service, 'name'),
|
||||
version: get(service, 'version'),
|
||||
description: get(service, 'attributes.description'),
|
||||
ipfs: get(service, 'attributes.ipfs'),
|
||||
connected
|
||||
};
|
||||
});
|
||||
|
||||
displayServers.sort((a, b) => {
|
||||
return a.connected && !b.connected ? -1 : b.connected && !a.connected ? 1 : b.name < a.name ? 1 : -1;
|
||||
});
|
||||
|
||||
if (displayServers.length === 0) {
|
||||
displayServers.push({ name: 'None' });
|
||||
}
|
||||
|
||||
return (
|
||||
<Panel
|
||||
toolbar={
|
||||
@ -126,46 +48,32 @@ const IPFS = () => {
|
||||
<Tabs value={tab} onChange={(_, value) => setTab(value)}>
|
||||
<Tab value={TAB_STATUS} label='Status' />
|
||||
<Tab value={TAB_LOG} label='Log' />
|
||||
<Tab value={TAB_SWARM_LOG} label='Connection Log' />
|
||||
</Tabs>
|
||||
</Toolbar>
|
||||
}
|
||||
>
|
||||
<h4 className={classes.caption}>WNS-registered IPFS Servers</h4>
|
||||
<Table stickyHeader size='small' className={classes.table}>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>Identifier</TableCell>
|
||||
<TableCell size='medium'>Description</TableCell>
|
||||
<TableCell size='icon'>Connected</TableCell>
|
||||
<TableCell>Address</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{displayServers.map(({ name, description, ipfs, connected }) => (
|
||||
<TableRow key={name}>
|
||||
<TableCell>{name}</TableCell>
|
||||
<TableCell>{description}</TableCell>
|
||||
<TableCell>
|
||||
<BooleanIcon yes={connected} />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{ipfs.addresses}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<TabContext value={tab}>
|
||||
{tab === TAB_STATUS && (
|
||||
<div className={classes.panel}>
|
||||
<Paper className={classes.paper}>
|
||||
<IPFSStatus />
|
||||
</Paper>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<h4 className={classes.caption}>Local IPFS Server</h4>
|
||||
<Json data={{
|
||||
id: ipfsData.id.id,
|
||||
version: ipfsData.id.agentVersion,
|
||||
addresses: ipfsData.id.addresses,
|
||||
peers: ipfsData.swarm.peers.length,
|
||||
numObjects: ipfsData.repo.stats.numObjects,
|
||||
repoSize: ipfsData.repo.stats.repoSize
|
||||
}}
|
||||
/>
|
||||
{tab === TAB_LOG && (
|
||||
<div className={classes.panel}>
|
||||
<LogPoller service='ipfs' />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{tab === TAB_SWARM_LOG && (
|
||||
<div className={classes.panel}>
|
||||
<LogPoller service='ipfs-swarm-connect' />
|
||||
</div>
|
||||
)}
|
||||
</TabContext>
|
||||
</Panel>
|
||||
);
|
||||
};
|
||||
|
165
packages/console-app/src/containers/panels/ipfs/IPFSStatus.js
Normal file
165
packages/console-app/src/containers/panels/ipfs/IPFSStatus.js
Normal file
@ -0,0 +1,165 @@
|
||||
//
|
||||
// Copyright 2020 DxOS.org
|
||||
//
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import get from 'lodash.get';
|
||||
|
||||
import { useQuery } from '@apollo/react-hooks';
|
||||
import { makeStyles } from '@material-ui/core';
|
||||
import Tab from '@material-ui/core/Tab';
|
||||
import Tabs from '@material-ui/core/Tabs';
|
||||
import TableBody from '@material-ui/core/TableBody';
|
||||
import TableHead from '@material-ui/core/TableHead';
|
||||
import TableRow from '@material-ui/core/TableRow';
|
||||
|
||||
import IPFS_STATUS from '../../../gql/ipfs_status.graphql';
|
||||
import WNS_RECORDS from '../../../gql/wns_records.graphql';
|
||||
|
||||
import { useQueryStatusReducer } from '../../../hooks';
|
||||
|
||||
import Json from '../../../components/Json';
|
||||
import Panel from '../../../components/Panel';
|
||||
import Table from '../../../components/Table';
|
||||
import TableCell from '../../../components/TableCell';
|
||||
import Toolbar from '../../../components/Toolbar';
|
||||
import { BooleanIcon } from '../../../components/BooleanIcon';
|
||||
|
||||
const RECORD_TYPE = 'wrn:service';
|
||||
const SERVICE_TYPE = 'ipfs';
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
tableContainer: {
|
||||
flex: 1,
|
||||
overflowY: 'scroll'
|
||||
},
|
||||
|
||||
table: {
|
||||
tableLayout: 'fixed',
|
||||
|
||||
'& th': {
|
||||
fontVariant: 'all-small-caps',
|
||||
fontSize: 18,
|
||||
cursor: 'ns-resize'
|
||||
}
|
||||
},
|
||||
|
||||
connected: {
|
||||
fontWeight: 'bold'
|
||||
},
|
||||
|
||||
disconnected: {
|
||||
fontStyle: 'italic'
|
||||
},
|
||||
|
||||
colShort: {
|
||||
width: '30%'
|
||||
},
|
||||
|
||||
colWide: {},
|
||||
|
||||
colBoolean: {
|
||||
width: '10%'
|
||||
},
|
||||
|
||||
caption: {
|
||||
backgroundColor: theme.palette.primary[500],
|
||||
color: theme.palette.primary.contrastText,
|
||||
paddingLeft: '1em',
|
||||
margin: 0
|
||||
}
|
||||
}));
|
||||
|
||||
const TAB_STATUS = 'status';
|
||||
const TAB_LOG_IPFS = 'log';
|
||||
const TAB_LOG_SWARM = 'connect log';
|
||||
|
||||
const IPFSStatus = () => {
|
||||
const classes = useStyles();
|
||||
const [tab, setTab] = useState(TAB_STATUS);
|
||||
|
||||
const ipfsResponse = useQueryStatusReducer(useQuery(IPFS_STATUS));
|
||||
const wnsResponse = useQueryStatusReducer(useQuery(WNS_RECORDS, {
|
||||
variables: { attributes: { type: RECORD_TYPE, service: SERVICE_TYPE } }
|
||||
}));
|
||||
|
||||
if (!wnsResponse || !ipfsResponse) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const ipfsData = JSON.parse(ipfsResponse.ipfs_status.json);
|
||||
const registeredServers = JSON.parse(wnsResponse.wns_records.json);
|
||||
|
||||
const displayServers = registeredServers.map((service) => {
|
||||
console.error(service);
|
||||
const addresses = get(service, 'attributes.ipfs.addresses');
|
||||
let connected = false;
|
||||
for (const address of addresses) {
|
||||
const parts = address.split('/');
|
||||
const nodeId = parts[parts.length - 1];
|
||||
connected = !!ipfsData.swarm.peers.find(({ peer }) => peer === nodeId);
|
||||
if (connected) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
name: get(service, 'name'),
|
||||
version: get(service, 'version'),
|
||||
description: get(service, 'attributes.description'),
|
||||
ipfs: get(service, 'attributes.ipfs'),
|
||||
connected
|
||||
};
|
||||
});
|
||||
|
||||
displayServers.sort((a, b) => {
|
||||
return a.connected && !b.connected ? -1 : b.connected && !a.connected ? 1 : b.name < a.name ? 1 : -1;
|
||||
});
|
||||
|
||||
if (displayServers.length === 0) {
|
||||
displayServers.push({ name: 'None' });
|
||||
}
|
||||
|
||||
return (
|
||||
<Panel>
|
||||
<h4 className={classes.caption}>WNS-registered IPFS Servers</h4>
|
||||
<Table stickyHeader size='small' className={classes.table}>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>Identifier</TableCell>
|
||||
<TableCell size='medium'>Description</TableCell>
|
||||
<TableCell size='icon'>Connected</TableCell>
|
||||
<TableCell>Address</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{displayServers.map(({ name, description, ipfs, connected }) => (
|
||||
<TableRow key={name}>
|
||||
<TableCell>{name}</TableCell>
|
||||
<TableCell>{description}</TableCell>
|
||||
<TableCell>
|
||||
<BooleanIcon yes={connected}/>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{ipfs.addresses}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
||||
<h4 className={classes.caption}>Local IPFS Server</h4>
|
||||
<Json data={{
|
||||
id: ipfsData.id.id,
|
||||
version: ipfsData.id.agentVersion,
|
||||
addresses: ipfsData.id.addresses,
|
||||
peers: ipfsData.swarm.peers.length,
|
||||
numObjects: ipfsData.repo.stats.numObjects,
|
||||
repoSize: ipfsData.repo.stats.repoSize
|
||||
}}
|
||||
/>
|
||||
</Panel>
|
||||
);
|
||||
};
|
||||
|
||||
export default IPFSStatus;
|
@ -8,3 +8,10 @@ query {
|
||||
json
|
||||
}
|
||||
}
|
||||
|
||||
query {
|
||||
service_status {
|
||||
timestamp,
|
||||
json
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ type Query {
|
||||
app_status: JSONResult!
|
||||
ipfs_status: JSONResult!
|
||||
ipfs_swarm_status: JSONResult!
|
||||
service_status: JSONResult!
|
||||
signal_status: JSONResult!
|
||||
system_status: JSONResult!
|
||||
wns_status: JSONResult!
|
||||
|
@ -6,6 +6,7 @@ import moment from 'moment';
|
||||
import pick from 'lodash.pick';
|
||||
import os from 'os';
|
||||
import si from 'systeminformation';
|
||||
import { spawnSync } from "child_process";
|
||||
|
||||
const num = new Intl.NumberFormat('en', { maximumSignificantDigits: 3 });
|
||||
|
||||
@ -77,6 +78,18 @@ const getSystemInfo = async () => {
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Get system inforamtion.
|
||||
* https://www.npmjs.com/package/systeminformation
|
||||
*/
|
||||
const getServiceInfo = async () => {
|
||||
const command = 'wire';
|
||||
const args = ['service', '--json'];
|
||||
|
||||
const child = spawnSync(command, args, { encoding: 'utf8' });
|
||||
return child.stdout;
|
||||
}
|
||||
|
||||
export const systemResolvers = {
|
||||
Query: {
|
||||
system_status: async () => {
|
||||
@ -86,6 +99,14 @@ export const systemResolvers = {
|
||||
timestamp: new Date().toUTCString(),
|
||||
json: JSON.stringify(system)
|
||||
};
|
||||
}
|
||||
},
|
||||
service_status: async () => {
|
||||
const serviceInfo = await getServiceInfo();
|
||||
|
||||
return {
|
||||
timestamp: new Date().toUTCString(),
|
||||
json: JSON.stringify(serviceInfo)
|
||||
};
|
||||
},
|
||||
}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user