import React from 'react'; import "bootswatch/dist/cosmo/bootstrap.min.css"; import './App.css'; import Login from "./components/Login"; import Haspa from "./components/Haspa"; import Loading from "./components/Loading"; const privilegedIPs = ["localhost", "10.150.9.13", "::1"]; class App extends React.Component { state = { loading: true, auth: null, nodeState: {}, ws: null, isPrivileged: false, wsURL: "wss://" + window.location.hostname + ":8001" } ws = new WebSocket(this.state.wsURL); initWS = () => { this.ws.onopen = () => { console.log("websocket connected") this.setState({loading: false}) const auth = localStorage.getItem("token"); if (auth !== null && auth !== undefined) { let authState; try { authState = JSON.parse(auth); if (authState["expiresAt"] > new Date().getTime() / 1000) { this.ws.send(JSON.stringify({ "type": "refresh_token", "token": authState["token"] })) } else { console.log("found expired auth token in local storage", authState); } } catch { console.log("found invalid auth token in local storage"); } } } this.ws.onmessage = evt => { const message = JSON.parse(evt.data) console.log("received message", message) if (message["type"] === "authenticated") { const auth = { token: message["token"], expiresAt: message["expires_at"] } localStorage.setItem("token", JSON.stringify(auth)); this.setState({auth: auth, loading: false}); // set a timer to refresh the received token 10 seconds before it expires setTimeout(this.refreshToken, message["expires_at"] * 1000 - new Date().getTime() - 10000); } else if (message["type"] === "client_info") { const clientIP = message["client_ip"]; if (privilegedIPs.includes(clientIP) && !this.state.isPrivileged) { this.setState({isPrivileged: true, wsURL: message["privileged_address"]}); this.ws = new WebSocket(message["privileged_address"]); this.initWS(); } } else if (message["type"] === "error") { if (message["code"] === 403) { this.setState({loading: false, auth: null}); } } else if (message["type"] === "state") { if (!message.hasOwnProperty("state")) { console.log("error, invalid state message:", message); } else { this.setState({nodeState: message["state"]["nodes"]}) } } else if (message["type"] === "state_update") { if (!message.hasOwnProperty("updates")) { console.log("error, invalid state message:", message); } else { this.setState({nodeState: Object.assign(this.state.nodeState, message["updates"]["nodes"])}); } } } this.ws.onclose = () => { console.log("websocket disconnected") this.setState({ loading: true, auth: null }) // try to reconnect after 1 second setTimeout(() => { this.ws = new WebSocket(this.state.wsURL); this.initWS(); }, 1000); } } componentDidMount() { this.initWS(); } refreshToken = () => { if (!this.state.loading && this.state.auth !== null) { this.ws.send(JSON.stringify({ "type": "refresh_token", "token": this.state.auth.token })) } } authenticate = (username, password) => { this.setState({loading: true}); this.ws.send(JSON.stringify({ type: "authenticate", username: username, password: password })) } send = (payload) => { if ((this.state.auth === null || this.state.auth.expiresAt < new Date().getTime() / 1000) && !this.state.isPrivileged) { this.setState({auth: null}); return } const msg = { ...payload } if (!this.state.isPrivileged) { msg.token= this.state.auth.token; } console.log("sending message:", msg); this.ws.send(JSON.stringify(msg)); } render() { if (this.state.loading) { return ( <Loading/> ); } else { if (this.state.auth !== null || this.state.isPrivileged) { return ( <Haspa nodeState={this.state.nodeState} send={this.send} isPrivileged={this.state.isPrivileged}/> ); } else { return ( <Login authenticate={this.authenticate}/> ); } } } } export default App;