diff --git a/advanced-features/openvidu-recording-improved-node/src/config.js b/advanced-features/openvidu-recording-improved-node/src/config.js index b30a112a..413a0e29 100644 --- a/advanced-features/openvidu-recording-improved-node/src/config.js +++ b/advanced-features/openvidu-recording-improved-node/src/config.js @@ -1,4 +1,5 @@ export const SERVER_PORT = process.env.SERVER_PORT || 6080; +export const APP_NAME = "openvidu-recording-improved-tutorial"; // LiveKit configuration export const LIVEKIT_URL = process.env.LIVEKIT_URL || "http://localhost:7880"; @@ -13,3 +14,4 @@ export const AWS_REGION = process.env.AWS_REGION || "us-east-1"; export const S3_BUCKET = process.env.S3_BUCKET || "openvidu"; export const RECORDINGS_PATH = process.env.RECORDINGS_PATH ?? "recordings/"; +export const RECORDINGS_METADATA_PATH = ".metadata/"; diff --git a/advanced-features/openvidu-recording-improved-node/src/controllers/recording.controller.js b/advanced-features/openvidu-recording-improved-node/src/controllers/recording.controller.js index c0ba5e9d..2909a106 100644 --- a/advanced-features/openvidu-recording-improved-node/src/controllers/recording.controller.js +++ b/advanced-features/openvidu-recording-improved-node/src/controllers/recording.controller.js @@ -1,6 +1,12 @@ import { Router } from "express"; import { EgressClient, EncodedFileOutput, EncodedFileType } from "livekit-server-sdk"; -import { LIVEKIT_URL, LIVEKIT_API_KEY, LIVEKIT_API_SECRET, RECORDINGS_PATH } from "../config.js"; +import { + LIVEKIT_URL, + LIVEKIT_API_KEY, + LIVEKIT_API_SECRET, + RECORDINGS_PATH, + RECORDINGS_METADATA_PATH +} from "../config.js"; import { S3Service } from "../services/s3.service.js"; const egressClient = new EgressClient(LIVEKIT_URL, LIVEKIT_API_KEY, LIVEKIT_API_SECRET); @@ -86,12 +92,12 @@ recordingController.get("/", async (req, res) => { try { const keyStart = - RECORDINGS_PATH + ".metadata/" + (roomName ? `${roomName}` + (roomId ? `-${roomId}` : "") : ""); + RECORDINGS_PATH + RECORDINGS_METADATA_PATH + (roomName ? `${roomName}` + (roomId ? `-${roomId}` : "") : ""); const keyEnd = ".json"; const regex = new RegExp(`^${keyStart}.*${keyEnd}$`); // List all Egress metadata files in the recordings path that match the regex - const metadataKeys = await s3Service.listObjects(RECORDINGS_PATH + ".metadata/", regex); + const metadataKeys = await s3Service.listObjects(RECORDINGS_PATH + RECORDINGS_METADATA_PATH, regex); const recordings = await Promise.all(metadataKeys.map((metadataKey) => s3Service.getObjectAsJson(metadataKey))); res.json({ recordings }); } catch (error) { @@ -130,7 +136,7 @@ recordingController.get("/:recordingName", async (req, res) => { recordingController.delete("/:recordingName", async (req, res) => { const { recordingName } = req.params; const recordingKey = RECORDINGS_PATH + recordingName; - const metadataKey = RECORDINGS_PATH + ".metadata/" + recordingName.replace(".mp4", ".json"); + const metadataKey = RECORDINGS_PATH + RECORDINGS_METADATA_PATH + recordingName.replace(".mp4", ".json"); const exists = await s3Service.exists(recordingKey); if (!exists) { diff --git a/advanced-features/openvidu-recording-improved-node/src/controllers/webhook.controller.js b/advanced-features/openvidu-recording-improved-node/src/controllers/webhook.controller.js index 7e9c1824..f2566b80 100644 --- a/advanced-features/openvidu-recording-improved-node/src/controllers/webhook.controller.js +++ b/advanced-features/openvidu-recording-improved-node/src/controllers/webhook.controller.js @@ -1,6 +1,13 @@ import express, { Router } from "express"; import { EgressStatus, RoomServiceClient, WebhookReceiver } from "livekit-server-sdk"; -import { LIVEKIT_URL, LIVEKIT_API_KEY, LIVEKIT_API_SECRET } from "../config.js"; +import { + LIVEKIT_URL, + LIVEKIT_API_KEY, + LIVEKIT_API_SECRET, + APP_NAME, + RECORDINGS_PATH, + RECORDINGS_METADATA_PATH +} from "../config.js"; import { S3Service } from "../services/s3.service.js"; const webhookReceiver = new WebhookReceiver(LIVEKIT_API_KEY, LIVEKIT_API_SECRET); @@ -12,17 +19,22 @@ webhookController.use(express.raw({ type: "application/webhook+json" })); webhookController.post("/", async (req, res) => { try { - const event = await webhookReceiver.receive(req.body, req.get("Authorization")); - console.log(event); + const webhookEvent = await webhookReceiver.receive(req.body, req.get("Authorization")); + const isWebhookRelatedToMe = await checkWebhookRelatedToMe(webhookEvent); - switch (event.event) { - case "egress_started": - case "egress_updated": - await handleEgressUpdated(event.egressInfo); - break; - case "egress_ended": - await handleEgressEnded(event.egressInfo); - break; + if (isWebhookRelatedToMe) { + console.log(webhookEvent); + const { event: eventType, egressInfo } = webhookEvent; + + switch (eventType) { + case "egress_started": + case "egress_updated": + await handleEgressUpdated(egressInfo); + break; + case "egress_ended": + await handleEgressEnded(egressInfo); + break; + } } } catch (error) { console.error("Error validating webhook event.", error); @@ -31,6 +43,25 @@ webhookController.post("/", async (req, res) => { res.status(200).send(); }); +const checkWebhookRelatedToMe = async (webhookEvent) => { + const { room, egressInfo, ingressInfo } = webhookEvent; + let roomInfo = room; + + if (!room || !room.metadata) { + const roomName = room?.name ?? egressInfo?.roomName ?? ingressInfo?.roomName; + const rooms = await roomClient.listRooms([roomName]); + + if (rooms.length === 0) { + return false; + } + + roomInfo = rooms[0]; + } + + const metadata = roomInfo.metadata ? JSON.parse(roomInfo.metadata) : null; + return metadata?.createdBy === APP_NAME; +}; + const handleEgressUpdated = async (egressInfo) => { await updateRecordingStatus(egressInfo); }; @@ -38,7 +69,7 @@ const handleEgressUpdated = async (egressInfo) => { const handleEgressEnded = async (egressInfo) => { const recordingInfo = convertToRecordingInfo(egressInfo); const metadataName = recordingInfo.name.replace(".mp4", ".json"); - const key = `recordings/.metadata/${metadataName}`; + const key = RECORDINGS_PATH + RECORDINGS_METADATA_PATH + metadataName; await s3Service.uploadObject(key, recordingInfo); await updateRecordingStatus(egressInfo); @@ -60,7 +91,7 @@ const updateRecordingStatus = async (egressInfo) => { await roomClient.updateRoomMetadata( roomName, JSON.stringify({ - createdBy: "openvidu-recording-improved-tutorial", + createdBy: APP_NAME, recordingStatus }) ); diff --git a/advanced-features/openvidu-recording-improved-node/src/index.js b/advanced-features/openvidu-recording-improved-node/src/index.js index 4fd92019..5f7526dd 100644 --- a/advanced-features/openvidu-recording-improved-node/src/index.js +++ b/advanced-features/openvidu-recording-improved-node/src/index.js @@ -4,7 +4,7 @@ import cors from "cors"; import path from "path"; import { fileURLToPath } from "url"; import { AccessToken, RoomServiceClient } from "livekit-server-sdk"; -import { LIVEKIT_URL, LIVEKIT_API_KEY, LIVEKIT_API_SECRET, SERVER_PORT } from "./config.js"; +import { LIVEKIT_URL, LIVEKIT_API_KEY, LIVEKIT_API_SECRET, SERVER_PORT, APP_NAME } from "./config.js"; import { recordingController } from "./controllers/recording.controller.js"; import { webhookController } from "./controllers/webhook.controller.js"; @@ -53,7 +53,7 @@ app.post("/token", async (req, res) => { const roomOptions = { name: roomName, metadata: JSON.stringify({ - createdBy: "openvidu-recording-improved-tutorial", + createdBy: APP_NAME, recordingStatus: "STOPPED" }) };