Redux websockets implemented
This commit is contained in:
parent
a4b59dc922
commit
0805d9d4d0
5 changed files with 61 additions and 82 deletions
|
@ -3,6 +3,7 @@
|
|||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@giantmachines/redux-websocket": "^1.1.7",
|
||||
"@material-ui/core": "^4.9.4",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@testing-library/jest-dom": "^4.2.4",
|
||||
|
|
20
smart-hut/src/endpoint.js
Normal file
20
smart-hut/src/endpoint.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
* Returns the endpoint URL (SmartHut backend URL)
|
||||
* @returns {String} endpoint URL
|
||||
*/
|
||||
export function endpointURL() {
|
||||
return window.BACKEND_URL !== "__BACKEND_URL__"
|
||||
? window.BACKEND_URL
|
||||
: "http://localhost:8080";
|
||||
}
|
||||
|
||||
export function socketURL(token) {
|
||||
const httpURL = new URL(endpointURL());
|
||||
const isSecure = httpURL.protocol === "https:";
|
||||
const protocol = isSecure ? "wss:" : "ws:";
|
||||
const port = httpURL.port || (isSecure ? 443 : 80);
|
||||
const url = `${protocol}//${httpURL.hostname}:${port}/sensor-socket?token=${token}`;
|
||||
console.log('socket url: ', url);
|
||||
return url;
|
||||
}
|
||||
|
|
@ -1,6 +1,9 @@
|
|||
import smartHutStore from "./store";
|
||||
import actions from "./storeActions";
|
||||
import axios from "axios";
|
||||
import { endpointURL, socketURL } from "./endpoint";
|
||||
import { connect, disconnect } from "@giantmachines/redux-websocket";
|
||||
|
||||
|
||||
/**
|
||||
* An object returned by promise rejections in remoteservice
|
||||
|
@ -16,16 +19,6 @@ class RemoteError extends Error {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the endpoint URL (SmartHut backend URL)
|
||||
* @returns {String} endpoint URL
|
||||
*/
|
||||
function endpointURL() {
|
||||
return window.BACKEND_URL !== "__BACKEND_URL__"
|
||||
? window.BACKEND_URL
|
||||
: "http://localhost:8080";
|
||||
}
|
||||
|
||||
const Endpoint = {
|
||||
axiosInstance: axios.create({
|
||||
baseURL: endpointURL(),
|
||||
|
@ -176,7 +169,10 @@ export const RemoteService = {
|
|||
login: (usernameOrEmail, password) => {
|
||||
return (dispatch) => {
|
||||
return Endpoint.login(usernameOrEmail, password)
|
||||
.then((token) => dispatch(actions.loginSuccess(token)))
|
||||
.then((token) => {
|
||||
dispatch(actions.loginSuccess(token))
|
||||
dispatch(connect(socketURL(token)))
|
||||
})
|
||||
.catch((err) => {
|
||||
console.warn("login error", err);
|
||||
throw new RemoteError([
|
||||
|
@ -193,7 +189,10 @@ export const RemoteService = {
|
|||
*/
|
||||
logout: () => {
|
||||
return (dispatch) =>
|
||||
Endpoint.logout().then(void dispatch(actions.logout()));
|
||||
Endpoint.logout().then(() => {
|
||||
dispatch(disconnect())
|
||||
dispatch(actions.logout())
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -476,71 +475,6 @@ for (const key in RemoteService) {
|
|||
RemoteService[key] = RemoteService[key].bind(RemoteService);
|
||||
}
|
||||
|
||||
/** Class to handle connection with the sensor socket */
|
||||
class ServiceSocket {
|
||||
token;
|
||||
authenticated = false;
|
||||
retries = 0;
|
||||
connection;
|
||||
|
||||
static get URL() {
|
||||
const httpURL = new URL(endpointURL());
|
||||
const isSecure = httpURL.protocol === "https:";
|
||||
const protocol = isSecure ? "wss:" : "ws:";
|
||||
const port = httpURL.port || (isSecure ? 443 : 80);
|
||||
return `${protocol}//${httpURL.host}:${port}/sensor-socket`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new sensor socket connection
|
||||
* @param {string} token - The JWT token (needed for authentication)
|
||||
*/
|
||||
constructor(token) {
|
||||
this.token = token;
|
||||
this.authenticated = false;
|
||||
}
|
||||
|
||||
_init() {
|
||||
this.connection = new WebSocket(ServiceSocket.URL);
|
||||
|
||||
this.connection.onopen = (_) => {
|
||||
this.connection.send(JSON.stringify({ token: this.token }));
|
||||
};
|
||||
|
||||
this.connection.onmessage = (evt) => {
|
||||
let data = JSON.parse(evt.data);
|
||||
|
||||
if (!this.authenticated) {
|
||||
if (data.authenticated) {
|
||||
this.authenticated = true;
|
||||
this.retries = 0;
|
||||
} else {
|
||||
console.error("socket authentication failed", data);
|
||||
}
|
||||
} else {
|
||||
this.invokeCallbacks(data);
|
||||
}
|
||||
};
|
||||
|
||||
this.connection.onerror = (evt) => {
|
||||
console.warn("socket error", evt);
|
||||
if (this.retries >= 5) {
|
||||
console.error("too many socket connection retries");
|
||||
return;
|
||||
}
|
||||
this.retries++;
|
||||
this._init();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the underlying websocket connection
|
||||
*/
|
||||
close() {
|
||||
this.connection.close();
|
||||
}
|
||||
}
|
||||
|
||||
export class Forms {
|
||||
/**
|
||||
* Attempts to create a new user from the given data.
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { createStore, applyMiddleware } from "redux";
|
||||
import { createStore, applyMiddleware, compose } from "redux";
|
||||
import thunk from "redux-thunk";
|
||||
import update from "immutability-helper";
|
||||
import reduxWebSocket, { connect } from "@giantmachines/redux-websocket";
|
||||
import { socketURL } from "./endpoint";
|
||||
|
||||
function reducer(previousState, action) {
|
||||
let newState, change;
|
||||
|
@ -229,12 +231,20 @@ function reducer(previousState, action) {
|
|||
},
|
||||
});
|
||||
break;
|
||||
case "REDUX_WEBSOCKET::MESSAGE":
|
||||
const devices = JSON.parse(action.payload.message);
|
||||
console.log(devices);
|
||||
newState = reducer(previousState, {
|
||||
type: "DEVICES_UPDATE",
|
||||
partial: true,
|
||||
devices
|
||||
});
|
||||
break;
|
||||
default:
|
||||
console.warn(`Action type ${action.type} unknown`, action);
|
||||
return previousState;
|
||||
}
|
||||
|
||||
console.log("new state: ", newState);
|
||||
|
||||
return newState;
|
||||
}
|
||||
|
||||
|
@ -274,7 +284,14 @@ function createSmartHutStore() {
|
|||
initialState.login.token = null;
|
||||
}
|
||||
|
||||
return createStore(reducer, initialState, applyMiddleware(thunk));
|
||||
const store = createStore(reducer, initialState,
|
||||
compose(
|
||||
applyMiddleware(thunk),
|
||||
applyMiddleware(reduxWebSocket())));
|
||||
if (initialState.login.loggedIn) {
|
||||
store.dispatch(connect(socketURL(token)));
|
||||
}
|
||||
return store;
|
||||
}
|
||||
|
||||
const smartHutStore = createSmartHutStore();
|
||||
|
|
|
@ -973,6 +973,13 @@
|
|||
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
|
||||
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
|
||||
|
||||
"@giantmachines/redux-websocket@^1.1.7":
|
||||
version "1.1.7"
|
||||
resolved "https://registry.yarnpkg.com/@giantmachines/redux-websocket/-/redux-websocket-1.1.7.tgz#8c045a359cd3f9a73ef141ce722fd14ae754cd1b"
|
||||
integrity sha512-t90k+NcVInXvppMVpU3c7ZC6i58S/jBPqltckAlKfrtc92YmGZ/He3qYT9OiemlvS+/d+R6P/Ed4yEqKVevYdg==
|
||||
dependencies:
|
||||
redux "~4"
|
||||
|
||||
"@hapi/address@2.x.x":
|
||||
version "2.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5"
|
||||
|
@ -9008,7 +9015,7 @@ redux-thunk@^2.3.0:
|
|||
resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622"
|
||||
integrity sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw==
|
||||
|
||||
redux@^4.0.5:
|
||||
redux@^4.0.5, redux@~4:
|
||||
version "4.0.5"
|
||||
resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.5.tgz#4db5de5816e17891de8a80c424232d06f051d93f"
|
||||
integrity sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==
|
||||
|
|
Loading…
Reference in a new issue