Browse Source

added http api on client side for token grants

update-deps
Alex Mikhalev 7 years ago
parent
commit
41ece40a84
  1. 2
      app/components/DeviceView.tsx
  2. 2
      app/components/ProgramTable.tsx
  3. 4
      app/components/RunSectionForm.tsx
  4. 2
      app/components/SectionRunnerView.tsx
  5. 2
      app/components/SectionTable.tsx
  6. 9
      app/index.tsx
  7. 19
      app/sprinklersRpc/websocketClient.ts
  8. 26
      app/state/ClientState.ts
  9. 54
      app/state/HttpApi.ts
  10. 11
      app/state/StateBase.ts
  11. 65
      app/state/Token.ts
  12. 45
      app/state/TokenStore.ts
  13. 8
      app/state/index.ts
  14. 14
      app/state/web.ts
  15. 7
      common/TokenClaims.ts
  16. 17
      common/http.ts
  17. 0
      common/sprinklersRpc/ConnectionState.ts
  18. 0
      common/sprinklersRpc/ErrorCode.ts
  19. 0
      common/sprinklersRpc/Program.ts
  20. 0
      common/sprinklersRpc/Section.ts
  21. 0
      common/sprinklersRpc/SectionRunner.ts
  22. 0
      common/sprinklersRpc/SprinklersDevice.ts
  23. 2
      common/sprinklersRpc/SprinklersRPC.ts
  24. 0
      common/sprinklersRpc/deviceRequests.ts
  25. 2
      common/sprinklersRpc/index.ts
  26. 10
      common/sprinklersRpc/mqtt/index.ts
  27. 0
      common/sprinklersRpc/schedule.ts
  28. 0
      common/sprinklersRpc/schema/common.ts
  29. 0
      common/sprinklersRpc/schema/index.ts
  30. 0
      common/sprinklersRpc/schema/list.ts
  31. 0
      common/sprinklersRpc/schema/requests.ts
  32. 4
      common/sprinklersRpc/websocketData.ts
  33. 1
      package.json
  34. 63
      server/express/authentication.ts
  35. 2
      server/express/index.ts
  36. 2
      server/index.ts
  37. 8
      server/sprinklersRpc/websocketServer.ts
  38. 2
      server/state.ts
  39. 4
      yarn.lock

2
app/components/DeviceView.tsx

@ -4,7 +4,7 @@ import * as React from "react"; @@ -4,7 +4,7 @@ import * as React from "react";
import { Grid, Header, Icon, Item, SemanticICONS } from "semantic-ui-react";
import { injectState, StateBase } from "@app/state";
import { ConnectionState as ConState } from "@common/sprinklers";
import { ConnectionState as ConState } from "@common/sprinklersRpc";
import { ProgramTable, RunSectionForm, SectionRunnerView, SectionTable } from ".";
import "./DeviceView.scss";

2
app/components/ProgramTable.tsx

