This commit is contained in:
@@ -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 })
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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<T = SuccessCallbackResult> = (result: T | ErrorCallbackResult) => void
|
||||
|
||||
interface ClientToServerEvents {
|
||||
join: (
|
||||
options: {
|
||||
rtpCapabilities: types.RtpCapabilities
|
||||
},
|
||||
cb: EventCallback<ChadClient[]>
|
||||
) => void
|
||||
getRtpCapabilities: (
|
||||
cb: EventCallback<types.RtpCapabilities>
|
||||
) => void
|
||||
createTransport: (
|
||||
options: {
|
||||
producing: boolean
|
||||
consuming: boolean
|
||||
},
|
||||
cb: EventCallback<Pick<types.WebRtcTransport, 'id' | 'iceParameters' | 'iceCandidates' | 'dtlsParameters'>>
|
||||
) => 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<Omit<ChadClient, 'socketId' | 'userId'>>,
|
||||
cb: EventCallback<ChadClient>
|
||||
) => 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<types.WebRtcTransport['id'], types.WebRtcTransport>
|
||||
producers: Map<types.Producer['id'], types.Producer>
|
||||
consumers: Map<types.Consumer['id'], types.Consumer>
|
||||
}
|
||||
|
||||
type SomeSocket = Socket<ClientToServerEvents, ServerToClientEvents, InterServerEvent, SocketData> | RemoteSocket<ServerToClientEvents, SocketData>
|
||||
import { socketToClient } from '../utils/socket-to-client.ts'
|
||||
|
||||
export default function (io: SocketServer, router: types.Router) {
|
||||
const namespace: Namespace<ClientToServerEvents, ServerToClientEvents, InterServerEvent, SocketData> = 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
139
server/types/webrtc.ts
Normal file
139
server/types/webrtc.ts
Normal file
@@ -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<T = SuccessCallbackResult> = (result: T | ErrorCallbackResult) => void
|
||||
|
||||
export interface ClientToServerEvents {
|
||||
join: (
|
||||
options: {
|
||||
rtpCapabilities: types.RtpCapabilities
|
||||
},
|
||||
cb: EventCallback<ChadClient[]>
|
||||
) => void
|
||||
getRtpCapabilities: (
|
||||
cb: EventCallback<types.RtpCapabilities>
|
||||
) => void
|
||||
createTransport: (
|
||||
options: {
|
||||
producing: boolean
|
||||
consuming: boolean
|
||||
},
|
||||
cb: EventCallback<Pick<types.WebRtcTransport, 'id' | 'iceParameters' | 'iceCandidates' | 'dtlsParameters'>>
|
||||
) => 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<Pick<ChadClient, 'inputMuted' | 'outputMuted'>>,
|
||||
cb: EventCallback<ChadClient>
|
||||
) => 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<types.WebRtcTransport['id'], types.WebRtcTransport>
|
||||
producers: Map<types.Producer['id'], types.Producer>
|
||||
consumers: Map<types.Consumer['id'], types.Consumer>
|
||||
}
|
||||
|
||||
export type SomeSocket = Socket<ClientToServerEvents, ServerToClientEvents, InterServerEvent, SocketData> | RemoteSocket<ServerToClientEvents, SocketData>
|
||||
|
||||
export type Namespace = SocketNamespace<ClientToServerEvents, ServerToClientEvents, InterServerEvent, SocketData>
|
||||
12
server/utils/socket-to-client.ts
Normal file
12
server/utils/socket-to-client.ts
Normal file
@@ -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,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user