Refactored out websocket api and state stuff
This commit is contained in:
parent
e4f1c1c6a3
commit
d5b65d7a99
@ -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"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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, () => {
|
||||
|
@ -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();
|
||||
}
|
@ -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<void> {
|
||||
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<void> {
|
||||
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<requests.Response | false> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user