WIP on redux refactor: last commit before client_server.js removal
This commit is contained in:
parent
636ade0273
commit
c36d298f10
2 changed files with 122 additions and 32 deletions
|
@ -3,6 +3,7 @@ import actions from "./storeActions";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
class Endpoint {
|
class Endpoint {
|
||||||
|
socket = null;
|
||||||
axiosInstance = axios.create({
|
axiosInstance = axios.create({
|
||||||
baseURL: this.URL,
|
baseURL: this.URL,
|
||||||
validateStatus: (status) => status >= 200 && status < 300,
|
validateStatus: (status) => status >= 200 && status < 300,
|
||||||
|
@ -55,6 +56,31 @@ class Endpoint {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Performs login
|
||||||
|
* @param {String} usernameOrEmail
|
||||||
|
* @param {String} password
|
||||||
|
* @returns {Promise<Undefined, String[]>} promise that resolves to void and rejects
|
||||||
|
* with user-fiendly errors as a String array
|
||||||
|
*/
|
||||||
|
static login(dispatch, usernameOrEmail, password) {
|
||||||
|
return Endpoint.axiosInstance
|
||||||
|
.post(`${Endpoint.URL}/auth/login`, {
|
||||||
|
usernameOrEmail,
|
||||||
|
password,
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
localStorage.setItem("token", res.token);
|
||||||
|
localStorage.setItem("exp", new Date().getTime() + 5 * 60 * 60 * 1000);
|
||||||
|
this.socket = new ServiceSocket(res.data.token);
|
||||||
|
return res.data.token;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static logout() {
|
||||||
|
this.socket.close();
|
||||||
|
this.socket = null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs an authenticated GET request
|
* Performs an authenticated GET request
|
||||||
|
@ -126,19 +152,8 @@ export class RemoteService {
|
||||||
*/
|
*/
|
||||||
static login(usernameOrEmail, password) {
|
static login(usernameOrEmail, password) {
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
return Endpoint.axiosInstance
|
return Endpoint.login(dispatch, usernameOrEmail, password)
|
||||||
.post(`${Endpoint.URL}/auth/login`, {
|
.then((token) => dispatch(actions.loginSuccess(token)))
|
||||||
usernameOrEmail,
|
|
||||||
password,
|
|
||||||
})
|
|
||||||
.then((res) => {
|
|
||||||
localStorage.setItem("token", res.token);
|
|
||||||
localStorage.setItem(
|
|
||||||
"exp",
|
|
||||||
new Date().getTime() + 5 * 60 * 60 * 1000
|
|
||||||
);
|
|
||||||
dispatch(actions.loginSuccess(res.token));
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.warn("login error", err);
|
console.warn("login error", err);
|
||||||
return [
|
return [
|
||||||
|
@ -156,7 +171,7 @@ export class RemoteService {
|
||||||
* @param {String} password
|
* @param {String} password
|
||||||
*/
|
*/
|
||||||
static logout() {
|
static logout() {
|
||||||
return (dispatch) => void dispatch(actions.logout());
|
return (dispatch) => Endpoint.logout.then(void dispatch(actions.logout()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -386,6 +401,71 @@ export class RemoteService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Class to handle connection with the sensor socket */
|
||||||
|
class ServiceSocket {
|
||||||
|
token;
|
||||||
|
authenticated = false;
|
||||||
|
retries = 0;
|
||||||
|
connection;
|
||||||
|
|
||||||
|
static get URL() {
|
||||||
|
const httpURL = new URL(Endpoint.URL);
|
||||||
|
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 {
|
export class Forms {
|
||||||
/**
|
/**
|
||||||
* Attempts to create a new user from the given data.
|
* Attempts to create a new user from the given data.
|
||||||
|
|
|
@ -1,22 +1,7 @@
|
||||||
import { createStore } from "redux";
|
import { createStore, applyMiddleware } from "redux";
|
||||||
import { RemoteService } from "./remote";
|
import thunk from "redux-thunk";
|
||||||
import { createDispatchHook } from "react-redux";
|
|
||||||
import actions from "./storeActions";
|
import actions from "./storeActions";
|
||||||
|
|
||||||
const initialToken = localStorage.getItem("token");
|
|
||||||
|
|
||||||
const initialState = {
|
|
||||||
login: {
|
|
||||||
loggedIn: false,
|
|
||||||
token: initialToken ? initialToken : null,
|
|
||||||
},
|
|
||||||
userInfo: null,
|
|
||||||
/** @type {[integer]Room} */
|
|
||||||
rooms: {},
|
|
||||||
/** @type {[integer]Device} */
|
|
||||||
devices: {},
|
|
||||||
};
|
|
||||||
|
|
||||||
function reducer(previousState, action) {
|
function reducer(previousState, action) {
|
||||||
let newState = Object.assign({}, previousState);
|
let newState = Object.assign({}, previousState);
|
||||||
const createOrUpdateRoom = (room) => {
|
const createOrUpdateRoom = (room) => {
|
||||||
|
@ -129,9 +114,34 @@ function reducer(previousState, action) {
|
||||||
console.warn(`Action type ${action.type} unknown`, action);
|
console.warn(`Action type ${action.type} unknown`, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log("new state: ", newState);
|
||||||
return newState;
|
return newState;
|
||||||
}
|
}
|
||||||
|
|
||||||
const smartHutStore = createStore(reducer, initialState);
|
function createSmartHutStore() {
|
||||||
|
const token = localStorage.getItem("token");
|
||||||
|
const exp = localStorage.getItem("exp");
|
||||||
|
|
||||||
|
const initialState = {
|
||||||
|
login: {
|
||||||
|
token: token,
|
||||||
|
},
|
||||||
|
userInfo: null,
|
||||||
|
/** @type {[integer]Room} */
|
||||||
|
rooms: {},
|
||||||
|
/** @type {[integer]Device} */
|
||||||
|
devices: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
initialState.login.loggedIn = token && exp > new Date().getTime();
|
||||||
|
if (!initialState.login.loggedIn) {
|
||||||
|
localStorage.removeItem("token");
|
||||||
|
localStorage.removeItem("exp");
|
||||||
|
initialState.login.token = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return createStore(reducer, initialState, applyMiddleware(thunk));
|
||||||
|
}
|
||||||
|
|
||||||
|
const smartHutStore = createSmartHutStore();
|
||||||
export default smartHutStore;
|
export default smartHutStore;
|
||||||
|
|
Loading…
Reference in a new issue