87 lines
2.7 KiB
TypeScript
87 lines
2.7 KiB
TypeScript
// apps/web/server.js
|
||
import express from 'express';
|
||
import http from 'http';
|
||
import next from 'next';
|
||
import { WebSocketServer } from 'ws';
|
||
import { applyWSSHandler } from '@trpc/server/adapters/ws';
|
||
import { appRouter } from '@lifetracker/trpc/routers/_app';
|
||
import { createWSContext } from '@/server/api/ws';
|
||
import { parse } from 'url';
|
||
import { NextRequestHint } from 'next/dist/server/web/adapter';
|
||
|
||
const dev = process.env.NODE_ENV !== 'production';
|
||
|
||
// Create an Express app and HTTP server.
|
||
const app = express();
|
||
const server = http.createServer(app);
|
||
|
||
const nextApp = next({
|
||
dev,
|
||
customServer: true,
|
||
hostname: process.env.HOSTNAME || "localhost",
|
||
port: Number(process.env.PORT) || 3000,
|
||
});
|
||
const handle = nextApp.getRequestHandler();
|
||
|
||
nextApp.prepare().then(() => {
|
||
|
||
// Fallback to NextJS request handling for everything else.
|
||
app.all('*', (req: express.Request, res: express.Response) => {
|
||
return handle(req, res);
|
||
});
|
||
|
||
// Create a WebSocket server that shares the same HTTP server.
|
||
const wss = new WebSocketServer({
|
||
noServer: true,
|
||
path: '/api/ws',
|
||
});
|
||
|
||
// Attach the TRPC WebSocket handler.
|
||
const handler = applyWSSHandler({
|
||
wss,
|
||
router: appRouter,
|
||
createContext: createWSContext,
|
||
});
|
||
|
||
wss.on('connection', (ws) => {
|
||
console.log(`➕➕ Got new websocket connection (now ${wss.clients.size})`);
|
||
ws.once('close', () => {
|
||
console.log(`➖➖ Closed websocket connection (now ${wss.clients.size})`);
|
||
});
|
||
});
|
||
wss.on('error', function (error) {
|
||
console.log(error);
|
||
});
|
||
|
||
const port = process.env.PORT || 3000;
|
||
server.listen(port, () => {
|
||
console.log(`> Server listening on http://localhost:${port}`);
|
||
console.log(`> TRPC WebSocket server listening at ws://localhost:${port}/api/ws`);
|
||
});
|
||
|
||
app.all('*', (req: express.Request, res: express.Response) => {
|
||
return handle(req, res);
|
||
});
|
||
|
||
server.on('upgrade', (request, socket, head) => {
|
||
const { pathname } = parse(request.url!);
|
||
// Only handle WebSocket upgrades of the specific path(s) your application
|
||
// needs to handle
|
||
if (pathname === "/api/ws") {
|
||
wss.handleUpgrade(request, socket, head, function done(ws) {
|
||
console.log("Socket connected");
|
||
// At this point, you have the WebSocket in `ws`
|
||
// and the original HTTP request in `request` available
|
||
ws.send("Hello from Lifetracker!");
|
||
});
|
||
}
|
||
});
|
||
|
||
// Handle graceful shutdown.
|
||
process.on('SIGTERM', () => {
|
||
console.log('SIGTERM received, shutting down gracefully.');
|
||
handler.broadcastReconnectNotification();
|
||
server.close();
|
||
});
|
||
});
|