2018-07-02 15:22:59 -06:00
|
|
|
import { createBrowserHistory, History } from "history";
|
2018-08-17 13:48:34 -06:00
|
|
|
import { computed, configure, when } from "mobx";
|
2018-07-08 07:16:17 -06:00
|
|
|
import { RouterStore, syncHistoryWithStore } from "mobx-react-router";
|
2018-07-01 02:00:17 -06:00
|
|
|
|
2018-08-07 21:21:26 +03:00
|
|
|
import { WebSocketRpcClient } from "@client/sprinklersRpc/WebSocketRpcClient";
|
|
|
|
import HttpApi from "@client/state/HttpApi";
|
|
|
|
import { UiStore } from "@client/state/UiStore";
|
2018-08-11 19:28:19 +03:00
|
|
|
import { UserStore } from "@client/state/UserStore";
|
2018-07-13 00:04:59 -06:00
|
|
|
import ApiError from "@common/ApiError";
|
|
|
|
import { ErrorCode } from "@common/ErrorCode";
|
2018-07-08 20:44:45 -07:00
|
|
|
import log from "@common/logger";
|
2018-08-17 14:41:18 -06:00
|
|
|
import { DefaultEvents, TypedEventEmitter } from "@common/TypedEventEmitter";
|
2018-07-08 20:44:45 -07:00
|
|
|
|
2018-08-17 13:48:34 -06:00
|
|
|
interface AppEvents extends DefaultEvents {
|
2018-09-02 02:57:55 -06:00
|
|
|
checkToken(): void;
|
|
|
|
hasToken(): void;
|
2018-08-17 13:48:34 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
export default class AppState extends TypedEventEmitter<AppEvents> {
|
2018-09-02 02:57:55 -06:00
|
|
|
history: History = createBrowserHistory();
|
|
|
|
routerStore = new RouterStore();
|
|
|
|
uiStore = new UiStore();
|
|
|
|
userStore = new UserStore();
|
|
|
|
httpApi = new HttpApi();
|
|
|
|
tokenStore = this.httpApi.tokenStore;
|
|
|
|
sprinklersRpc = new WebSocketRpcClient(this.tokenStore);
|
2018-08-17 13:48:34 -06:00
|
|
|
|
2018-09-02 02:57:55 -06:00
|
|
|
constructor() {
|
|
|
|
super();
|
|
|
|
this.sprinklersRpc.on("newUserData", this.userStore.receiveUserData);
|
|
|
|
this.sprinklersRpc.on("tokenError", this.clearToken);
|
|
|
|
this.httpApi.on("tokenGranted", () => this.emit("hasToken"));
|
|
|
|
this.httpApi.on("tokenError", this.clearToken);
|
2018-08-17 13:48:34 -06:00
|
|
|
|
2018-09-02 02:57:55 -06:00
|
|
|
this.on("checkToken", this.doCheckToken);
|
2018-08-17 13:48:34 -06:00
|
|
|
|
2018-09-02 02:57:55 -06:00
|
|
|
this.on("hasToken", () => {
|
|
|
|
when(() => !this.tokenStore.accessToken.isValid, this.checkToken);
|
|
|
|
this.sprinklersRpc.start();
|
|
|
|
});
|
|
|
|
}
|
2018-07-01 02:00:17 -06:00
|
|
|
|
2018-09-02 02:57:55 -06:00
|
|
|
@computed
|
|
|
|
get isLoggedIn() {
|
|
|
|
return this.tokenStore.accessToken.isValid;
|
|
|
|
}
|
2018-07-08 06:57:03 -06:00
|
|
|
|
2018-09-02 02:57:55 -06:00
|
|
|
async start() {
|
|
|
|
configure({
|
|
|
|
enforceActions: true
|
|
|
|
});
|
2018-08-13 15:11:36 +03:00
|
|
|
|
2018-09-02 02:57:55 -06:00
|
|
|
syncHistoryWithStore(this.history, this.routerStore);
|
|
|
|
await this.tokenStore.loadLocalStorage();
|
2018-07-08 06:57:03 -06:00
|
|
|
|
2018-09-02 02:57:55 -06:00
|
|
|
await this.checkToken();
|
|
|
|
}
|
2018-08-11 19:59:20 +03:00
|
|
|
|
2018-09-02 02:57:55 -06:00
|
|
|
clearToken = (err?: any) => {
|
|
|
|
this.tokenStore.clearAccessToken();
|
|
|
|
this.checkToken();
|
|
|
|
};
|
2018-08-28 05:34:23 -06:00
|
|
|
|
2018-09-02 02:57:55 -06:00
|
|
|
checkToken = () => {
|
|
|
|
this.emit("checkToken");
|
|
|
|
};
|
2018-08-17 13:48:34 -06:00
|
|
|
|
2018-09-02 02:57:55 -06:00
|
|
|
private doCheckToken = async () => {
|
|
|
|
const { accessToken, refreshToken } = this.tokenStore;
|
|
|
|
accessToken.updateCurrentTime();
|
|
|
|
if (accessToken.isValid) {
|
|
|
|
// if the access token is valid, we are good
|
|
|
|
this.emit("hasToken");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!refreshToken.isValid) {
|
|
|
|
// if the refresh token is not valid, need to login again
|
|
|
|
this.history.push("/login");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
await this.httpApi.grantRefresh();
|
|
|
|
this.emit("hasToken");
|
|
|
|
} catch (err) {
|
|
|
|
if (err instanceof ApiError && err.code === ErrorCode.BadToken) {
|
|
|
|
log.warn({ err }, "refresh is bad for some reason, erasing");
|
|
|
|
this.tokenStore.clearAll();
|
|
|
|
this.history.push("/login");
|
|
|
|
} else {
|
|
|
|
log.error({ err }, "could not refresh access token");
|
|
|
|
// TODO: some kind of error page?
|
|
|
|
}
|
2018-07-01 02:00:17 -06:00
|
|
|
}
|
2018-09-02 02:57:55 -06:00
|
|
|
};
|
2018-07-01 02:00:17 -06:00
|
|
|
}
|