From 7ed23df3e99694c88a9eb0946361c84ac1d254c7 Mon Sep 17 00:00:00 2001 From: opti1337 Date: Fri, 26 Dec 2025 01:08:44 +0600 Subject: [PATCH] refactor --- server/routes/user.ts | 47 +++++++++ server/socket/webrtc.ts | 172 ++----------------------------- server/types/webrtc.ts | 139 +++++++++++++++++++++++++ server/utils/socket-to-client.ts | 12 +++ 4 files changed, 207 insertions(+), 163 deletions(-) create mode 100644 server/types/webrtc.ts create mode 100644 server/utils/socket-to-client.ts diff --git a/server/routes/user.ts b/server/routes/user.ts index 8c095b0..e1011da 100644 --- a/server/routes/user.ts +++ b/server/routes/user.ts @@ -1,6 +1,7 @@ import type { FastifyInstance } from 'fastify' import { z } from 'zod' import prisma from '../prisma/client.ts' +import { socketToClient } from '../utils/socket-to-client.ts' export default function (fastify: FastifyInstance) { fastify.get('/preferences', async (req, reply) => { @@ -47,4 +48,50 @@ export default function (fastify: FastifyInstance) { } } }) + + fastify.patch('/profile', async (req, reply) => { + if (!req.user) { + reply.code(401).send(false) + + return + } + + try { + const schema = z.object({ + displayName: z.string().optional(), + }) + const input = schema.parse(req.body) + + const updatedUser = prisma.user.update({ + where: { userId: req.user.id }, + data: { + displayName: input.displayName, + }, + }) + + const namespace = fastify.io.of('/webrtc') + const sockets = await namespace.fetchSockets() + + const found = sockets.find(socket => socket.id === req.user!.id) + + if (found) { + found.data.displayName = input.displayName + + namespace.emit('clientChanged', found.id, socketToClient(found)) + } + + return updatedUser + } + catch (err) { + fastify.log.error(err) + reply.code(400) + + if (err instanceof z.ZodError) { + reply.send({ error: z.prettifyError(err) }) + } + else { + reply.send({ error: err.message }) + } + } + }) } diff --git a/server/socket/webrtc.ts b/server/socket/webrtc.ts index c2ac4da..bfdcf13 100644 --- a/server/socket/webrtc.ts +++ b/server/socket/webrtc.ts @@ -1,145 +1,15 @@ -import type { User } from '@prisma/client' import type { types } from 'mediasoup' -import type { Namespace, RemoteSocket, Socket, Server as SocketServer } from 'socket.io' +import type { Server as SocketServer } from 'socket.io' +import type { + Namespace, + SomeSocket, +} from '../types/webrtc.ts' import { consola } from 'consola' import prisma from '../prisma/client.ts' - -interface ChadClient { - socketId: string - userId: User['id'] - username: User['username'] - displayName: User['displayName'] - inputMuted: boolean - outputMuted: boolean -} - -interface ProducerShort { - producerId: types.Producer['id'] - kind: types.MediaKind -} - -interface ErrorCallbackResult { - error: string -} - -interface SuccessCallbackResult { - ok: true -} - -type EventCallback = (result: T | ErrorCallbackResult) => void - -interface ClientToServerEvents { - join: ( - options: { - rtpCapabilities: types.RtpCapabilities - }, - cb: EventCallback - ) => void - getRtpCapabilities: ( - cb: EventCallback - ) => void - createTransport: ( - options: { - producing: boolean - consuming: boolean - }, - cb: EventCallback> - ) => void - connectTransport: ( - options: { - transportId: types.WebRtcTransport['id'] - dtlsParameters: types.WebRtcTransport['dtlsParameters'] - }, - cb: EventCallback - ) => void - produce: ( - options: { - transportId: types.WebRtcTransport['id'] - kind: types.MediaKind - rtpParameters: types.RtpParameters - }, - cb: EventCallback<{ id: types.Producer['id'] }> - ) => void - closeProducer: ( - options: { - producerId: types.Producer['id'] - }, - cb: EventCallback - ) => void - pauseProducer: ( - options: { - producerId: types.Producer['id'] - }, - cb: EventCallback - ) => void - resumeProducer: ( - options: { - producerId: types.Producer['id'] - }, - cb: EventCallback - ) => void - pauseConsumer: ( - options: { - consumerId: types.Consumer['id'] - }, - cb: EventCallback - ) => void - resumeConsumer: ( - options: { - consumerId: types.Consumer['id'] - }, - cb: EventCallback - ) => void - updateClient: ( - options: Partial>, - cb: EventCallback - ) => void -} - -interface ServerToClientEvents { - authenticated: () => void - newPeer: (arg: ChadClient) => void - producers: (arg: ProducerShort[]) => void - newConsumer: ( - arg: { - socketId: string - producerId: types.Producer['id'] - id: types.Consumer['id'] - kind: types.MediaKind - rtpParameters: types.RtpParameters - type: types.ConsumerType - appData: types.Producer['appData'] - producerPaused: types.Consumer['producerPaused'] - }, - cb: EventCallback - ) => void - peerClosed: (arg: string) => void - consumerClosed: (arg: { consumerId: string }) => void - consumerPaused: (arg: { consumerId: string }) => void - consumerResumed: (arg: { consumerId: string }) => void - consumerScore: (arg: { consumerId: string, score: types.ConsumerScore }) => void - clientChanged: (clientId: ChadClient['socketId'], client: ChadClient) => void -} - -interface InterServerEvent {} - -interface SocketData { - joined: boolean - userId: User['id'] - username: User['username'] - displayName: User['displayName'] - inputMuted: boolean - outputMuted: boolean - rtpCapabilities: types.RtpCapabilities - transports: Map - producers: Map - consumers: Map -} - -type SomeSocket = Socket | RemoteSocket +import { socketToClient } from '../utils/socket-to-client.ts' export default function (io: SocketServer, router: types.Router) { - const namespace: Namespace = io.of('/webrtc') + const namespace: Namespace = io.of('/webrtc') namespace.on('connection', async (socket) => { consola.info('[WebRtc]', 'Client connected', socket.id) @@ -439,24 +309,11 @@ export default function (io: SocketServer, router: types.Router) { }) socket.on('updateClient', async (updatedClient, cb) => { - if (updatedClient.displayName) { - await prisma.user.update({ - where: { - id: socket.data.userId, - }, - data: { - displayName: updatedClient.displayName, - }, - }) - - socket.data.displayName = updatedClient.displayName - } - - if (updatedClient.inputMuted) { + if (typeof updatedClient.inputMuted === 'boolean') { socket.data.inputMuted = updatedClient.inputMuted } - if (updatedClient.outputMuted) { + if (typeof updatedClient.outputMuted === 'boolean') { socket.data.outputMuted = updatedClient.outputMuted } @@ -583,15 +440,4 @@ export default function (io: SocketServer, router: types.Router) { consola.error('_createConsumer() | failed:%o', error) } } - - function socketToClient(socket: SomeSocket): ChadClient { - return { - socketId: socket.id, - userId: socket.data.userId, - username: socket.data.username, - displayName: socket.data.displayName, - inputMuted: socket.data.inputMuted, - outputMuted: socket.data.outputMuted, - } - } } diff --git a/server/types/webrtc.ts b/server/types/webrtc.ts new file mode 100644 index 0000000..f2cd206 --- /dev/null +++ b/server/types/webrtc.ts @@ -0,0 +1,139 @@ +import type { types } from 'mediasoup' +import type { RemoteSocket, Socket, Namespace as SocketNamespace } from 'socket.io' +import type { User } from '../prisma/client' + +export interface ChadClient { + socketId: string + userId: User['id'] + username: User['username'] + displayName: User['displayName'] + inputMuted: boolean + outputMuted: boolean +} + +export interface ProducerShort { + producerId: types.Producer['id'] + kind: types.MediaKind +} + +export interface ErrorCallbackResult { + error: string +} + +export interface SuccessCallbackResult { + ok: true +} + +export type EventCallback = (result: T | ErrorCallbackResult) => void + +export interface ClientToServerEvents { + join: ( + options: { + rtpCapabilities: types.RtpCapabilities + }, + cb: EventCallback + ) => void + getRtpCapabilities: ( + cb: EventCallback + ) => void + createTransport: ( + options: { + producing: boolean + consuming: boolean + }, + cb: EventCallback> + ) => void + connectTransport: ( + options: { + transportId: types.WebRtcTransport['id'] + dtlsParameters: types.WebRtcTransport['dtlsParameters'] + }, + cb: EventCallback + ) => void + produce: ( + options: { + transportId: types.WebRtcTransport['id'] + kind: types.MediaKind + rtpParameters: types.RtpParameters + }, + cb: EventCallback<{ id: types.Producer['id'] }> + ) => void + closeProducer: ( + options: { + producerId: types.Producer['id'] + }, + cb: EventCallback + ) => void + pauseProducer: ( + options: { + producerId: types.Producer['id'] + }, + cb: EventCallback + ) => void + resumeProducer: ( + options: { + producerId: types.Producer['id'] + }, + cb: EventCallback + ) => void + pauseConsumer: ( + options: { + consumerId: types.Consumer['id'] + }, + cb: EventCallback + ) => void + resumeConsumer: ( + options: { + consumerId: types.Consumer['id'] + }, + cb: EventCallback + ) => void + updateClient: ( + options: Partial>, + cb: EventCallback + ) => void +} + +export interface ServerToClientEvents { + authenticated: () => void + newPeer: (arg: ChadClient) => void + producers: (arg: ProducerShort[]) => void + newConsumer: ( + arg: { + socketId: string + producerId: types.Producer['id'] + id: types.Consumer['id'] + kind: types.MediaKind + rtpParameters: types.RtpParameters + type: types.ConsumerType + appData: types.Producer['appData'] + producerPaused: types.Consumer['producerPaused'] + }, + cb: EventCallback + ) => void + peerClosed: (arg: string) => void + consumerClosed: (arg: { consumerId: string }) => void + consumerPaused: (arg: { consumerId: string }) => void + consumerResumed: (arg: { consumerId: string }) => void + consumerScore: (arg: { consumerId: string, score: types.ConsumerScore }) => void + clientChanged: (clientId: ChadClient['socketId'], client: ChadClient) => void +} + +export interface InterServerEvent {} + +export interface SocketData { + joined: boolean + userId: User['id'] + username: User['username'] + displayName: User['displayName'] + inputMuted: boolean + outputMuted: boolean + rtpCapabilities: types.RtpCapabilities + transports: Map + producers: Map + consumers: Map +} + +export type SomeSocket = Socket | RemoteSocket + +export type Namespace = SocketNamespace diff --git a/server/utils/socket-to-client.ts b/server/utils/socket-to-client.ts new file mode 100644 index 0000000..7d024be --- /dev/null +++ b/server/utils/socket-to-client.ts @@ -0,0 +1,12 @@ +import type { ChadClient, SomeSocket } from '../types/webrtc.ts' + +export function socketToClient(socket: SomeSocket): ChadClient { + return { + socketId: socket.id, + userId: socket.data.userId, + username: socket.data.username, + displayName: socket.data.displayName, + inputMuted: socket.data.inputMuted, + outputMuted: socket.data.outputMuted, + } +}