nope/resources/admin-shell/dispatchers.tsx
2021-01-15 16:33:52 +01:00

376 lines
9.0 KiB
TypeScript

/**
* @author Martin Karkowski
* @email m.karkowski@zema.de
* @create date 2020-12-03 11:57:29
* @modify date 2020-12-03 11:57:29
* @desc [description]
*/
import React from "react";
import { Badge, Card, Col, ProgressBar, Row, Table } from "react-bootstrap";
import {
ENopeDispatcherStatus,
INopeDispatcher
} from "../../lib/types/nope/nopeDispatcher.interface";
import { INopeObserver } from "../../lib/types/nope/nopeObservable.interface";
/**
* Component used to render the Status of the Memory of a Host.
*/
class MemoryStatusOfHostComponent extends React.Component<
{
value: number;
},
{}
> {
render() {
// Determine the Now Value.
const now = Math.round(1000 - this.props.value * 1000) / 10;
const colorRange = {
"0": "success",
"30": "success",
"75": "warning",
"90": "danger",
"101": "danger"
};
// Determine the Color, Therefore filter the "keys" based on the now Value.
const color =
colorRange[
Object.getOwnPropertyNames(colorRange).filter(
(value) => now < parseFloat(value)
)[0]
];
// Render
return (
<>
<ProgressBar now={now} label={`${now} %`} variant={color} />
</>
);
}
}
class HostStatusComponent extends React.Component<
{
status: {
cpu: string;
cores: number;
os: string;
ram: number;
name: string;
pids: {
pid: number;
dispatchers: {
id: string;
status: ENopeDispatcherStatus;
timestamp: number;
}[];
}[];
status: ENopeDispatcherStatus;
timestamp: number;
};
},
{
lastUpdate: string;
variant: "success" | "warning" | "danger";
badge: boolean;
badgeText: string;
}
> {
protected _intervall: any = null;
get _state() {
const dict = {
0: "success",
1: "info",
2: "warning",
3: "danger"
};
return {
lastUpdate: new Date(this.props.status.timestamp).toISOString(),
variant: dict[this.props.status.status],
badge: this.props.status.status !== ENopeDispatcherStatus.HEALTHY,
badgeText: ENopeDispatcherStatus[this.props.status.status]
};
}
constructor(props) {
super(props);
this.state = this._state;
}
componentDidMount() {
const _this = this;
this._intervall = setInterval(() => {
_this.setState(this._state);
}, 200);
}
componentWillUnmount() {
if (this._intervall) {
clearInterval(this._intervall);
}
}
render() {
return (
<Card border={this.state.variant}>
<Card.Body>
<Card.Title>
{" "}
{this.state.badge ? (
<>
{this.props.status.name}{" "}
<Badge variant={this.state.variant}>
ELEMENT {this.state.badgeText} !
</Badge>{" "}
</>
) : (
<>{this.props.status.name}</>
)}{" "}
</Card.Title>
<Table bordered>
<tbody>
{this.props.status.ram > 0 ? (
<tr>
<td>RAM</td>
<td>
{" "}
{/* Rendert the Memory */}
<MemoryStatusOfHostComponent
value={this.props.status.ram}
></MemoryStatusOfHostComponent>
</td>
</tr>
) : (
<></>
)}
<tr>
<td>CPU</td>
<td>{this.props.status.cpu}</td>
</tr>
<tr>
<td>Cores</td>
<td>{this.props.status.cores}</td>
</tr>
<tr>
<td>Platform</td>
<td>{this.props.status.os}</td>
</tr>
<tr>
<td>Nope-Processes</td>
<td>{this.props.status.pids.length}</td>
</tr>
</tbody>
</Table>
</Card.Body>
<Card.Footer>
<small className="text-muted">
Last updated <b>{this.state.lastUpdate}</b>
</small>
</Card.Footer>
</Card>
);
}
}
class AvailableDispatchers extends React.Component<
{ dispatcher: INopeDispatcher },
{
dispatchers: {
cpu: string;
cores: number;
os: string;
ram: number;
name: string;
pids: {
pid: number;
dispatchers: {
id: string;
status: ENopeDispatcherStatus;
timestamp: number;
}[];
}[];
}[][];
connected: boolean;
}
> {
private _observer: INopeObserver[] = [];
private __sort() {
const sorted: {
[index: string]: {
cpu: string;
cores: number;
os: string;
ram: number;
name: string;
pids: {
[index: string]: {
id: string;
status: ENopeDispatcherStatus;
timestamp: number;
}[];
};
status: ENopeDispatcherStatus;
timestamp: number;
};
} = {};
const ret: {
cpu: string;
cores: number;
os: string;
ram: number;
name: string;
pids: {
pid: number;
dispatchers: {
id: string;
status: ENopeDispatcherStatus;
timestamp: number;
}[];
}[];
status: ENopeDispatcherStatus;
timestamp: number;
}[] = [];
for (const dispatcher of this.props.dispatcher.externalDispatchers.getContent()) {
if (sorted[dispatcher.host.name] === undefined) {
sorted[dispatcher.host.name] = {
cores: dispatcher.host.cores,
cpu: dispatcher.host.cpu,
name: dispatcher.host.name,
os: dispatcher.host.os,
pids: {},
ram: dispatcher.host.ram,
status: ENopeDispatcherStatus.HEALTHY,
timestamp: dispatcher.timestamp
};
}
if (sorted[dispatcher.host.name].pids[dispatcher.pid] === undefined) {
sorted[dispatcher.host.name].pids[dispatcher.pid] = [];
}
sorted[dispatcher.host.name].status = Math.max(
sorted[dispatcher.host.name].status,
dispatcher.status
);
sorted[dispatcher.host.name].timestamp = Math.min(
sorted[dispatcher.host.name].timestamp,
dispatcher.timestamp
);
// Store the Dispatcher Status
sorted[dispatcher.host.name].pids[dispatcher.pid].push({
id: dispatcher.id,
status: dispatcher.status,
timestamp: dispatcher.timestamp
});
}
for (const hostname in sorted) {
const _toAdd: any = sorted[hostname];
_toAdd.pids = Object.getOwnPropertyNames(sorted[hostname].pids).map(
(pid) => {
return {
pid,
dispatchers: sorted[hostname].pids[pid]
};
}
);
ret.push(_toAdd);
}
// console.log(this.props.dispatcher.externalDispatchers.getContent().length,ret.map(item => `${item.name}:${item.status}`).toString());
return ret;
}
private __refresh__() {
const connected = this.props.dispatcher.communicator.connected.getContent();
const dispatchers = [];
const maxItems = 3;
const sorted = this.__sort();
// Function to Split the Dispatcher Array into an array containing max 3 elements.
for (let i = 0; i < sorted.length; i = i + maxItems) {
dispatchers.push(sorted.slice(i, i + maxItems));
}
this.setState({
dispatchers: connected ? dispatchers : [],
connected
});
}
/**
* Function will be called if the Item has been rendered sucessfully.
*/
componentDidMount() {
if (this.props.dispatcher) {
// Subscribe to the Instances.
const _this = this;
this._observer.push(
this.props.dispatcher.externalDispatchers.subscribe(() => {
_this.__refresh__();
})
);
this._observer.push(
this.props.dispatcher.communicator.connected.subscribe(() => {
_this.__refresh__();
})
);
// Render the Elements
this.__refresh__();
}
}
/**
* Function, that will be called before the network fails.
*/
componentWillUnmount() {
// Call the unmount
for (const _observer of this._observer) {
_observer.unsubscribe();
}
}
constructor(props) {
super(props);
this.state = {
dispatchers: [],
connected: false
};
}
public render() {
return (
<>
{this.state.dispatchers.map((row, idx_01) => {
return (
<Row
key={idx_01}
style={{ paddingTop: "0.5rem", paddingBottom: "0.5rem" }}
>
{row.map((item, idx_02) => {
return (
<Col key={`${idx_01}_${idx_02}`} sm={4}>
<HostStatusComponent status={item}></HostStatusComponent>
</Col>
);
})}
</Row>
);
})}
</>
);
}
}
export default AvailableDispatchers;