elstat/priv/frontend/src/components/App.js

154 lines
3.5 KiB
JavaScript
Raw Normal View History

2018-06-12 21:56:50 +00:00
import React, { Component } from 'react';
2018-07-14 02:01:24 +00:00
import './App.css';
2018-06-12 21:56:50 +00:00
import Service from './Service.js';
2018-07-14 01:43:10 +00:00
import ServicePlaceholder from './ServicePlaceholder.js';
2018-07-14 02:06:38 +00:00
import OP from '../ws/op.js';
import { log } from '../util.js';
const DOMAIN = 'https://elstatus.stayathomeserver.club';
2018-07-09 05:50:53 +00:00
// const ENDPOINT = 'http://localhost:8069/api/status'
2018-06-12 21:56:50 +00:00
export default class App extends Component {
websocket = null;
2018-07-14 02:11:50 +00:00
reconnectionTime = 1000;
2018-06-12 21:56:50 +00:00
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,
};
});
2018-06-12 21:56:50 +00:00
}
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();
};
2018-07-14 02:33:53 +00:00
this.websocket.onclose = ({ code, reason }) => {
log(`ws closed with code ${code} (reason: ${reason || '<none>'}); `
+ `attempting to reconnect in ${this.reconnectionTime}ms`);
2018-07-14 02:11:50 +00:00
setTimeout(() => this.connect(), this.reconnectionTime);
this.reconnectionTime *= 2;
};
this.websocket.onmessage = (message) => {
const { data } = message;
const parsed = JSON.parse(data);
log('ws recv:', parsed);
this.handlePacket(parsed);
};
2018-07-14 02:33:53 +00:00
this.websocket.onerror = (event) => {
log('ws error:', event);
};
}
_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() });
}
}
2018-06-12 21:56:50 +00:00
render() {
const metrics = !this.state.metrics ? null : (
<div className="services">
{Object.entries(this.state.metrics.status)
.map(([name, info]) => (
<Service
name={name}
key={name}
2018-06-12 21:56:50 +00:00
graph={this.state.metrics.graph[name]}
{...info}
/>
))
2018-06-12 21:56:50 +00:00
}
</div>
);
return (
<div className="dashboard">
<h1>elstatus</h1>
2018-07-14 02:06:38 +00:00
{this.state.error ? (
<div className="error">
Error: {this.state.error}
</div>
) : null}
2018-07-14 02:34:03 +00:00
{this.state.loading && !this.state.error ? (
2018-07-14 01:43:10 +00:00
<React.Fragment>
<ServicePlaceholder />
<ServicePlaceholder />
<ServicePlaceholder />
</React.Fragment>
2018-07-14 02:06:38 +00:00
) : metrics}
2018-06-12 21:56:50 +00:00
</div>
);
}
}