added http api on client side for token grants
This commit is contained in:
parent
1acd60435f
commit
41ece40a84
@ -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";
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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 {
|
||||
}
|
||||
|
||||
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 {
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
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
Normal file
26
app/state/ClientState.ts
Normal file
@ -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
Normal file
54
app/state/HttpApi.ts
Normal file
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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
Normal file
65
app/state/Token.ts
Normal file
@ -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
Normal file
45
app/state/TokenStore.ts
Normal file
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
}
|
||||
|
@ -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
Normal file
7
common/TokenClaims.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export default interface TokenClaims {
|
||||
iss: string;
|
||||
type: "access" | "refresh";
|
||||
aud: string;
|
||||
name: string;
|
||||
exp: number;
|
||||
}
|
17
common/http.ts
Normal file
17
common/http.ts
Normal file
@ -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;
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import { ConnectionState } from "./ConnectionState";
|
||||
import { SprinklersDevice } from "./SprinklersDevice";
|
||||
|
||||
export interface ISprinklersApi {
|
||||
export interface SprinklersRPC {
|
||||
readonly connectionState: ConnectionState;
|
||||
readonly connected: boolean;
|
||||
|
@ -1,5 +1,5 @@
|
||||
// export * from "./Duration";
|
||||
export * from "./ISprinklersApi";
|
||||
export * from "./SprinklersRPC";
|
||||
export * from "./Program";
|
||||
export * from "./schedule";
|
||||
export * from "./Section";
|
@ -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 {
|
||||
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();
|
@ -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;
|
@ -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",
|
||||
|
@ -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) {
|
||||
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) {
|
||||
|
||||
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) {
|
||||
}
|
||||
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) {
|
||||
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,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";
|
||||
|
@ -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);
|
||||
|
@ -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";
|
||||
|
@ -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 {
|
||||
|
@ -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…
x
Reference in New Issue
Block a user