@ -5,7 +5,7 @@ import * as React from "react"; @@ -5,7 +5,7 @@ import * as React from "react";
import { Button, Table } from "semantic-ui-react";
import { Duration } from "@common/Duration";
import { DateOfYear, Program, Schedule, Section, TimeOfDay, Weekday } from "@common/sprinklers";
import { DateOfYear, Program, Schedule, Section, TimeOfDay, Weekday } from "@common/sprinklersRpc";
function timeToString(time: TimeOfDay) {
return moment(time).format("LTS");

4
app/components/RunSectionForm.tsx

@ -6,8 +6,8 @@ import { DropdownItemProps, DropdownProps, Form, Header, Segment } from "semanti @@ -6,8 +6,8 @@ import { DropdownItemProps, DropdownProps, Form, Header, Segment } from "semanti
import { UiStore } from "@app/state";
import { Duration } from "@common/Duration";
import log from "@common/logger";
import { Section, SprinklersDevice } from "@common/sprinklers";
import { RunSectionResponse } from "@common/sprinklers/deviceRequests";
import { Section, SprinklersDevice } from "@common/sprinklersRpc";
import { RunSectionResponse } from "@common/sprinklersRpc/deviceRequests";
import DurationInput from "./DurationInput";
@observer

2
app/components/SectionRunnerView.tsx

@ -5,7 +5,7 @@ import { Button, Icon, Progress, Segment } from "semantic-ui-react"; @@ -5,7 +5,7 @@ import { Button, Icon, Progress, Segment } from "semantic-ui-react";
import { Duration } from "@common/Duration";
import log from "@common/logger";
import { Section, SectionRun, SectionRunner } from "@common/sprinklers";
import { Section, SectionRun, SectionRunner } from "@common/sprinklersRpc";
interface PausedStateProps {
paused: boolean;

2
app/components/SectionTable.tsx

@ -3,7 +3,7 @@ import { observer } from "mobx-react"; @@ -3,7 +3,7 @@ import { observer } from "mobx-react";
import * as React from "react";
import { Icon, Table } from "semantic-ui-react";
import { Section } from "@common/sprinklers";
import { Section } from "@common/sprinklersRpc";
/* tslint:disable:object-literal-sort-keys */

9
app/index.tsx

@ -3,11 +3,14 @@ import * as ReactDOM from "react-dom"; @@ -3,11 +3,14 @@ import * as ReactDOM from "react-dom";
import { AppContainer } from "react-hot-loader";
import App from "@app/components/App";
import { ProvideState, StateBase } from "@app/state";
import { WebApiState as StateClass } from "@app/state/web";
import { ProvideState, StateBase, WebApiState as StateClass } from "@app/state";
import logger from "@common/logger";
const state: StateBase = new StateClass();
state.start();
state.start()
.catch((err) => {
logger.error({err}, "error starting state");
});
const rootElem = document.getElementById("app");

19
app/sprinklers/websocket.ts → app/sprinklersRpc/websocketClient.ts

@ -3,12 +3,12 @@ import { update } from "serializr"; @@ -3,12 +3,12 @@ import { update } from "serializr";
import * as rpc from "@common/jsonRpc";
import logger from "@common/logger";
import * as deviceRequests from "@common/sprinklers/deviceRequests";
import { ErrorCode } from "@common/sprinklers/ErrorCode";
import * as s from "@common/sprinklers/index";
import * as schema from "@common/sprinklers/schema/index";
import { seralizeRequest } from "@common/sprinklers/schema/requests";
import * as ws from "@common/sprinklers/websocketData";
import * as deviceRequests from "@common/sprinklersRpc/deviceRequests";
import { ErrorCode } from "@common/sprinklersRpc/ErrorCode";
import * as s from "@common/sprinklersRpc/index";
import * as schema from "@common/sprinklersRpc/schema/index";
import { seralizeRequest } from "@common/sprinklersRpc/schema/requests";
import * as ws from "@common/sprinklersRpc/websocketData";
const log = logger.child({ source: "websocket" });
@ -36,7 +36,9 @@ export class WSSprinklersDevice extends s.SprinklersDevice { @@ -36,7 +36,9 @@ export class WSSprinklersDevice extends s.SprinklersDevice {
}
async subscribe() {
await this.api.authenticate("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzcHJpbmtsZXJzMyIsImF1ZCI6IjA4NDQ4N2Q1LWU1NzktNDQ5YS05MzI5LTU5NWJlNGJjMmJiYyIsIm5hbWUiOiJBbGV4IE1pa2hhbGV2IiwidHlwZSI6ImFjY2VzcyIsImV4cCI6MTUzMDQxNzU3MCwiaWF0IjoxNTMwNDE1NzcwfQ.fRGiN_X1j3Hwe8a5y68wXLx1DQPtTkQr9h6Uh848dFM");
if (this.api.accessToken) {
await this.api.authenticate(this.api.accessToken);
}
const subscribeRequest: ws.IDeviceSubscribeRequest = {
deviceId: this.id,
};
@ -58,7 +60,7 @@ export class WSSprinklersDevice extends s.SprinklersDevice { @@ -58,7 +60,7 @@ export class WSSprinklersDevice extends s.SprinklersDevice {
}
}
export class WebSocketApiClient implements s.ISprinklersApi {
export class WebSocketApiClient implements s.SprinklersRPC {
readonly webSocketUrl: string;
devices: Map<string, WSSprinklersDevice> = new Map();
@ -68,6 +70,7 @@ export class WebSocketApiClient implements s.ISprinklersApi { @@ -68,6 +70,7 @@ export class WebSocketApiClient implements s.ISprinklersApi {
private nextRequestId = Math.round(Math.random() * 1000000);
private responseCallbacks: ws.ServerResponseHandlers = {};
private reconnectTimer: number | null = null;
accessToken: string | undefined;
get connected(): boolean {
return this.connectionState.isConnected || false;

26
app/state/ClientState.ts

@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
import { WebSocketApiClient } from "@app/sprinklersRpc/websocketClient";
import HttpApi from "@app/state/HttpApi";
import { UiStore } from "@app/state/UiStore";
const isDev = process.env.NODE_ENV === "development";
const websocketPort = isDev ? 8080 : location.port;
export default class ClientState {
sprinklersApi = new WebSocketApiClient(`ws://${location.hostname}:${websocketPort}`);
uiStore = new UiStore();
httpApi = new HttpApi();
async start() {
if (!this.httpApi.tokenStore.accessToken.isValid) {
if (this.httpApi.tokenStore.refreshToken.isValid) {
await this.httpApi.tokenStore.grantRefresh();
} else {
await this.httpApi.tokenStore.grantPassword("alex", "kakashka");
}
}
this.sprinklersApi.accessToken = this.httpApi.tokenStore.accessToken.token!;
this.sprinklersApi.start();
}
}

54
app/state/HttpApi.ts

@ -0,0 +1,54 @@ @@ -0,0 +1,54 @@
import { Token } from "@app/state/Token";
import { TokenStore } from "@app/state/TokenStore";
export class HttpApiError extends Error {
name = "HttpApiError";
status: number;
constructor(message: string, status: number = 500) {
super(message);
this.status = status;
}
}
export default class HttpApi {
baseUrl: string;
tokenStore: TokenStore;
private get authorizationHeader(): {} | { "Authorization": string } {
if (!this.tokenStore.accessToken) {
return {};
}
return { Authorization: `Bearer ${this.tokenStore.accessToken.token}` };
}
constructor(baseUrl: string = `http://${location.hostname}:${location.port}/api`) {
while (baseUrl.charAt(baseUrl.length - 1) === "/") {
baseUrl = baseUrl.substring(0, baseUrl.length - 1);
}
this.baseUrl = baseUrl;
this.tokenStore = new TokenStore(this);
}
async makeRequest(url: string, options?: RequestInit, body?: any): Promise<any> {
options = options || {};
options = {
headers: {
"Content-Type": "application/json",
...this.authorizationHeader,
...options.headers || {},
},
body: JSON.stringify(body),
...options,
};
const response = await fetch(this.baseUrl + url, options);
const responseBody = await response.json() || {};
if (!response.ok) {
throw new HttpApiError(responseBody.message || response.statusText, response.status);
}
return responseBody;
}
}

11
app/state/StateBase.ts

@ -1,11 +0,0 @@ @@ -1,11 +0,0 @@
import { ISprinklersApi } from "@common/sprinklers";
import { UiStore } from "./UiStore";
export default abstract class StateBase {
abstract readonly sprinklersApi: ISprinklersApi;
uiStore = new UiStore();
start() {
this.sprinklersApi.start();
}
}

65
app/state/Token.ts

@ -0,0 +1,65 @@ @@ -0,0 +1,65 @@
import TokenClaims from "@common/TokenClaims";
import * as jwt from "jsonwebtoken";
import { computed, createAtom, IAtom, observable } from "mobx";
export class Token {
@observable token: string | null;
@computed get claims(): TokenClaims | null {
if (this.token == null) {
return null;
}
return jwt.decode(this.token) as any;
}
private isExpiredAtom: IAtom;
private currentTime!: number;
private expirationTimer: number | undefined;
constructor(token: string | null = null) {
this.token = token;
this.isExpiredAtom = createAtom("Token.isExpired",
this.startUpdating, this.stopUpdating);
this.updateCurrentTime();
}
private updateCurrentTime = (reportChanged: boolean = true) => {
if (reportChanged) {
this.isExpiredAtom.reportChanged();
}
this.currentTime = Date.now() / 1000;
}
get remainingTime(): number {
if (!this.isExpiredAtom.reportObserved()) {
this.updateCurrentTime(false);
}
if (this.claims == null) {
return Number.NEGATIVE_INFINITY;
}
return this.claims.exp - this.currentTime;
}
private startUpdating = () => {
this.stopUpdating();
const remaining = this.remainingTime;
if (remaining > 0) {
this.expirationTimer = setTimeout(this.updateCurrentTime, this.remainingTime);
}
}
private stopUpdating = () => {
if (this.expirationTimer != null) {
clearTimeout(this.expirationTimer);
this.expirationTimer = undefined;
}
}
get isExpired() {
return this.remainingTime <= 0;
}
@computed get isValid() {
return this.token != null && !this.isExpired;
}
}

45
app/state/TokenStore.ts

@ -0,0 +1,45 @@ @@ -0,0 +1,45 @@
import { observable } from "mobx";
import HttpApi, { HttpApiError } from "@app/state/HttpApi";
import { Token } from "@app/state/Token";
import { TokenGrantPasswordRequest, TokenGrantRefreshRequest, TokenGrantResponse } from "@common/http";
import logger from "@common/logger";
export class TokenStore {
@observable accessToken: Token = new Token();
@observable refreshToken: Token = new Token();
private api: HttpApi;
constructor(api: HttpApi) {
this.api = api;
}
async grantPassword(username: string, password: string) {
const request: TokenGrantPasswordRequest = {
grant_type: "password", username, password,
};
const response: TokenGrantResponse = await this.api.makeRequest("/token/grant", {
method: "POST",
}, request);
this.accessToken.token = response.access_token;
this.refreshToken.token = response.refresh_token;
logger.debug({ aud: this.accessToken.claims!.aud }, "got password grant tokens");
}
async grantRefresh() {
if (!this.refreshToken.isValid) {
throw new HttpApiError("can not grant refresh with invalid refresh_token");
}
const request: TokenGrantRefreshRequest = {
grant_type: "refresh", refresh_token: this.refreshToken.token!,
};
const response: TokenGrantResponse = await this.api.makeRequest("/token/grant", {
method: "POST",
}, request);
this.accessToken.token = response.access_token;
this.refreshToken.token = response.refresh_token;
logger.debug({ aud: this.accessToken.claims!.aud }, "got refresh grant tokens");
}
}

8
app/state/index.ts

@ -1,3 +1,9 @@ @@ -1,3 +1,9 @@
export { UiMessage, UiStore } from "./UiStore";
export * from "./reactContext";
export { default as StateBase } from "./StateBase";
export { ClientState as StateBase } from "./ClientState";
import ClientState from "./ClientState";
export class WebApiState extends ClientState {
}

14
app/state/web.ts

@ -1,14 +0,0 @@ @@ -1,14 +0,0 @@
import { MqttApiClient } from "@common/sprinklers/mqtt";
import { WebSocketApiClient } from "../sprinklers/websocket";
import StateBase from "./StateBase";
const isDev = process.env.NODE_ENV === "development";
const websocketPort = isDev ? 8080 : location.port;
export class MqttApiState extends StateBase {
sprinklersApi = new MqttApiClient(`ws://${location.hostname}:1884`);
}
export class WebApiState extends StateBase {
sprinklersApi = new WebSocketApiClient(`ws://${location.hostname}:${websocketPort}`);
}

7
common/TokenClaims.ts

@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
export default interface TokenClaims {
iss: string;
type: "access" | "refresh";
aud: string;
name: string;
exp: number;
}

17
common/http.ts

@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
export interface TokenGrantPasswordRequest {
grant_type: "password";
username: string;
password: string;
}
export interface TokenGrantRefreshRequest {
grant_type: "refresh";
refresh_token: string;
}
export type TokenGrantRequest = TokenGrantPasswordRequest | TokenGrantRefreshRequest;
export interface TokenGrantResponse {
access_token: string;
refresh_token: string;
}

0
common/sprinklers/ConnectionState.ts → common/sprinklersRpc/ConnectionState.ts

0
common/sprinklers/ErrorCode.ts → common/sprinklersRpc/ErrorCode.ts

0
common/sprinklers/Program.ts → common/sprinklersRpc/Program.ts

0
common/sprinklers/Section.ts → common/sprinklersRpc/Section.ts

0
common/sprinklers/SectionRunner.ts → common/sprinklersRpc/SectionRunner.ts

0
common/sprinklers/SprinklersDevice.ts → common/sprinklersRpc/SprinklersDevice.ts

2
common/sprinklers/ISprinklersApi.ts → common/sprinklersRpc/SprinklersRPC.ts

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
import { ConnectionState } from "./ConnectionState";
import { SprinklersDevice } from "./SprinklersDevice";
export interface ISprinklersApi {
export interface SprinklersRPC {
readonly connectionState: ConnectionState;
readonly connected: boolean;

0
common/sprinklers/deviceRequests.ts → common/sprinklersRpc/deviceRequests.ts

2
common/sprinklers/index.ts → common/sprinklersRpc/index.ts

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
// export * from "./Duration";
export * from "./ISprinklersApi";
export * from "./SprinklersRPC";
export * from "./Program";
export * from "./schedule";
export * from "./Section";

10
common/sprinklers/mqtt/index.ts → common/sprinklersRpc/mqtt/index.ts

@ -3,10 +3,10 @@ import * as mqtt from "mqtt"; @@ -3,10 +3,10 @@ import * as mqtt from "mqtt";
import { update } from "serializr";
import logger from "@common/logger";
import * as s from "@common/sprinklers";
import * as requests from "@common/sprinklers/deviceRequests";
import * as schema from "@common/sprinklers/schema";
import { seralizeRequest } from "@common/sprinklers/schema/requests";
import * as s from "@common/sprinklersRpc";
import * as requests from "@common/sprinklersRpc/deviceRequests";
import * as schema from "@common/sprinklersRpc/schema";
import { seralizeRequest } from "@common/sprinklersRpc/schema/requests";
const log = logger.child({ source: "mqtt" });
@ -14,7 +14,7 @@ interface WithRid { @@ -14,7 +14,7 @@ interface WithRid {
rid: number;
}
export class MqttApiClient implements s.ISprinklersApi {
export class MqttApiClient implements s.SprinklersRPC {
readonly mqttUri: string;
client!: mqtt.Client;
@observable connectionState: s.ConnectionState = new s.ConnectionState();

0
common/sprinklers/schedule.ts → common/sprinklersRpc/schedule.ts

0
common/sprinklers/schema/common.ts → common/sprinklersRpc/schema/common.ts

0
common/sprinklers/schema/index.ts → common/sprinklersRpc/schema/index.ts

0
common/sprinklers/schema/list.ts → common/sprinklersRpc/schema/list.ts

0
common/sprinklers/schema/requests.ts → common/sprinklersRpc/schema/requests.ts

4
common/sprinklers/websocketData.ts → common/sprinklersRpc/websocketData.ts

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
import * as rpc from "../jsonRpc/index";
import { Response as ResponseData } from "@common/sprinklers/deviceRequests";
import { ErrorCode } from "@common/sprinklers/ErrorCode";
import { Response as ResponseData } from "@common/sprinklersRpc/deviceRequests";
import { ErrorCode } from "@common/sprinklersRpc/ErrorCode";
export interface IAuthenticateRequest {
accessToken: string;

1
package.json

@ -44,6 +44,7 @@ @@ -44,6 +44,7 @@
"fork-ts-checker-webpack-plugin": "^0.4.2",
"jsonwebtoken": "^8.3.0",
"mobx": "^5.0.3",
"mobx-utils": "^5.0.0",
"module-alias": "^2.1.0",
"moment": "^2.22.2",
"mqtt": "^2.18.1",

63
server/express/authentication.ts

@ -1,9 +1,20 @@ @@ -1,9 +1,20 @@
import * as Express from "express";
import Router from "express-promise-router";
import * as jwt from "jsonwebtoken";
import TokenClaims from "@common/TokenClaims";
import { User } from "../models/User";
import { ServerState } from "../state";
import { ApiError } from "./errors";
import {
TokenGrantPasswordRequest,
TokenGrantRefreshRequest,
TokenGrantRequest,
TokenGrantResponse
} from "@common/http";
export { TokenClaims };
declare global {
namespace Express {
@ -28,14 +39,6 @@ function getExpTime(lifetime: number) { @@ -28,14 +39,6 @@ function getExpTime(lifetime: number) {
return Math.floor(Date.now() / 1000) + lifetime;
}
export interface TokenClaims {
iss: string;
type: "access" | "refresh";
aud: string;
name: string;
exp: number;
}
function signToken(claims: TokenClaims): Promise<string> {
return new Promise((resolve, reject) => {
jwt.sign(claims, JWT_SECRET, (err: Error, encoded: string) => {
@ -94,8 +97,7 @@ export function authentication(state: ServerState) { @@ -94,8 +97,7 @@ export function authentication(state: ServerState) {
const router = Router();
async function passwordGrant(req: Express.Request, res: Express.Response) {
const { body } = req;
async function passwordGrant(body: TokenGrantPasswordRequest, res: Express.Response): Promise<User> {
const { username, password } = body;
if (!body || !username || !password) {
throw new ApiError(400, "Must specify username and password");
@ -106,22 +108,13 @@ export function authentication(state: ServerState) { @@ -106,22 +108,13 @@ export function authentication(state: ServerState) {
}
const passwordMatches = user.comparePassword(password);
if (passwordMatches) {
const [access_token, refresh_token] = await Promise.all(
[await generateAccessToken(user, JWT_SECRET),
await generateRefreshToken(user, JWT_SECRET)]);
res.json({
access_token, refresh_token,
});
return user;
} else {
res.status(400)
.json({
message: "incorrect login",
});
throw new ApiError(400, "User does not exist");
}
}
async function refreshGrant(req: Express.Request, res: Express.Response) {
const { body } = req;
async function refreshGrant(body: TokenGrantRefreshRequest, res: Express.Response): Promise<User> {
const { refresh_token } = body;
if (!body || !refresh_token) {
throw new ApiError(400, "Must specify a refresh_token");
@ -134,24 +127,26 @@ export function authentication(state: ServerState) { @@ -134,24 +127,26 @@ export function authentication(state: ServerState) {
if (!user) {
throw new ApiError(400, "User does not exist");
}
const [access_token, new_refresh_token] = await Promise.all(
[await generateAccessToken(user, JWT_SECRET),
await generateRefreshToken(user, JWT_SECRET)]);
res.json({
access_token, refresh_token: new_refresh_token,
});
return user;
}
router.post("/token/grant", async (req, res) => {
const { body } = req;
const { grant_type } = body;
if (grant_type === "password") {
await passwordGrant(req, res);
} else if (grant_type === "refresh") {
await refreshGrant(req, res);
const body: TokenGrantRequest = req.body;
let user: User;
if (body.grant_type === "password") {
user = await passwordGrant(body, res);
} else if (body.grant_type === "refresh") {
user = await refreshGrant(body, res);
} else {
throw new ApiError(400, "Invalid grant_type");
}
const [access_token, refresh_token] = await Promise.all(
[await generateAccessToken(user, JWT_SECRET),
await generateRefreshToken(user, JWT_SECRET)]);
const response: TokenGrantResponse = {
access_token, refresh_token,
};
res.json(response);
});
router.post("/token/verify", authorizeAccess, async (req, res) => {

2
server/express/index.ts

@ -2,7 +2,7 @@ import * as bodyParser from "body-parser"; @@ -2,7 +2,7 @@ import * as bodyParser from "body-parser";
import * as express from "express";
import { serialize} from "serializr";
import * as schema from "@common/sprinklers/schema";
import * as schema from "@common/sprinklersRpc/schema";
import { ServerState } from "../state";
import logger from "./logger";
import serveApp from "./serveApp";

2
server/index.ts

@ -9,7 +9,7 @@ import * as WebSocket from "ws"; @@ -9,7 +9,7 @@ import * as WebSocket from "ws";
import { ServerState } from "./state";
import { createApp } from "./express";
import { WebSocketApi } from "./websocket";
import { WebSocketApi } from "./sprinklersRpc/websocketServer";
const state = new ServerState();
const app = createApp(state);

8
server/websocket/index.ts → server/sprinklersRpc/websocketServer.ts

@ -4,10 +4,10 @@ import * as WebSocket from "ws"; @@ -4,10 +4,10 @@ import * as WebSocket from "ws";
import * as rpc from "@common/jsonRpc";
import log from "@common/logger";
import * as deviceRequests from "@common/sprinklers/deviceRequests";
import { ErrorCode } from "@common/sprinklers/ErrorCode";
import * as schema from "@common/sprinklers/schema";
import * as ws from "@common/sprinklers/websocketData";
import * as deviceRequests from "@common/sprinklersRpc/deviceRequests";
import { ErrorCode } from "@common/sprinklersRpc/ErrorCode";
import * as schema from "@common/sprinklersRpc/schema";
import * as ws from "@common/sprinklersRpc/websocketData";
import { TokenClaims, verifyToken } from "../express/authentication";
import { ServerState } from "../state";

2
server/state.ts

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
import logger from "@common/logger";
import * as mqtt from "@common/sprinklers/mqtt";
import * as mqtt from "@common/sprinklersRpc/mqtt";
import { Database } from "./models/Database";
export class ServerState {

4
yarn.lock

@ -4138,6 +4138,10 @@ mobx-react@^5.2.3: @@ -4138,6 +4138,10 @@ mobx-react@^5.2.3:
hoist-non-react-statics "^2.5.0"
react-lifecycles-compat "^3.0.2"
mobx-utils@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/mobx-utils/-/mobx-utils-5.0.0.tgz#384e805064c237b9a9446788a9e68278a3437610"
mobx@^5.0.3:
version "5.0.3"
resolved "https://registry.yarnpkg.com/mobx/-/mobx-5.0.3.tgz#53b97f2a0f9b0dd7774c96249f81bf2d513d8e1c"

Loading…
Cancel
Save