mirror of
https://github.com/pezkuwichain/pezkuwi-telemetry.git
synced 2026-04-22 02:08:04 +00:00
Feat: Map Node Stats (Version, Operating System etc) to each Node in Feed (#591)
* added functionality for specifying node details per each node * Backend done Added new item in Ranking node_map, mapping node id to node detail Co-authored-by: Cyndie Kamau <cyndiekamaa@gmail.com> * feat: last frontend working version * chore: Clean up unused code * fix(frontend): update node details to carry 10 fields * chore: remove unnecessary code * chore: run cargo fmt for formatting * chore: run prettier to format frontend * fixed e2e tests added missing struct params * remoted .idea file * Hide new columns by default, default to - if no data, and remove .idea folder --------- Co-authored-by: MrishoLukamba <abdulrazzaqlukamba@gmail.com> Co-authored-by: Cyndie Kamau <cyndiekamaa@gmail.com>
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
||||
# See https://help.github.com/ignore-files/ for more about ignoring files.
|
||||
htdocs
|
||||
|
||||
.idea
|
||||
backend/target
|
||||
|
||||
# dependencies
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
target
|
||||
*.Dockerfile
|
||||
.git
|
||||
.idea
|
||||
@@ -69,7 +69,7 @@ pub enum FromShardWebsocket {
|
||||
Disconnected,
|
||||
}
|
||||
|
||||
/// The aggregator can these messages back to a shard connection.
|
||||
/// The aggregator can send these messages back to a shard connection.
|
||||
#[derive(Debug)]
|
||||
pub enum ToShardWebsocket {
|
||||
/// Mute messages to the core by passing the shard-local ID of them.
|
||||
@@ -84,7 +84,7 @@ pub enum ToShardWebsocket {
|
||||
pub enum FromFeedWebsocket {
|
||||
/// When the socket is opened, it'll send this first
|
||||
/// so that we have a way to communicate back to it.
|
||||
/// Unbounded so that slow feeds don't block aggregato
|
||||
/// Unbounded so that slow feeds don't block aggregator
|
||||
/// progress.
|
||||
Initialize {
|
||||
channel: flume::Sender<ToFeedWebsocket>,
|
||||
|
||||
@@ -183,12 +183,18 @@ impl FeedMessageWrite for AddedNode<'_> {
|
||||
let AddedNode(nid, node, expose_node_details) = self;
|
||||
|
||||
let details = node.details();
|
||||
// Hide the ip, sysinfo and hwbench if the `expose_node_details` flag was not specified.
|
||||
// Always include sysinfo, conditionally include ip and hwbench based on expose_node_details.
|
||||
let node_hwbench = node.hwbench();
|
||||
let (ip, sys_info, hwbench) = if *expose_node_details {
|
||||
(&details.ip, &details.sysinfo, &node_hwbench)
|
||||
let ip = if *expose_node_details {
|
||||
&details.ip
|
||||
} else {
|
||||
(&None, &None, &None)
|
||||
&None
|
||||
};
|
||||
let sys_info = &details.sysinfo;
|
||||
let hwbench = if *expose_node_details {
|
||||
&node_hwbench
|
||||
} else {
|
||||
&None
|
||||
};
|
||||
|
||||
let details = (
|
||||
@@ -197,6 +203,9 @@ impl FeedMessageWrite for AddedNode<'_> {
|
||||
&details.version,
|
||||
&details.validator,
|
||||
&details.network_id,
|
||||
&details.target_os,
|
||||
&details.target_arch,
|
||||
&details.target_env,
|
||||
&ip,
|
||||
&sys_info,
|
||||
&hwbench,
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
use super::counter::{Counter, CounterValue};
|
||||
use crate::feed_message::ChainStats;
|
||||
|
||||
// These are the benchmark scores generated on our reference hardware.
|
||||
const REFERENCE_CPU_SCORE: u64 = 1028;
|
||||
const REFERENCE_MEMORY_SCORE: u64 = 14899;
|
||||
|
||||
@@ -39,7 +39,7 @@ impl<K> Counter<K>
|
||||
where
|
||||
K: Sized + std::hash::Hash + Eq,
|
||||
{
|
||||
/// Either adds or removes a single occurrence of a given `key`.
|
||||
/// Either adds or removes a single occurence of a given `key`.
|
||||
pub fn modify<'a, Q>(&mut self, key: Option<&'a Q>, op: CounterValue)
|
||||
where
|
||||
Q: ?Sized + std::hash::Hash + Eq,
|
||||
|
||||
@@ -19,5 +19,4 @@
|
||||
mod hash;
|
||||
mod node_message;
|
||||
|
||||
pub use hash::Hash;
|
||||
pub use node_message::*;
|
||||
|
||||
@@ -136,6 +136,9 @@ pub struct NodeDetails {
|
||||
pub version: String,
|
||||
pub validator: Option<String>,
|
||||
pub network_id: Option<String>,
|
||||
pub os: String,
|
||||
pub arch: String,
|
||||
pub target_env: String,
|
||||
pub ip: Option<String>,
|
||||
pub sysinfo: Option<NodeSysInfo>,
|
||||
}
|
||||
@@ -144,7 +147,6 @@ impl FeedMessage {
|
||||
/// Decode a slice of bytes into a vector of feed messages
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<Vec<FeedMessage>, anyhow::Error> {
|
||||
let v: Vec<&RawValue> = serde_json::from_slice(bytes)?;
|
||||
|
||||
let mut feed_messages = vec![];
|
||||
for raw_keyval in v.chunks(2) {
|
||||
let raw_key = raw_keyval[0];
|
||||
@@ -161,6 +163,8 @@ impl FeedMessage {
|
||||
|
||||
// Deserialize the feed message to a value based on the "action" key
|
||||
fn decode(action: u8, raw_val: &RawValue) -> Result<FeedMessage, anyhow::Error> {
|
||||
println!("\n\n");
|
||||
println!("{raw_val:#?}");
|
||||
let feed_message = match action {
|
||||
// Version:
|
||||
0 => {
|
||||
@@ -189,7 +193,19 @@ impl FeedMessage {
|
||||
3 => {
|
||||
let (
|
||||
node_id,
|
||||
(name, implementation, version, validator, network_id, ip, sysinfo, hwbench),
|
||||
(
|
||||
name,
|
||||
implementation,
|
||||
version,
|
||||
validator,
|
||||
network_id,
|
||||
os,
|
||||
arch,
|
||||
target_env,
|
||||
ip,
|
||||
sysinfo,
|
||||
hwbench,
|
||||
),
|
||||
stats,
|
||||
io,
|
||||
hardware,
|
||||
@@ -209,6 +225,9 @@ impl FeedMessage {
|
||||
version,
|
||||
validator,
|
||||
network_id,
|
||||
os,
|
||||
arch,
|
||||
target_env,
|
||||
ip,
|
||||
sysinfo,
|
||||
},
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"warn",
|
||||
{
|
||||
{
|
||||
"argsIgnorePattern": "^_",
|
||||
"varsIgnorePattern": "^_",
|
||||
"caughtErrorsIgnorePattern": "^_"
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# substrate-telemetry-frontend
|
||||
|
||||
### [Documentation](https://github.com/paritytech/substrate-telemetry/blob/master/README.md)
|
||||
### [Documentation](https://github.com/paritytech/substrate-telemetry/blob/master/README.md)
|
||||
|
||||
@@ -1,23 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="theme-color" content="#000000">
|
||||
<meta charset="utf-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, shrink-to-fit=no"
|
||||
/>
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<title>Polkadot Telemetry</title>
|
||||
<script type="text/javascript" src="/tmp/env-config.js"></script>
|
||||
<style>
|
||||
body, html {
|
||||
body,
|
||||
html {
|
||||
background: #fff;
|
||||
color: #111;
|
||||
}
|
||||
</style>
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<noscript> You need to enable JavaScript to run this app. </noscript>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
// loading images gives back a path. This is what we replace
|
||||
// that with for tests:
|
||||
module.exports = 'test-image-stub';
|
||||
module.exports = 'test-image-stub';
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
// For loading styles, give back an empty object in tests:
|
||||
module.exports = {};
|
||||
module.exports = {};
|
||||
|
||||
Vendored
+3
-3
@@ -14,6 +14,6 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
declare module '*.svg'
|
||||
declare module '*.png'
|
||||
declare module '*.jpg'
|
||||
declare module '*.svg';
|
||||
declare module '*.png';
|
||||
declare module '*.jpg';
|
||||
|
||||
@@ -20,7 +20,8 @@ module.exports = {
|
||||
testEnvironment: 'jsdom',
|
||||
setupFiles: ['<rootDir>/setupJest.js'],
|
||||
moduleNameMapper: {
|
||||
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/assets/mock.image.js",
|
||||
"\\.(css|less|scss|sass)$": "<rootDir>/assets/mock.style.js"
|
||||
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
|
||||
'<rootDir>/assets/mock.image.js',
|
||||
'\\.(css|less|scss|sass)$': '<rootDir>/assets/mock.style.js',
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -22,4 +22,4 @@ global.TextEncoder = TextEncoder;
|
||||
global.TextDecoder = TextDecoder;
|
||||
|
||||
// polyfill fetch since it's not in jsdom:
|
||||
require('whatwg-fetch');
|
||||
require('whatwg-fetch');
|
||||
|
||||
+17
-3
@@ -46,6 +46,7 @@ export default class App extends React.Component {
|
||||
constructor(props: Record<string, unknown>) {
|
||||
super(props);
|
||||
|
||||
//todo! Check what's important to set to true, false
|
||||
this.settings = new PersistentObject(
|
||||
'settings',
|
||||
{
|
||||
@@ -55,8 +56,6 @@ export default class App extends React.Component {
|
||||
networkId: false,
|
||||
peers: true,
|
||||
txs: true,
|
||||
cpu: true,
|
||||
mem: true,
|
||||
upload: false,
|
||||
download: false,
|
||||
stateCacheSize: false,
|
||||
@@ -65,12 +64,27 @@ export default class App extends React.Component {
|
||||
diskWrite: false,
|
||||
blocknumber: true,
|
||||
blockhash: true,
|
||||
blocktime: true,
|
||||
finalized: false,
|
||||
finalizedhash: false,
|
||||
blocktime: true,
|
||||
blockpropagation: true,
|
||||
blocklasttime: false,
|
||||
uptime: false,
|
||||
version: false,
|
||||
target_os: false,
|
||||
target_arch: false,
|
||||
cpu: false,
|
||||
cpu_hashrate_score: true,
|
||||
cpu_vendor: true,
|
||||
core_count: false,
|
||||
mem: true,
|
||||
memory: false,
|
||||
linux_distro: false,
|
||||
linux_kernel: false,
|
||||
memory_memcpy_score: true,
|
||||
disk_sequential_write_score: true,
|
||||
disk_random_write_score: true,
|
||||
is_virtual_machine: false,
|
||||
},
|
||||
(settings) => {
|
||||
const selectedColumns = this.selectedColumns(settings);
|
||||
|
||||
@@ -269,7 +269,6 @@ export class Connection {
|
||||
|
||||
case ACTIONS.NodeStats: {
|
||||
const [id, nodeStats] = message.payload;
|
||||
|
||||
nodes.mutAndMaybeSort(
|
||||
id,
|
||||
(node) => node.updateStats(nodeStats),
|
||||
|
||||
@@ -25,6 +25,15 @@ export type NodeId = Id<'Node'>;
|
||||
export type NodeName = Opaque<string, 'NodeName'>;
|
||||
export type NodeImplementation = Opaque<string, 'NodeImplementation'>;
|
||||
export type NodeVersion = Opaque<string, 'NodeVersion'>;
|
||||
export type OperatingSystem = Opaque<string, 'OperatingSystem'>;
|
||||
export type CpuArchitecture = Opaque<string, 'CpuArchitecture'>;
|
||||
export type Cpu = string;
|
||||
export type CpuCores = number;
|
||||
export type TargetEnv = string;
|
||||
export type Memory = number;
|
||||
export type VirtualMachine = boolean;
|
||||
export type LinuxKernel = string;
|
||||
export type LinuxDistro = string;
|
||||
export type BlockNumber = Opaque<number, 'BlockNumber'>;
|
||||
export type BlockHash = Opaque<string, 'BlockHash'>;
|
||||
export type Address = Opaque<string, 'Address'>;
|
||||
@@ -43,6 +52,15 @@ export type Bytes = Opaque<number, 'Bytes'>;
|
||||
export type BytesPerSecond = Opaque<number, 'BytesPerSecond'>;
|
||||
export type NetworkId = Opaque<string, 'NetworkId'>;
|
||||
|
||||
export type NodeSysInfo = {
|
||||
cpu: string;
|
||||
memory: number;
|
||||
core_count: number;
|
||||
linux_kernel: string;
|
||||
linux_distro: string;
|
||||
is_virtual_machine: boolean;
|
||||
};
|
||||
|
||||
export type BlockDetails = [
|
||||
BlockNumber,
|
||||
BlockHash,
|
||||
@@ -56,8 +74,13 @@ export type NodeDetails = [
|
||||
NodeVersion,
|
||||
Maybe<Address>,
|
||||
Maybe<NetworkId>,
|
||||
Maybe<string>
|
||||
OperatingSystem,
|
||||
CpuArchitecture,
|
||||
TargetEnv,
|
||||
undefined,
|
||||
NodeSysInfo
|
||||
];
|
||||
|
||||
export type NodeStats = [PeerCount, TransactionCount];
|
||||
export type NodeIO = [Array<Bytes>];
|
||||
export type NodeHardware = [
|
||||
|
||||
@@ -38,6 +38,15 @@ import {
|
||||
BlockPropagationColumn,
|
||||
LastBlockColumn,
|
||||
UptimeColumn,
|
||||
CpuArchitectureColumn, //extra columns added
|
||||
CpuColumn,
|
||||
CpuCoresColumn,
|
||||
LinuxKernelColumn,
|
||||
IsVirtualMachineColumn,
|
||||
MemoryColumn,
|
||||
OperatingSystemColumn,
|
||||
VersionColumn,
|
||||
LinuxDistroColumn,
|
||||
} from './';
|
||||
|
||||
export type Column =
|
||||
@@ -58,7 +67,16 @@ export type Column =
|
||||
| typeof BlockTimeColumn
|
||||
| typeof BlockPropagationColumn
|
||||
| typeof LastBlockColumn
|
||||
| typeof UptimeColumn;
|
||||
| typeof UptimeColumn
|
||||
| typeof CpuArchitectureColumn
|
||||
| typeof CpuColumn
|
||||
| typeof CpuCoresColumn
|
||||
| typeof LinuxDistroColumn
|
||||
| typeof LinuxKernelColumn
|
||||
| typeof IsVirtualMachineColumn
|
||||
| typeof MemoryColumn
|
||||
| typeof OperatingSystemColumn
|
||||
| typeof VersionColumn;
|
||||
|
||||
export interface ColumnProps {
|
||||
node: Node;
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
// Source code for the Substrate Telemetry Server.
|
||||
// Copyright (C) 2023 Parity Technologies (UK) Ltd.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
//Column for specifying which CPU Architecture the node is running on
|
||||
import * as React from 'react';
|
||||
import { ColumnProps } from './';
|
||||
import { Node } from '../../../state';
|
||||
import icon from '../../../icons/file-binary.svg';
|
||||
|
||||
export class CpuArchitectureColumn extends React.Component<ColumnProps> {
|
||||
public static readonly label = 'CPU Architecture';
|
||||
public static readonly icon = icon;
|
||||
public static readonly width = 154;
|
||||
public static readonly setting = 'target_arch';
|
||||
public static readonly sortBy = ({ target_arch }: Node) => target_arch || '';
|
||||
|
||||
private data: string;
|
||||
|
||||
public shouldComponentUpdate(nextProps: ColumnProps) {
|
||||
return this.data !== nextProps.node.hash;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { target_arch } = this.props.node;
|
||||
|
||||
this.data = target_arch;
|
||||
|
||||
return <td className="Column">{target_arch || '-'}</td>;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// Source code for the Substrate Telemetry Server.
|
||||
// Copyright (C) 2023 Parity Technologies (UK) Ltd.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
//Column for specifying which CPU type the node is running on
|
||||
|
||||
import * as React from 'react';
|
||||
import { ColumnProps } from './';
|
||||
import { Node } from '../../../state';
|
||||
import icon from '../../../icons/file-binary.svg';
|
||||
|
||||
export class CpuColumn extends React.Component<ColumnProps> {
|
||||
public static readonly label = 'CPU Column';
|
||||
public static readonly icon = icon;
|
||||
public static readonly width = 154;
|
||||
public static readonly setting = 'cpu';
|
||||
public static readonly sortBy = ({ cpu }: Node) => cpu || 0;
|
||||
|
||||
private data: string;
|
||||
|
||||
public shouldComponentUpdate(nextProps: ColumnProps) {
|
||||
return this.data !== nextProps.node.cpu;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { cpu } = this.props.node;
|
||||
|
||||
this.data = cpu;
|
||||
|
||||
return <td className="Column">{cpu || '-'}</td>;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
// Source code for the Substrate Telemetry Server.
|
||||
// Copyright (C) 2023 Parity Technologies (UK) Ltd.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
import * as React from 'react';
|
||||
import { ColumnProps } from './';
|
||||
import { Node } from '../../../state';
|
||||
import icon from '../../../icons/file-binary.svg';
|
||||
|
||||
export class CpuCoresColumn extends React.Component<ColumnProps> {
|
||||
public static readonly label = 'CPU Cores';
|
||||
public static readonly icon = icon;
|
||||
public static readonly width = 154;
|
||||
public static readonly setting = 'core_count';
|
||||
public static readonly sortBy = ({ core_count }: Node) => core_count || 0;
|
||||
|
||||
private data: number;
|
||||
|
||||
public shouldComponentUpdate(nextProps: ColumnProps) {
|
||||
return this.data !== nextProps.node.core_count;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { core_count } = this.props.node;
|
||||
|
||||
this.data = core_count;
|
||||
|
||||
return <td className="Column">{core_count || '-'}</td>;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// Source code for the Substrate Telemetry Server.
|
||||
// Copyright (C) 2023 Parity Technologies (UK) Ltd.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
//Column for specifying whether each node runs a VM or not
|
||||
import * as React from 'react';
|
||||
import { ColumnProps } from './';
|
||||
import { Node } from '../../../state';
|
||||
import icon from '../../../icons/file-binary.svg';
|
||||
|
||||
export class IsVirtualMachineColumn extends React.Component<ColumnProps> {
|
||||
public static readonly label = 'Virtual Machine';
|
||||
public static readonly icon = icon;
|
||||
public static readonly width = 154;
|
||||
public static readonly setting = 'is_virtual_machine';
|
||||
public static readonly sortBy = ({ is_virtual_machine }: Node) =>
|
||||
is_virtual_machine || false;
|
||||
|
||||
private data: boolean;
|
||||
|
||||
public shouldComponentUpdate(nextProps: ColumnProps) {
|
||||
return this.data !== nextProps.node.is_virtual_machine;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { is_virtual_machine } = this.props.node;
|
||||
|
||||
this.data = is_virtual_machine;
|
||||
|
||||
return <td className="Column">{is_virtual_machine ? 'Yes' : 'No'}</td>;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
// Source code for the Substrate Telemetry Server.
|
||||
// Copyright (C) 2023 Parity Technologies (UK) Ltd.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
//Column for specifying type of distro each node is running (Linux Distribution)
|
||||
|
||||
import * as React from 'react';
|
||||
import { ColumnProps } from './';
|
||||
import { Node } from '../../../state';
|
||||
import icon from '../../../icons/file-binary.svg';
|
||||
|
||||
export class LinuxDistroColumn extends React.Component<ColumnProps> {
|
||||
public static readonly label = 'Linux Distro';
|
||||
public static readonly icon = icon;
|
||||
public static readonly width = 154;
|
||||
public static readonly setting = 'linux_distro';
|
||||
public static readonly sortBy = ({ linux_distro }: Node) =>
|
||||
linux_distro || '';
|
||||
|
||||
private data: string;
|
||||
|
||||
public shouldComponentUpdate(nextProps: ColumnProps) {
|
||||
return this.data !== nextProps.node.linux_distro;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { linux_distro } = this.props.node;
|
||||
|
||||
this.data = linux_distro;
|
||||
|
||||
return <td className="Column">{linux_distro || '-'}</td>;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// Source code for the Substrate Telemetry Server.
|
||||
// Copyright (C) 2023 Parity Technologies (UK) Ltd.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
//Column for specifying which kernel each node is running on
|
||||
import * as React from 'react';
|
||||
import { ColumnProps } from './';
|
||||
import { Node } from '../../../state';
|
||||
import icon from '../../../icons/file-binary.svg';
|
||||
|
||||
export class LinuxKernelColumn extends React.Component<ColumnProps> {
|
||||
public static readonly label = 'Linux Kernel';
|
||||
public static readonly icon = icon;
|
||||
public static readonly width = 154;
|
||||
public static readonly setting = 'linux_kernel';
|
||||
public static readonly sortBy = ({ linux_kernel }: Node) => linux_kernel || 0;
|
||||
|
||||
private data: string;
|
||||
|
||||
public shouldComponentUpdate(nextProps: ColumnProps) {
|
||||
return this.data !== nextProps.node.linux_kernel;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { linux_kernel } = this.props.node;
|
||||
|
||||
this.data = linux_kernel;
|
||||
|
||||
return <td className="Column">{linux_kernel || '-'}</td>;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// Source code for the Substrate Telemetry Server.
|
||||
// Copyright (C) 2023 Parity Technologies (UK) Ltd.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
//Column specifying type of memory each node has
|
||||
import * as React from 'react';
|
||||
import { ColumnProps } from './';
|
||||
import { Node } from '../../../state';
|
||||
import icon from '../../../icons/file-binary.svg';
|
||||
|
||||
export class MemoryColumn extends React.Component<ColumnProps> {
|
||||
public static readonly label = 'memory';
|
||||
public static readonly icon = icon;
|
||||
public static readonly width = 154;
|
||||
public static readonly setting = 'memory';
|
||||
public static readonly sortBy = ({ memory }: Node) => memory || '';
|
||||
|
||||
private data: number;
|
||||
|
||||
public shouldComponentUpdate(nextProps: ColumnProps) {
|
||||
return this.data !== nextProps.node.memory;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { memory } = this.props.node;
|
||||
|
||||
this.data = memory;
|
||||
|
||||
return <td className="Column">{memory || '-'}</td>;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// Source code for the Substrate Telemetry Server.
|
||||
// Copyright (C) 2023 Parity Technologies (UK) Ltd.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
//Column for specifying which OS the node is running on
|
||||
|
||||
import * as React from 'react';
|
||||
import { ColumnProps } from './';
|
||||
import { Node } from '../../../state';
|
||||
import icon from '../../../icons/file-binary.svg';
|
||||
|
||||
export class OperatingSystemColumn extends React.Component<ColumnProps> {
|
||||
public static readonly label = 'OS';
|
||||
public static readonly icon = icon;
|
||||
public static readonly width = 154;
|
||||
public static readonly setting = 'target_os';
|
||||
public static readonly sortBy = ({ target_os }: Node) => target_os || '';
|
||||
|
||||
private data: string;
|
||||
|
||||
public shouldComponentUpdate(nextProps: ColumnProps) {
|
||||
return this.data !== nextProps.node.hash;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { target_os } = this.props.node;
|
||||
|
||||
this.data = target_os;
|
||||
|
||||
return <td className="Column">{target_os || '-'}</td>;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// Source code for the Substrate Telemetry Server.
|
||||
// Copyright (C) 2023 Parity Technologies (UK) Ltd.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
//Column for specifying which polkadot version node is running on
|
||||
|
||||
import * as React from 'react';
|
||||
import { ColumnProps } from './';
|
||||
import { Node } from '../../../state';
|
||||
import icon from '../../../icons/file-binary.svg';
|
||||
|
||||
export class VersionColumn extends React.Component<ColumnProps> {
|
||||
public static readonly label = 'version';
|
||||
public static readonly icon = icon;
|
||||
public static readonly width = 154;
|
||||
public static readonly setting = 'version';
|
||||
public static readonly sortBy = ({ version }: Node) => version || '';
|
||||
|
||||
private data: string;
|
||||
|
||||
public shouldComponentUpdate(nextProps: ColumnProps) {
|
||||
return this.data !== nextProps.node.version;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { version } = this.props.node;
|
||||
|
||||
this.data = version;
|
||||
|
||||
return <td className="Column">{version || '-'}</td>;
|
||||
}
|
||||
}
|
||||
@@ -33,3 +33,12 @@ export * from './BlockTimeColumn';
|
||||
export * from './BlockPropagationColumn';
|
||||
export * from './LastBlockColumn';
|
||||
export * from './UptimeColumn';
|
||||
export * from './CpuArchitectureColumn'; //extra columns added
|
||||
export * from './CpuCoresColumn';
|
||||
export * from './LinuxDistroColumn';
|
||||
export * from './IsVirtualMachineColumn';
|
||||
export * from './MemoryColumn';
|
||||
export * from './CpuColumn';
|
||||
export * from './OperatingSystemColumn';
|
||||
export * from './VersionColumn';
|
||||
export * from './LinuxKernelColumn';
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
// Each Row in the List Page
|
||||
import * as React from 'react';
|
||||
import { Types } from '../../common';
|
||||
import { Node } from '../../state';
|
||||
@@ -38,6 +39,15 @@ import {
|
||||
BlockPropagationColumn,
|
||||
LastBlockColumn,
|
||||
UptimeColumn,
|
||||
CpuArchitectureColumn,
|
||||
CpuColumn,
|
||||
CpuCoresColumn,
|
||||
MemoryColumn,
|
||||
OperatingSystemColumn,
|
||||
VersionColumn,
|
||||
IsVirtualMachineColumn,
|
||||
LinuxDistroColumn,
|
||||
LinuxKernelColumn,
|
||||
} from './';
|
||||
|
||||
import './Row.css';
|
||||
@@ -72,8 +82,16 @@ export class Row extends React.Component<RowProps, RowState> {
|
||||
BlockPropagationColumn,
|
||||
LastBlockColumn,
|
||||
UptimeColumn,
|
||||
VersionColumn,
|
||||
OperatingSystemColumn,
|
||||
CpuArchitectureColumn,
|
||||
CpuColumn,
|
||||
CpuCoresColumn,
|
||||
MemoryColumn,
|
||||
LinuxDistroColumn,
|
||||
LinuxKernelColumn,
|
||||
IsVirtualMachineColumn,
|
||||
];
|
||||
|
||||
private renderedChangeRef = 0;
|
||||
|
||||
public shouldComponentUpdate(nextProps: RowProps): boolean {
|
||||
|
||||
+63
-3
@@ -26,8 +26,8 @@ export const PINNED_CHAINS = {
|
||||
};
|
||||
|
||||
export function comparePinnedChains(a: string, b: string) {
|
||||
const aWeight = PINNED_CHAINS[a] || 1024;
|
||||
const bWeight = PINNED_CHAINS[b] || 1024;
|
||||
const aWeight: number = (PINNED_CHAINS as any)[a] || 1024;
|
||||
const bWeight: number = (PINNED_CHAINS as any)[b] || 1024;
|
||||
|
||||
return aWeight - bWeight;
|
||||
}
|
||||
@@ -62,6 +62,17 @@ export class Node {
|
||||
public readonly validator: Maybe<Types.Address>;
|
||||
public readonly networkId: Maybe<Types.NetworkId>;
|
||||
public readonly startupTime: Maybe<Types.Timestamp>;
|
||||
public readonly target_os: Types.OperatingSystem;
|
||||
public readonly target_arch: Types.CpuArchitecture;
|
||||
public readonly target_env: Types.TargetEnv;
|
||||
public readonly sysInfo: Types.NodeSysInfo;
|
||||
|
||||
public readonly cpu: Types.Cpu;
|
||||
public readonly memory: Types.Memory;
|
||||
public readonly core_count: Types.CpuCores;
|
||||
public readonly linux_kernel: Types.LinuxKernel;
|
||||
public readonly linux_distro: Types.LinuxDistro;
|
||||
public readonly is_virtual_machine: Types.VirtualMachine;
|
||||
|
||||
public readonly sortableName: string;
|
||||
public readonly sortableVersion: number;
|
||||
@@ -102,7 +113,18 @@ export class Node {
|
||||
location: Maybe<Types.NodeLocation>,
|
||||
startupTime: Maybe<Types.Timestamp>
|
||||
) {
|
||||
const [name, implementation, version, validator, networkId] = nodeDetails;
|
||||
const [
|
||||
name,
|
||||
implementation,
|
||||
version,
|
||||
validator,
|
||||
networkId,
|
||||
target_os,
|
||||
target_arch,
|
||||
target_env,
|
||||
customNullField,
|
||||
sysInfo,
|
||||
] = nodeDetails; //step 4
|
||||
|
||||
this.pinned = pinned;
|
||||
|
||||
@@ -113,6 +135,30 @@ export class Node {
|
||||
this.validator = validator;
|
||||
this.networkId = networkId;
|
||||
this.startupTime = startupTime;
|
||||
this.target_os = target_os;
|
||||
this.target_arch = target_arch;
|
||||
this.target_env = target_env;
|
||||
this.sysInfo = {
|
||||
cpu: sysInfo?.cpu ?? '', // Default value or some global constant
|
||||
memory: sysInfo?.memory ?? 0,
|
||||
core_count: sysInfo?.core_count ?? 0,
|
||||
linux_kernel: sysInfo?.linux_kernel ?? '',
|
||||
linux_distro: sysInfo?.linux_distro ?? '',
|
||||
is_virtual_machine: sysInfo?.is_virtual_machine ?? false,
|
||||
};
|
||||
|
||||
this.cpu = sysInfo && sysInfo.cpu ? sysInfo.cpu : '';
|
||||
this.memory = sysInfo && sysInfo.memory ? Number(sysInfo.memory) : 0;
|
||||
this.core_count =
|
||||
sysInfo && sysInfo.core_count ? Number(sysInfo.core_count) : 0;
|
||||
this.linux_kernel =
|
||||
sysInfo && sysInfo.linux_kernel ? sysInfo.linux_kernel : '';
|
||||
this.linux_distro =
|
||||
sysInfo && sysInfo.linux_distro ? sysInfo.linux_distro : '';
|
||||
this.is_virtual_machine =
|
||||
sysInfo && sysInfo.is_virtual_machine
|
||||
? Boolean(sysInfo.is_virtual_machine)
|
||||
: false;
|
||||
|
||||
const [major = 0, minor = 0, patch = 0] = (version || '0.0.0')
|
||||
.split('.')
|
||||
@@ -255,6 +301,20 @@ export interface StateSettings {
|
||||
blockpropagation: boolean;
|
||||
blocklasttime: boolean;
|
||||
uptime: boolean;
|
||||
version: boolean;
|
||||
target_os: boolean;
|
||||
target_arch: boolean;
|
||||
cpu: boolean;
|
||||
core_count: boolean;
|
||||
memory: boolean;
|
||||
is_virtual_machine: boolean;
|
||||
linux_distro: boolean;
|
||||
linux_kernel: boolean;
|
||||
cpu_hashrate_score: boolean;
|
||||
memory_memcpy_score: boolean;
|
||||
disk_sequential_write_score: boolean;
|
||||
disk_random_write_score: boolean;
|
||||
cpu_vendor: boolean;
|
||||
}
|
||||
|
||||
export interface State {
|
||||
|
||||
@@ -4,11 +4,7 @@
|
||||
"outDir": "./build/",
|
||||
"module": "es2020",
|
||||
"target": "es2015",
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"sourceMap": true,
|
||||
"allowJs": false,
|
||||
"jsx": "react",
|
||||
|
||||
@@ -16,19 +16,19 @@ module.exports = {
|
||||
// allow 'import "foo.css"' and '@import "foo.css" in css files
|
||||
test: /\.css$/i,
|
||||
use: ['style-loader', 'css-loader'],
|
||||
generator: { filename: 'styles/[name].[contenthash][ext]' }
|
||||
generator: { filename: 'styles/[name].[contenthash][ext]' },
|
||||
},
|
||||
{
|
||||
// allow 'import Icon from "./icon.png"'
|
||||
test: /\.(png|svg|jpg|jpeg|gif)$/i,
|
||||
type: 'asset/resource',
|
||||
generator: { filename: 'images/[name].[contenthash][ext]' }
|
||||
generator: { filename: 'images/[name].[contenthash][ext]' },
|
||||
},
|
||||
{
|
||||
// allow CSS @url('./my-font.woff2')" style font loading
|
||||
test: /\.(woff|woff2|eot|ttf|otf)$/i,
|
||||
type: 'asset/resource',
|
||||
generator: { filename: 'fonts/[name].[contenthash][ext]' }
|
||||
generator: { filename: 'fonts/[name].[contenthash][ext]' },
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -36,8 +36,8 @@ module.exports = {
|
||||
// Use our index.html as a starting point (to add script links etc to)
|
||||
// and make sure to use/copy over the favicon too.
|
||||
new HtmlWebpackPlugin({
|
||||
favicon: "./assets/favicon.svg",
|
||||
template: "./assets/index.html"
|
||||
favicon: './assets/favicon.svg',
|
||||
template: './assets/index.html',
|
||||
}),
|
||||
],
|
||||
resolve: {
|
||||
@@ -46,6 +46,6 @@ module.exports = {
|
||||
output: {
|
||||
filename: 'main.[contenthash].js',
|
||||
path: path.resolve(__dirname, 'build'),
|
||||
clean: true
|
||||
clean: true,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user