From d5b65d7a99b7121d4d36225c46ead8f9f372911f Mon Sep 17 00:00:00 2001 From: Alex Mikhalev Date: Mon, 25 Jun 2018 02:20:44 -0600 Subject: [PATCH] Refactored out websocket api and state stuff --- common/sprinklers/schema/list.ts | 2 +- server/app/index.ts | 20 +++--- server/index.ts | 13 ++-- server/state.ts | 6 +- server/websocket/index.ts | 108 +++++++++++++++++-------------- 5 files changed, 80 insertions(+), 69 deletions(-) diff --git a/common/sprinklers/schema/list.ts b/common/sprinklers/schema/list.ts index 2c9d19e..6fde8a9 100644 --- a/common/sprinklers/schema/list.ts +++ b/common/sprinklers/schema/list.ts @@ -2,7 +2,7 @@ import { primitive, PropSchema } from "serializr"; function invariant(cond: boolean, message?: string) { if (!cond) { - throw new Error("[serializr] " + (message || "Illegal State")); + throw new Error("[serializr] " + (message || "Illegal ServerState")); } } diff --git a/server/app/index.ts b/server/app/index.ts index fdaff43..aeac4ce 100644 --- a/server/app/index.ts +++ b/server/app/index.ts @@ -2,19 +2,21 @@ import * as express from "express"; import * as schema from "@common/sprinklers/schema"; import {serialize} from "serializr"; -import {state} from "../state"; +import { ServerState } from "../state"; import logger from "./logger"; import serveApp from "./serveApp"; -const app = express(); +export function createApp(state: ServerState) { + const app = express(); -app.use(logger); + app.use(logger); -app.get("/api/grinklers", (req, res) => { - const j = serialize(schema.sprinklersDevice, state.device); - res.send(j); -}); + app.get("/api/grinklers", (req, res) => { + const j = serialize(schema.sprinklersDevice, state.device); + res.send(j); + }); -serveApp(app); + serveApp(app); -export default app; + return app; +} diff --git a/server/index.ts b/server/index.ts index 322a1a7..5438381 100644 --- a/server/index.ts +++ b/server/index.ts @@ -7,17 +7,20 @@ import log from "@common/logger"; import {Server} from "http"; import * as WebSocket from "ws"; -import app from "./app"; -import {state} from "./state"; -import {handler as webSocketHandler} from "./websocket"; +import { ServerState } from "./state"; +import { createApp } from "./app"; +import { WebSocketApi } from "./websocket"; + +const state = new ServerState(); +const app = createApp(state); +const webSocketApi = new WebSocketApi(state); const port = +(process.env.PORT || 8080); const host = process.env.HOST || "0.0.0.0"; const server = new Server(app); const webSocketServer = new WebSocket.Server({server}); - -webSocketServer.on("connection", webSocketHandler); +webSocketServer.on("connection", webSocketApi.handleConnection); state.start(); server.listen(port, host, () => { diff --git a/server/state.ts b/server/state.ts index 7a160e1..02c607a 100644 --- a/server/state.ts +++ b/server/state.ts @@ -1,7 +1,7 @@ import {SprinklersDevice} from "@common/sprinklers"; import * as mqtt from "@common/sprinklers/mqtt"; -export class State { +export class ServerState { mqttClient!: mqtt.MqttApiClient; device!: SprinklersDevice; @@ -15,6 +15,4 @@ export class State { this.mqttClient.start(); } -} - -export const state: State = new State(); +} \ No newline at end of file diff --git a/server/websocket/index.ts b/server/websocket/index.ts index 70807d6..fe1cb72 100644 --- a/server/websocket/index.ts +++ b/server/websocket/index.ts @@ -1,61 +1,43 @@ -import { autorun } from "mobx"; -import { serialize } from "serializr"; -import * as WebSocket from "ws"; - import log from "@common/logger"; import * as requests from "@common/sprinklers/requests"; import * as schema from "@common/sprinklers/schema"; import * as ws from "@common/sprinklers/websocketData"; +import { autorun } from "mobx"; +import { serialize } from "serializr"; +import * as WebSocket from "ws"; +import { ServerState } from "../state"; -import { state } from "../state"; +export class WebSocketApi { + state: ServerState; -async function doDeviceCallRequest(requestData: ws.IDeviceCallRequest) { - const { deviceName, data } = requestData; - if (deviceName !== "grinklers") { - // error handling? or just get the right device - return false; + constructor(state: ServerState) { + this.state = state; } - const request = schema.requests.deserializeRequest(data); - return state.device.makeRequest(request); -} -async function deviceCallRequest(socket: WebSocket, data: ws.IDeviceCallRequest): Promise { - let response: requests.Response | false; - try { - response = await doDeviceCallRequest(data); - } catch (err) { - response = err; - } - if (response) { - const resData: ws.IDeviceCallResponse = { - type: "deviceCallResponse", - id: data.id, - data: response, + handleConnection = (socket: WebSocket) => { + const disposers = [ + autorun(() => { + const json = serialize(schema.sprinklersDevice, this.state.device); + log.trace({ device: json }); + const data: ws.IDeviceUpdate = { type: "deviceUpdate", name: "grinklers", data: json }; + socket.send(JSON.stringify(data)); + }, { delay: 100 }), + autorun(() => { + const data: ws.IBrokerConnectionUpdate = { + type: "brokerConnectionUpdate", + brokerConnected: this.state.mqttClient.connected, + }; + socket.send(JSON.stringify(data)); + }), + ]; + const stop = () => { + disposers.forEach((disposer) => disposer()); }; - socket.send(JSON.stringify(resData)); + socket.on("message", this.handleSocketMessage); + socket.on("close", () => stop()); } -} -export function handler(socket: WebSocket) { - const disposers = [ - autorun(() => { - const json = serialize(schema.sprinklersDevice, state.device); - log.trace({ device: json }); - const data: ws.IDeviceUpdate = { type: "deviceUpdate", name: "grinklers", data: json }; - socket.send(JSON.stringify(data)); - }, { delay: 100 }), - autorun(() => { - const data: ws.IBrokerConnectionUpdate = { - type: "brokerConnectionUpdate", - brokerConnected: state.mqttClient.connected, - }; - socket.send(JSON.stringify(data)); - }), - ]; - const stop = () => { - disposers.forEach((disposer) => disposer()); - }; - socket.on("message", (socketData: WebSocket.Data) => { + private handleSocketMessage = (socket: WebSocket, socketData: WebSocket.Data) => { if (typeof socketData !== "string") { return log.error({ type: typeof socketData }, "received invalid socket data type from client"); } @@ -67,11 +49,37 @@ export function handler(socket: WebSocket) { } switch (data.type) { case "deviceCallRequest": - deviceCallRequest(socket, data); + this.deviceCallRequest(socket, data); break; default: return log.warn({ data }, "received invalid client message type"); } - }); - socket.on("close", () => stop()); + } + + private async deviceCallRequest(socket: WebSocket, data: ws.IDeviceCallRequest): Promise { + let response: requests.Response | false; + try { + response = await this.doDeviceCallRequest(data); + } catch (err) { + response = err; + } + if (response) { + const resData: ws.IDeviceCallResponse = { + type: "deviceCallResponse", + id: data.id, + data: response, + }; + socket.send(JSON.stringify(resData)); + } + } + + private async doDeviceCallRequest(requestData: ws.IDeviceCallRequest): Promise { + const { deviceName, data } = requestData; + if (deviceName !== "grinklers") { + // error handling? or just get the right device + return false; + } + const request = schema.requests.deserializeRequest(data); + return this.state.device.makeRequest(request); + } }