147 lines
3.1 KiB
JavaScript
147 lines
3.1 KiB
JavaScript
import React, { Component } from 'react';
|
|
|
|
import Service from './Service.js';
|
|
import './App.css';
|
|
|
|
import OP from './ws/op.js';
|
|
|
|
const log = (...args) => {
|
|
console.log(
|
|
'%c[elstat]%c',
|
|
'color: purple; font-weight: bold',
|
|
'color: inherit; font-weight: inherit',
|
|
...args,
|
|
);
|
|
};
|
|
|
|
const DOMAIN = 'https://elstatus.stayathomeserver.club';
|
|
// const ENDPOINT = 'http://localhost:8069/api/status'
|
|
|
|
export default class App extends Component {
|
|
websocket = null;
|
|
|
|
state = {
|
|
loading: true,
|
|
error: null,
|
|
metrics: null,
|
|
};
|
|
|
|
async componentDidMount() {
|
|
await this.loadMetrics();
|
|
this.connect();
|
|
}
|
|
|
|
subscribeToChannels() {
|
|
const channels = Object.keys(this.state.metrics.graph).map((channel) => `latency:${channel}`);
|
|
log('subscribing to channels:', channels);
|
|
|
|
this._send({
|
|
op: OP.SUBSCRIBE,
|
|
channels,
|
|
});
|
|
}
|
|
|
|
handlePacket(packet) {
|
|
const { op, c: channel, d: data } = packet;
|
|
|
|
if (op !== OP.DATA) {
|
|
log('ignoring boring packet:', packet);
|
|
return;
|
|
}
|
|
|
|
const [, name] = channel.split(':');
|
|
|
|
log('updating from channel:', channel);
|
|
|
|
const { metrics } = this.state;
|
|
const graph = metrics.graph[name].slice(1);
|
|
const newGraph = [data, ...graph];
|
|
|
|
log('adding data:', data);
|
|
|
|
this.setState(({ metrics: oldMetrics }, _props) => {
|
|
const newMetrics = { ...oldMetrics };
|
|
newMetrics.graph[name] = newGraph;
|
|
|
|
const [, latency] = data;
|
|
newMetrics.status[name].latency = latency;
|
|
|
|
return {
|
|
metrics: newMetrics,
|
|
};
|
|
});
|
|
}
|
|
|
|
connect() {
|
|
log('connecting to ws');
|
|
|
|
const endpoint = (`${DOMAIN}/api/streaming`).replace('https', 'wss');
|
|
this.websocket = new WebSocket(endpoint);
|
|
|
|
this.websocket.onopen = () => {
|
|
log('ws opened');
|
|
this.subscribeToChannels();
|
|
};
|
|
|
|
this.websocket.onmessage = (message) => {
|
|
const { data } = message;
|
|
const parsed = JSON.parse(data);
|
|
log('ws recv:', parsed);
|
|
|
|
this.handlePacket(parsed);
|
|
};
|
|
|
|
this.websocket.onerror = (error) => {
|
|
log('ws error:', error);
|
|
};
|
|
}
|
|
|
|
|
|
_send(payload) {
|
|
this.websocket.send(JSON.stringify(payload));
|
|
}
|
|
|
|
async loadMetrics() {
|
|
log('loading metrics');
|
|
|
|
try {
|
|
const resp = await fetch(`${DOMAIN}/api/status`);
|
|
const json = await resp.json();
|
|
|
|
this.setState({ metrics: json, loading: false });
|
|
} catch (err) {
|
|
this.setState({ error: err.toString() });
|
|
}
|
|
}
|
|
|
|
|
|
render() {
|
|
const metrics = !this.state.metrics ? null : (
|
|
<div className="services">
|
|
{Object.entries(this.state.metrics.status)
|
|
.map(([name, info]) => (
|
|
<Service
|
|
name={name}
|
|
key={name}
|
|
graph={this.state.metrics.graph[name]}
|
|
{...info}
|
|
/>
|
|
))
|
|
}
|
|
</div>
|
|
);
|
|
|
|
return (
|
|
<div className="dashboard">
|
|
<h1>elstatus</h1>
|
|
{this.state.loading ? (
|
|
<div>Loading metrics...</div>
|
|
) : null}
|
|
{this.state.error ? (
|
|
<div>Error: {this.state.error}</div>
|
|
) : null}
|
|
{metrics}
|
|
</div>
|
|
);
|
|
}
|
|
}
|