feat: Setup websockets with socket.io
This commit is contained in:
parent
861418db70
commit
618afe9840
@ -37,6 +37,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"drizzle-orm": "^0.33.0",
|
||||
"postgres": "^3.4.4"
|
||||
"postgres": "^3.4.4",
|
||||
"socket.io": "^4.8.1",
|
||||
"socket.io-client": "^4.8.1"
|
||||
}
|
||||
}
|
||||
|
11
prodServer.ts
Normal file
11
prodServer.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import * as path from 'path';
|
||||
import * as url from 'url';
|
||||
import { createWSSGlobalInstance, onHttpServerUpgrade } from './src/lib/server/webSocketUtils';
|
||||
|
||||
const __filename = url.fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
createWSSGlobalInstance();
|
||||
|
||||
const { server } = await import(path.resolve(__dirname, './build/index.js'));
|
||||
server.server.on('upgrade', onHttpServerUpgrade);
|
29
src/lib/hooks.server.ts
Normal file
29
src/lib/hooks.server.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { building } from '$app/environment';
|
||||
import type { Handle } from '@sveltejs/kit';
|
||||
import { Server as SocketIOServer } from 'socket.io';
|
||||
|
||||
let io: SocketIOServer | undefined;
|
||||
|
||||
const startupSocketIOServer = (httpServer: never) => {
|
||||
if (io) return;
|
||||
console.log('[socket.io:kit] setup');
|
||||
io = new SocketIOServer(httpServer);
|
||||
io.on('connection', (socket) => {
|
||||
console.log(`[socket.io:kit] client connected (${socket.id})`);
|
||||
socket.emit('message', `Hello from SvelteKit ${new Date().toLocaleString()} (${socket.id})`);
|
||||
|
||||
socket.on('disconnect', () => {
|
||||
console.log(`[socket.io:kit] client disconnected (${socket.id})`);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const handle = (async ({ event, resolve }) => {
|
||||
if (!building) {
|
||||
startupSocketIOServer(event.locals.httpServer);
|
||||
event.locals.io = io;
|
||||
}
|
||||
return resolve(event, {
|
||||
filterSerializedResponseHeaders: (name) => name === 'content-type'
|
||||
});
|
||||
}) satisfies Handle;
|
51
src/lib/server/webSocketUtils.ts
Normal file
51
src/lib/server/webSocketUtils.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import { parse } from 'url';
|
||||
import { WebSocketServer } from 'ws';
|
||||
import { nanoid } from 'nanoid';
|
||||
import type { Server, WebSocket as WebSocketBase } from 'ws';
|
||||
import type { IncomingMessage } from 'http';
|
||||
import type { Duplex } from 'stream';
|
||||
|
||||
export const GlobalThisWSS = Symbol.for('sveltekit.wss');
|
||||
|
||||
export interface ExtendedWebSocket extends WebSocketBase {
|
||||
socketId: string;
|
||||
// userId: string;
|
||||
};
|
||||
|
||||
// You can define server-wide functions or class instances here
|
||||
// export interface ExtendedServer extends Server<ExtendedWebSocket> {};
|
||||
|
||||
export type ExtendedWebSocketServer = Server<ExtendedWebSocket>;
|
||||
|
||||
export type ExtendedGlobal = typeof globalThis & {
|
||||
[GlobalThisWSS]: ExtendedWebSocketServer;
|
||||
};
|
||||
|
||||
export const onHttpServerUpgrade = (req: IncomingMessage, sock: Duplex, head: Buffer) => {
|
||||
const pathname = req.url ? parse(req.url).pathname : null;
|
||||
if (pathname !== '/websocket') return;
|
||||
|
||||
const wss = (globalThis as ExtendedGlobal)[GlobalThisWSS];
|
||||
|
||||
wss.handleUpgrade(req, sock, head, (ws) => {
|
||||
console.log('[handleUpgrade] creating new connecttion');
|
||||
wss.emit('connection', ws, req);
|
||||
});
|
||||
};
|
||||
|
||||
export const createWSSGlobalInstance = () => {
|
||||
const wss = new WebSocketServer({ noServer: true }) as ExtendedWebSocketServer;
|
||||
|
||||
(globalThis as ExtendedGlobal)[GlobalThisWSS] = wss;
|
||||
|
||||
wss.on('connection', (ws) => {
|
||||
ws.socketId = nanoid();
|
||||
console.log(`[wss:global] client connected (${ws.socketId})`);
|
||||
|
||||
ws.on('close', () => {
|
||||
console.log(`[wss:global] client disconnected (${ws.socketId})`);
|
||||
});
|
||||
});
|
||||
|
||||
return wss;
|
||||
};
|
@ -1,2 +1,44 @@
|
||||
<h1>Welcome to SvelteKit</h1>
|
||||
<p>Visit <a href="https://svelte.dev/docs/kit">svelte.dev/docs/kit</a> to read the documentation</p>
|
||||
<script lang="ts">
|
||||
import { io } from 'socket.io-client';
|
||||
|
||||
let socket: ReturnType<typeof io> | null = null;
|
||||
let log: string[] = [];
|
||||
|
||||
function logEvent(str: string) {
|
||||
log = [...log, str];
|
||||
}
|
||||
|
||||
function establishSocketIOConnection() {
|
||||
if (socket) return;
|
||||
socket = io();
|
||||
|
||||
socket.on('connect', () => {
|
||||
console.log('[ws] connection open');
|
||||
logEvent('[ws] connection open');
|
||||
});
|
||||
|
||||
socket.on('disconnect', () => {
|
||||
console.log('[ws] connection closed');
|
||||
logEvent('[ws] connection closed');
|
||||
});
|
||||
|
||||
socket.on('message', (data: string) => {
|
||||
console.log('[ws] message received', data);
|
||||
logEvent(`[ws] message received: ${data}`);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<main>
|
||||
<h1 class="text-lg"># SvelteKit with Socket.IO Integration</h1>
|
||||
|
||||
<button class="button" on:click={() => establishSocketIOConnection()}>
|
||||
Establish Socket.IO connection
|
||||
</button>
|
||||
|
||||
<ul>
|
||||
{#each log as event}
|
||||
<li>{event}</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</main>
|
@ -2,10 +2,5 @@ import type { Config } from 'tailwindcss';
|
||||
|
||||
export default {
|
||||
content: ['./src/**/*.{html,js,svelte,ts}'],
|
||||
|
||||
theme: {
|
||||
extend: {}
|
||||
},
|
||||
|
||||
plugins: []
|
||||
} satisfies Config;
|
||||
|
@ -1,6 +1,33 @@
|
||||
import { sveltekit } from '@sveltejs/kit/vite';
|
||||
import { defineConfig } from 'vite';
|
||||
import { Server as SocketIOServer } from 'socket.io';
|
||||
|
||||
function setupSocketIOServer(httpServer: never) {
|
||||
if (!httpServer) {
|
||||
throw new Error('HTTP server is not available');
|
||||
}
|
||||
const io = new SocketIOServer(httpServer);
|
||||
io.on('connection', (socket) => {
|
||||
console.log(`[socket.io] client connected (${socket.id})`);
|
||||
io.emit('message', `Hello from SvelteKit ${new Date().toLocaleString()} (${socket.id})`);
|
||||
|
||||
socket.on('disconnect', () => {
|
||||
console.log(`[socket.io] client disconnected (${socket.id})`);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [sveltekit()]
|
||||
plugins: [
|
||||
sveltekit(),
|
||||
{
|
||||
name: 'integratedSocketIOServer',
|
||||
configureServer(server) {
|
||||
setupSocketIOServer(server.httpServer);
|
||||
},
|
||||
configurePreviewServer(server) {
|
||||
setupSocketIOServer(server.httpServer);
|
||||
}
|
||||
},
|
||||
]
|
||||
});
|
Loading…
Reference in New Issue
Block a user