128 lines
3.5 KiB
JavaScript
128 lines
3.5 KiB
JavaScript
/**
|
|
* Custom server for Socket.io integration with Next.js
|
|
* Run this with `node server.js` for real-time chat support
|
|
*/
|
|
|
|
const { createServer } = require('http')
|
|
const { parse } = require('url')
|
|
const next = require('next')
|
|
const { Server } = require('socket.io')
|
|
|
|
const dev = process.env.NODE_ENV !== 'production'
|
|
const hostname = 'localhost'
|
|
const port = parseInt(process.env.PORT, 10) || 3000
|
|
|
|
const app = next({ dev, hostname, port })
|
|
const handle = app.getRequestHandler()
|
|
|
|
app.prepare().then(() => {
|
|
const httpServer = createServer((req, res) => {
|
|
const parsedUrl = parse(req.url, true)
|
|
handle(req, res, parsedUrl)
|
|
})
|
|
|
|
// Setup Socket.io on the HTTP server
|
|
const io = new Server(httpServer, {
|
|
cors: {
|
|
origin: process.env.NEXT_PUBLIC_APP_URL || `http://${hostname}:${port}`,
|
|
methods: ['GET', 'POST'],
|
|
credentials: true,
|
|
},
|
|
})
|
|
|
|
// Import Prisma Client
|
|
const { PrismaClient } = require('@prisma/client')
|
|
const prisma = new PrismaClient()
|
|
|
|
io.on('connection', (socket) => {
|
|
console.log('Client connected:', socket.id)
|
|
|
|
// Join a stream room
|
|
socket.on('join:stream', ({ streamId, userId }) => {
|
|
console.log(`User ${userId} joined stream ${streamId}`)
|
|
socket.join(`stream:${streamId}`)
|
|
|
|
// Broadcast viewer count
|
|
const roomSize = io.sockets.adapter.rooms.get(`stream:${streamId}`)?.size || 0
|
|
io.to(`stream:${streamId}`).emit('viewers:update', {
|
|
streamId,
|
|
viewerCount: roomSize,
|
|
})
|
|
|
|
// Update DB
|
|
prisma.stream
|
|
.update({
|
|
where: { id: streamId },
|
|
data: { viewerCount: roomSize },
|
|
})
|
|
.catch(console.error)
|
|
})
|
|
|
|
// Leave stream
|
|
socket.on('leave:stream', ({ streamId, userId }) => {
|
|
socket.leave(`stream:${streamId}`)
|
|
const roomSize = io.sockets.adapter.rooms.get(`stream:${streamId}`)?.size || 0
|
|
io.to(`stream:${streamId}`).emit('viewers:update', {
|
|
streamId,
|
|
viewerCount: roomSize,
|
|
})
|
|
prisma.stream
|
|
.update({
|
|
where: { id: streamId },
|
|
data: { viewerCount: roomSize },
|
|
})
|
|
.catch(console.error)
|
|
})
|
|
|
|
// Chat message
|
|
socket.on('chat:message', async ({ streamId, userId, message }) => {
|
|
try {
|
|
const user = await prisma.user.findUnique({
|
|
where: { id: userId },
|
|
select: {
|
|
id: true,
|
|
displayName: true,
|
|
avatarUrl: true,
|
|
verified: true,
|
|
isCreator: true,
|
|
},
|
|
})
|
|
|
|
if (!user) return socket.emit('chat:error', { message: 'User not found' })
|
|
|
|
const chatMessage = await prisma.chatMessage.create({
|
|
data: {
|
|
streamId,
|
|
userId,
|
|
message: message.trim(),
|
|
badges: user.isCreator ? ['creator'] : [],
|
|
},
|
|
})
|
|
|
|
io.to(`stream:${streamId}`).emit('chat:message', {
|
|
id: chatMessage.id,
|
|
message: chatMessage.message,
|
|
badges: chatMessage.badges,
|
|
user: {
|
|
id: user.id,
|
|
displayName: user.displayName,
|
|
avatarUrl: user.avatarUrl,
|
|
verified: user.verified,
|
|
},
|
|
createdAt: chatMessage.createdAt,
|
|
})
|
|
} catch (error) {
|
|
console.error('Chat error:', error)
|
|
}
|
|
})
|
|
|
|
socket.on('disconnect', () => {
|
|
console.log('Client disconnected:', socket.id)
|
|
})
|
|
})
|
|
|
|
httpServer.listen(port, () => {
|
|
console.log(`> Ready on http://${hostname}:${port}`)
|
|
console.log(`> Socket.io server running`)
|
|
})
|
|
})
|