import type { FastifyInstance } from 'fastify' import type { ServerOptions } from 'socket.io' import type { ChadClient } from '../types/socket.ts' import { consola } from 'consola' import fp from 'fastify-plugin' import { Server } from 'socket.io' import prisma from '../prisma/client.ts' import registerChannelHandlers from '../socket/channel.ts' import registerWebrtcHandlers from '../socket/webrtc.ts' declare module 'fastify' { interface FastifyInstance { io: Server } } export default fp>( async (fastify, opts) => { fastify.decorate('io', new Server(fastify.server, opts)) fastify.addHook('preClose', () => { fastify.io.disconnectSockets(true) }) fastify.addHook('onClose', async (fastify: FastifyInstance) => { await fastify.io.close() }) fastify.ready(() => { const audioLevelObserver = await fastify.mediasoupRouter.createAudioLevelObserver({ maxEntries: 10, threshold: -80, interval: 800, }) const activeSpeakerObserver = await fastify.mediasoupRouter.createActiveSpeakerObserver() audioLevelObserver.on('volumes', async (volumes: types.AudioLevelObserverVolume[]) => { fastify.io.emit('webrtc:speaking-peers', volumes.map(({ producer, volume }) => { const { socketId } = producer.appData as { socketId: ChadClient['socketId'] } return { clientId: socketId, volume, } })) }) audioLevelObserver.on('silence', () => { fastify.io.emit('webrtc:speaking-peers', []) fastify.io.emit('webrtc:active-speaker', undefined) }) activeSpeakerObserver.on('dominantspeaker', ({ producer }) => { const { socketId } = producer.appData as { socketId: ChadClient['socketId'] } fastify.io.emit('webrtc:active-speaker', socketId) }) fastify.io.on('connection', async (socket) => { consola.info('New connection', socket.id) const user = await prisma.user.findUnique({ where: { id: socket.handshake.auth.userId, }, select: { id: true, username: true, displayName: true, }, }) if (!user) { socket.disconnect() return } const { id, username, displayName } = user socket.data.userId = id socket.data.username = username socket.data.displayName = displayName consola.info('User authorized', ...Object.values(user)) const channel = await registerChannelHandlers(fastify.io, socket) const webrtc = await registerWebrtcHandlers( fastify.io, socket, fastify.mediasoupRouter, audioLevelObserver, activeSpeakerObserver, ) socket.emit('webrtc:authenticated', { ...channel, ...webrtc, rtpCapabilities: fastify.mediasoupRouter.rtpCapabilities, }) }) }) }, { name: 'socket-io', dependencies: ['mediasoup-worker', 'mediasoup-router'] }, ) export const autoConfig: Partial = { path: '/chad/ws', cors: { origin: process.env.CORS_ORIGIN || '*', methods: ['GET', 'POST'], credentials: true, }, }