hapticlink / server /src /index.ts
Anuj-Panthri's picture
added get_pong route in server
58fc009
/*
Created by Anne Lefebvre and Anuj Panthri - 2023
Handles the HTTP file serving and the WebSocket connect for HapticTouch
*/
import express, { Application, Request, Response } from "express";
import * as http from "http";
import * as WebSocket from "ws";
import { HapticLinkServer } from "./socket/hapticLinkServer";
import { registerRoutes } from "./socket/routes";
import WebSocketWrapper from "./socket/WebSocketAdapter";
import pino from "pino";
import path from "path";
// If started with --silent, then logging will be disabled.
(() => {
const args = process.argv;
if (args.includes("--silent")) {
return main(false);
}
return main(true);
})();
/**
* Starts HTTP(S) and WS server, initializes HapticLinkServer and handles routing.
* @param {boolean} logging - Defaults true
*/
function main(logging: boolean = true) {
// Added by Anuj
const PING_INTERVAL = parseInt(process.env.PING_INTERVAL as string, 10) || 5 * 1000;
interface LooseWebSocket extends WebSocket {
isAlive?: boolean
}
const port: number = parseInt(process.env.PORT as string, 10) || 3000;
const logger = pino({
level: logging ? "info" : "silent",
formatters: {
bindings(bindings) {
return {
level: bindings.level,
time: bindings.time,
msg: bindings.msg,
};
},
},
});
const app: Application = express();
const server = http.createServer(app);
const wss = new WebSocket.Server({ server });
// The entire build/web directory is statically served.
app.use(express.static(path.join(__dirname, "../../client/build/web")));
// Catch all. If we want to add pages later, then we should probably change this.
app.get("*", (_req: Request, res: Response) => {
res.sendFile(path.join(__dirname + "/../../client/build/web/index.html"));
});
// Routes are in socket/routes/*.ts
// registerRoutes imports and adds them all to router
const hapticLink = new HapticLinkServer();
registerRoutes(hapticLink);
// When a user sends a message, the router checks if that route is available
// and then calls the handler. It also generates a User object for them to store
// data for later requests such as an ID
wss.on("connection", (ws: LooseWebSocket) => {
logger.info("Client Connected");
const wsw = new WebSocketWrapper(ws);
ws.isAlive = true; // Added by Anuj
ws.on("message", (message: string) => {
logger.info(`Received Message: ${message}`);
hapticLink.handleRoute(wsw, message);
});
// Added by Anuj
// When receive pong from a client this is triggered
ws.on('pong', () => {
ws.isAlive = true;
logger.info("received pong");
});
// Added by Anuj
// When receive ping from a client this is triggered
ws.on('ping', () => {
logger.info("received ping");
});
// When a user disconnects, their account is removed, and they are removed from all groups
ws.on("close", () => {
hapticLink.removeUser(wsw);
});
ws.on("error", () => {
hapticLink.removeUser(wsw);
});
ws.send("Welcome");
});
// Added by Anuj
const interval = setInterval(function ping() {
wss.clients.forEach((ws) => {
const client = ws as LooseWebSocket;
if (client.isAlive === false) return ws.terminate();
ws.ping();
client.isAlive = false;
});
}, PING_INTERVAL);
// Added by Anuj
wss.on('close', function close() {
clearInterval(interval);
});
server.listen(port, () => {
logger.info(`Server is running on port ${port}`);
});
}