Implemented websocket connection with backend on sensors

This commit is contained in:
Claudio Maggioni 2020-03-23 22:45:13 +01:00
parent 1b86f6caa4
commit 77a2502be9
3 changed files with 140 additions and 14 deletions

View file

@ -1,33 +1,149 @@
// vim: set ts=2 sw=2 et tw=80:
import axios from "axios"; import axios from "axios";
let config = "http://localhost:8080/"; let config = "http://localhost:8080/";
var tkn = localStorage.getItem("token"); var tkn = localStorage.getItem("token");
/** the ServiceSocket instance valid for the current session */
var socket;
// requests data devices // requests data devices
/* /*
{ {
params : data, params : data,
device: 'tipoDiDevice', device: 'tipoDiDevice',
id: se serve id: se serve
} }
device routes: device routes:
- buttonDimmer - buttonDimmer
- dimmableLight - dimmableLight
- knobDimmer - knobDimmer
- motionSensor - motionSensor
- regularLight - regularLight
- sensor - sensor
- smartPlug - smartPlug
- switch - switch
*/ */
/** The number of times a connection to the socket was tried */
var retries = 0;
/** Class to handle connection with the sensor socket */
class ServiceSocket {
/**
* Create a new sensor socket connection
* @param {string} token - The JWT token (needed for authentication)
* @param {Object.<number, function>|null} callbacks - A callback map from
* device id to callback function
*/
constructor(token, callbacks) {
this.token = token;
this.authenticated = false;
this.callbacks = callbacks || {};
this.connection = new WebSocket("ws://localhost:8080/sensor-socket");
this.connection.onopen = (evt) => {
this.connection.send(JSON.stringify({ token }));
};
this.connection.onmessage = (evt) => {
let data = JSON.parse(evt.data);
if (!this.authenticated) {
if (data.authenticated) {
this.authenticated = true;
retries = 0;
} else {
console.error("socket authentication failed");
}
} else {
if (data.id && this.callbacks[data.id]) {
this.callbacks[data.id].forEach((f) => f(data));
}
}
};
this.connection.onerror = (evt) => {
if (retries >= 5) {
console.error("too many socket connection retries");
return;
}
retries++;
socket = new ServiceSocket(this.token, this.callbacks);
};
}
/**
* Registers a new callback function to be called when updates on the device
* with the id given are recieved
* @param {number} id - the id of the device to check updates for
* @param {function} stateCallback - a function that recieves a device as the
* first parameter, that will be called whenever a update is recieved
*/
subscribe(id, stateCallback) {
if (this.callbacks[id] === undefined) {
this.callbacks[id] = [];
}
this.callbacks[id].push(stateCallback);
}
/**
* Unregisters a function previously registered with `subscribe(...)`.
* @param {number} id - the id of the device to stop checking updates for
* @param {function} stateCallback - the callback to unregister
*/
unsubscribe(id, stateCallback) {
this.callbacks[id].splice(this.callbacks[id].indexOf(stateCallback), 1);
}
/**
* Closes the underlying websocket connection
*/
close() {
this.connection.close();
}
}
if (tkn) {
socket = new ServiceSocket(tkn);
}
export var call = { export var call = {
setToken: function (token) { setToken: function (token) {
tkn = token; tkn = token;
if (tkn) {
if (socket) {
socket.close();
}
socket = new ServiceSocket(tkn);
}
},
/**
* Registers a new callback function to be called when updates on the device
* with the id given are recieved
* @param {number} id - the id of the device to check updates for
* @param {function} stateCallback - a function that recieves a device as the
* first parameter, that will be called whenever a update is recieved
*/
socketSubscribe: function (id, callback) {
socket.subscribe(id, callback);
},
/**
* Unregisters a function previously registered with `subscribe(...)`.
* @param {number} id - the id of the device to stop checking updates for
* @param {function} stateCallback - the callback to unregister
*/
socketUnsubscribe: function (id, callback) {
socket.unsubscribe(id, callback);
}, },
login: function (data, headers) { login: function (data, headers) {
return axios.post(config + "auth/login", data); return axios.post(config + "auth/login", data);

View file

@ -1,3 +1,5 @@
// vim: set ts=2 sw=2 et tw=80:
import React, { Component } from "react"; import React, { Component } from "react";
import { Grid } from "semantic-ui-react"; import { Grid } from "semantic-ui-react";
import { editButtonStyle, panelStyle } from "./devices/styleComponents"; import { editButtonStyle, panelStyle } from "./devices/styleComponents";

View file

@ -9,8 +9,8 @@
/* /*
OPTIONAL STATE OPTIONAL STATE
error: 2.4 error: 2.4
<text style={errorStyle} x={100} y={100} textAnchor="middle" dy="0.6em" fontWeight="bold"> <text style={errorStyle} x={100} y={100} textAnchor="middle" dy="0.6em" fontWeight="bold">
&#177;{this.state.error} &#177;{this.state.error}
</text> </text>
@ -28,6 +28,7 @@ import {
import { sensorText, style, valueStyle } from "./SensorStyle"; import { sensorText, style, valueStyle } from "./SensorStyle";
import Settings from "./DeviceSettings"; import Settings from "./DeviceSettings";
import { StyledDiv } from "./styleComponents"; import { StyledDiv } from "./styleComponents";
import { call } from "../../../client_server";
export default class Sensor extends Component { export default class Sensor extends Component {
constructor(props) { constructor(props) {
@ -37,6 +38,13 @@ export default class Sensor extends Component {
value: 0, value: 0,
}; };
this.units = ""; this.units = "";
this.stateCallback = (e) => this.setState(Object.assign(this.state, e));
call.socketSubscribe(this.props.device.id, this.stateCallback);
}
componentWillUnmount() {
call.socketUnsubscribe(this.props.device.id, this.stateCallback);
} }
setName = () => { setName = () => {