chad/server/index.mjs
Никита Круглицкий c0898d0df2
Some checks failed
Deploy / server (push) Successful in 4m5s
Deploy / client (push) Failing after 36s
#2, #3 update
2025-10-01 21:31:16 +06:00

147 lines
4.4 KiB
JavaScript

import express from "express";
import http from "http";
import cors from "cors";
import { Server } from "socket.io";
import * as mediasoup from "mediasoup";
const app = express();
app.use(cors());
const server = http.createServer(app);
const io = new Server(server, {
path: '/chad/ws',
cors: {
origin: '*'
}
});
let worker;
let router;
const transports = new Map(); // socketId -> [transports]
const producers = new Map(); // socketId -> [producers]
const consumers = new Map(); // socketId -> [consumers]
async function createWorker() {
worker = await mediasoup.createWorker();
worker.on("died", () => {
console.error("mediasoup worker died, exiting...");
process.exit(1);
});
router = await worker.createRouter({
mediaCodecs: [
{
kind: "audio",
mimeType: "audio/opus",
clockRate: 48000,
channels: 2,
}
],
});
console.log("Mediasoup worker & router created");
}
createWorker();
io.on("connection", (socket) => {
console.log("Client connected:", socket.id);
socket.on("getRtpCapabilities", (cb) => {
cb(router.rtpCapabilities);
});
socket.on("createTransport", async (cb) => {
try {
const transport = await router.createWebRtcTransport({
listenIps: [{ ip: "0.0.0.0", announcedIp: "91.144.171.182" }],
enableUdp: true,
enableTcp: true,
preferUdp: true,
});
transports.set(socket.id, [...(transports.get(socket.id) || []), transport]);
cb({
id: transport.id,
iceParameters: transport.iceParameters,
iceCandidates: transport.iceCandidates,
dtlsParameters: transport.dtlsParameters,
});
transport.observer.on("close", () => {
console.log("transport closed", transport.id);
});
} catch (err) {
console.error("createTransport error:", err);
cb({ error: err.message });
}
});
socket.on("connectTransport", async ({ transportId, dtlsParameters }, cb) => {
const transport = transports.get(socket.id)?.find((t) => t.id === transportId);
if (!transport) return cb({ error: "transport not found" });
await transport.connect({ dtlsParameters });
cb({ connected: true });
});
socket.on("produce", async ({ transportId, kind, rtpParameters }, cb) => {
const transport = transports.get(socket.id)?.find((t) => t.id === transportId);
if (!transport) return cb({ error: "transport not found" });
const producer = await transport.produce({ kind, rtpParameters });
producers.set(socket.id, [...(producers.get(socket.id) || []), producer]);
cb({ id: producer.id });
socket.broadcast.emit("newProducer", { producerId: producer.id });
producer.observer.on("close", () => {
console.log("producer closed", producer.id);
});
});
socket.on("consume", async ({ producerId, transportId, rtpCapabilities }, cb) => {
try {
if (!router.canConsume({ producerId, rtpCapabilities })) {
return cb({ error: "cannot consume" });
}
const transport = transports.get(socket.id)?.find((t) => t.id === transportId);
if (!transport) return cb({ error: "transport not found" });
const consumer = await transport.consume({
producerId,
rtpCapabilities,
paused: false,
});
consumers.set(socket.id, [...(consumers.get(socket.id) || []), consumer]);
cb({
id: consumer.id,
producerId,
kind: consumer.kind,
rtpParameters: consumer.rtpParameters,
});
} catch (err) {
console.error("consume error:", err);
cb({ error: err.message });
}
});
socket.on("disconnect", () => {
console.log("Client disconnected:", socket.id);
transports.get(socket.id)?.forEach((t) => t.close());
producers.get(socket.id)?.forEach((p) => p.close());
consumers.get(socket.id)?.forEach((c) => c.close());
transports.delete(socket.id);
producers.delete(socket.id);
consumers.delete(socket.id);
});
});
server.listen(process.env.PORT || 3000);