elstat/priv/frontend/src/App.js

150 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,
};
_send(payload) {
this.websocket.send(JSON.stringify(payload));
}
_subscribe() {
const channels = Object.keys(this.state.metrics.graph).map((channel) => `latency:${channel}`);
log('subscribing to channels:', channels);
this._send({
op: OP.SUBSCRIBE,
channels,
});
}
_handleMessage(packet) {
const { op, c: channel, d: data } = packet;
if (op !== OP.DATA) {
log('ignoring boring packet:', packet);
return;
}
const [, name] = channel.split(':');
const { metrics } = this.state;
const graph = metrics.graph[name].slice(1);
const newGraph = [...graph, data];
log('adding data:', data);
const clone = Object.assign({}, this.state.metrics);
clone.graph[name] = newGraph;
log('current graph:', graph, 'new graph:', newGraph);
log('current state', this.state, 'new state:', { metrics: clone });
this.setState({
metrics: clone,
});
}
_connectWs() {
log('connecting to ws');
const endpoint = (`${DOMAIN}/api/streaming`).replace('https', 'wss');
this.websocket = new WebSocket(endpoint);
this.websocket.onopen = () => {
log('ws opened');
this._subscribe();
};
this.websocket.onmessage = (message) => {
const { data } = message;
const parsed = JSON.parse(data);
log('ws recv:', parsed);
this._handleMessage(parsed);
};
this.websocket.onerror = (error) => {
log('ws error:', error);
};
}
async componentDidMount() {
await this._loadMetrics();
this._connectWs();
}
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>
);
}
}