testapp: enhance webhook event handling and storage; update room ID handling in forms
This commit is contained in:
parent
8a6066a87c
commit
6a8bae5dec
@ -7,7 +7,7 @@
|
|||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"build:watch": "tsc --watch",
|
"build:watch": "tsc --watch",
|
||||||
"start": "node dist/index.js",
|
"start": "node dist/index.js",
|
||||||
"dev:server": "ts-node-dev --respawn --watch src,public/ts src/index.ts",
|
"dev:server": "ts-node-dev --respawn --watch src,public/ts,public/views src/index.ts",
|
||||||
"dev": "concurrently \"npm:watch:client\" \"npm run dev:server\" --kill-others",
|
"dev": "concurrently \"npm:watch:client\" \"npm run dev:server\" --kill-others",
|
||||||
"build:client": "tsc -p tsconfig.client.json",
|
"build:client": "tsc -p tsconfig.client.json",
|
||||||
"watch:client": "tsc -p tsconfig.client.json --watch"
|
"watch:client": "tsc -p tsconfig.client.json --watch"
|
||||||
|
|||||||
@ -7,6 +7,7 @@ const addEventToLog = (eventType: string, eventMessage: string): void => {
|
|||||||
const eventsList = document.getElementById('events-list');
|
const eventsList = document.getElementById('events-list');
|
||||||
if (eventsList) {
|
if (eventsList) {
|
||||||
const li = document.createElement('li');
|
const li = document.createElement('li');
|
||||||
|
li.className = `event-${eventType}`;
|
||||||
li.textContent = `[ ${eventType} ] : ${eventMessage}`;
|
li.textContent = `[ ${eventType} ] : ${eventMessage}`;
|
||||||
eventsList.appendChild(li);
|
eventsList.appendChild(li);
|
||||||
}
|
}
|
||||||
@ -19,14 +20,54 @@ const escapeHtml = (unsafe: string): string => {
|
|||||||
.replace(/"/g, '"')
|
.replace(/"/g, '"')
|
||||||
.replace(/'/g, ''');
|
.replace(/'/g, ''');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getWebhookEventsFromStorage = (roomId: string): any[] => {
|
||||||
|
const data = localStorage.getItem('webhookEventsByRoom');
|
||||||
|
if (!data) return [];
|
||||||
|
const map = JSON.parse(data);
|
||||||
|
return map[roomId] || [];
|
||||||
|
};
|
||||||
|
|
||||||
|
const saveWebhookEventToStorage = (roomId: string, event: any): void => {
|
||||||
|
const data = localStorage.getItem('webhookEventsByRoom');
|
||||||
|
const map = data ? JSON.parse(data) : {};
|
||||||
|
if (!map[roomId]) map[roomId] = [];
|
||||||
|
map[roomId].push(event);
|
||||||
|
localStorage.setItem('webhookEventsByRoom', JSON.stringify(map));
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearWebhookEventsByRoom = (roomId: string): void => {
|
||||||
|
const data = localStorage.getItem('webhookEventsByRoom');
|
||||||
|
if (!data) return;
|
||||||
|
const map = JSON.parse(data);
|
||||||
|
if (map[roomId]) {
|
||||||
|
map[roomId] = [];
|
||||||
|
localStorage.setItem('webhookEventsByRoom', JSON.stringify(map));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const listenWebhookServerEvents = () => {
|
const listenWebhookServerEvents = () => {
|
||||||
socket.on('webhookEvent', (payload: any) => {
|
socket.on('webhookEvent', (event: any) => {
|
||||||
console.log('Webhook received:', payload);
|
console.log('Webhook received:', event);
|
||||||
|
const isMeetingEnded = event.event === 'meetingEnded';
|
||||||
|
const roomId = event.data.roomId;
|
||||||
|
if (roomId) {
|
||||||
|
saveWebhookEventToStorage(roomId, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
addWebhookEventElement(event);
|
||||||
|
|
||||||
|
// Clean up the previous events
|
||||||
|
if (isMeetingEnded) clearWebhookEventsByRoom(roomId);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const addWebhookEventElement = (event: any) => {
|
||||||
const webhookLogList = document.getElementById('webhook-log-list');
|
const webhookLogList = document.getElementById('webhook-log-list');
|
||||||
if (webhookLogList) {
|
if (webhookLogList) {
|
||||||
// Create unique IDs for this accordion item
|
// Create unique IDs for this accordion item
|
||||||
const itemId = payload.creationDate;
|
const itemId = event.creationDate;
|
||||||
const headerId = `header-${itemId}`;
|
const headerClassName = `webhook-${event.event}`;
|
||||||
const collapseId = `collapse-${itemId}`;
|
const collapseId = `collapse-${itemId}`;
|
||||||
|
|
||||||
// Create accordion item container
|
// Create accordion item container
|
||||||
@ -35,8 +76,7 @@ const listenWebhookServerEvents = () => {
|
|||||||
|
|
||||||
// Create header
|
// Create header
|
||||||
const header = document.createElement('h2');
|
const header = document.createElement('h2');
|
||||||
header.className = 'accordion-header';
|
header.classList.add(headerClassName, 'accordion-header');
|
||||||
header.id = headerId;
|
|
||||||
|
|
||||||
// Create header button
|
// Create header button
|
||||||
const button = document.createElement('button');
|
const button = document.createElement('button');
|
||||||
@ -48,17 +88,17 @@ const listenWebhookServerEvents = () => {
|
|||||||
button.setAttribute('aria-controls', collapseId);
|
button.setAttribute('aria-controls', collapseId);
|
||||||
button.style.padding = '10px';
|
button.style.padding = '10px';
|
||||||
|
|
||||||
if (payload.event === 'meetingStarted') {
|
if (event.event === 'meetingStarted') {
|
||||||
button.classList.add('bg-success');
|
button.classList.add('bg-success');
|
||||||
}
|
}
|
||||||
if (payload.event === 'meetingEnded') {
|
if (event.event === 'meetingEnded') {
|
||||||
button.classList.add('bg-danger');
|
button.classList.add('bg-danger');
|
||||||
}
|
}
|
||||||
if (payload.event.includes('recording')) {
|
if (event.event.includes('recording')) {
|
||||||
button.classList.add('bg-warning');
|
button.classList.add('bg-warning');
|
||||||
}
|
}
|
||||||
// Format the header text with event name and timestamp
|
// Format the header text with event name and timestamp
|
||||||
const date = new Date(payload.creationDate);
|
const date = new Date(event.creationDate);
|
||||||
|
|
||||||
const formattedDate = date.toLocaleString('es-ES', {
|
const formattedDate = date.toLocaleString('es-ES', {
|
||||||
// year: 'numeric',
|
// year: 'numeric',
|
||||||
@ -69,13 +109,13 @@ const listenWebhookServerEvents = () => {
|
|||||||
second: '2-digit',
|
second: '2-digit',
|
||||||
hour12: false,
|
hour12: false,
|
||||||
});
|
});
|
||||||
button.innerHTML = `[${formattedDate}] <strong>${payload.event}</strong>`;
|
button.innerHTML = `[${formattedDate}] <strong>${event.event}</strong>`;
|
||||||
|
|
||||||
// Create collapsible content container
|
// Create collapsible content container
|
||||||
const collapseDiv = document.createElement('div');
|
const collapseDiv = document.createElement('div');
|
||||||
collapseDiv.id = collapseId;
|
collapseDiv.id = collapseId;
|
||||||
collapseDiv.className = 'accordion-collapse collapse';
|
collapseDiv.className = 'accordion-collapse collapse';
|
||||||
collapseDiv.setAttribute('aria-labelledby', headerId);
|
collapseDiv.setAttribute('aria-labelledby', headerClassName);
|
||||||
collapseDiv.setAttribute('data-bs-parent', '#webhook-log-list');
|
collapseDiv.setAttribute('data-bs-parent', '#webhook-log-list');
|
||||||
|
|
||||||
// Create body content
|
// Create body content
|
||||||
@ -83,7 +123,7 @@ const listenWebhookServerEvents = () => {
|
|||||||
bodyDiv.className = 'accordion-body';
|
bodyDiv.className = 'accordion-body';
|
||||||
|
|
||||||
// Format JSON with syntax highlighting if possible
|
// Format JSON with syntax highlighting if possible
|
||||||
const formattedJson = JSON.stringify(payload, null, 2);
|
const formattedJson = JSON.stringify(event, null, 2);
|
||||||
bodyDiv.innerHTML = `<pre class="mb-0"><code>${escapeHtml(
|
bodyDiv.innerHTML = `<pre class="mb-0"><code>${escapeHtml(
|
||||||
formattedJson
|
formattedJson
|
||||||
)}</code></pre>`;
|
)}</code></pre>`;
|
||||||
@ -107,7 +147,6 @@ const listenWebhookServerEvents = () => {
|
|||||||
webhookLogList.removeChild(webhookLogList.lastChild!);
|
webhookLogList.removeChild(webhookLogList.lastChild!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Listen to events from openvidu-meet
|
// Listen to events from openvidu-meet
|
||||||
@ -156,6 +195,14 @@ const setUpWebComponentCommands = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const roomId = document.getElementById('room-id')?.textContent?.trim();
|
||||||
|
if (!roomId) {
|
||||||
|
console.error('Room ID not found in the DOM');
|
||||||
|
alert('Room ID not found in the DOM');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const events = getWebhookEventsFromStorage(roomId);
|
||||||
|
events.forEach((event) => addWebhookEventElement(event));
|
||||||
listenWebhookServerEvents();
|
listenWebhookServerEvents();
|
||||||
listenWebComponentEvents();
|
listenWebComponentEvents();
|
||||||
setUpWebComponentCommands();
|
setUpWebComponentCommands();
|
||||||
|
|||||||
@ -50,6 +50,11 @@
|
|||||||
name="participantRole"
|
name="participantRole"
|
||||||
value="moderator"
|
value="moderator"
|
||||||
/>
|
/>
|
||||||
|
<input
|
||||||
|
type="hidden"
|
||||||
|
name="roomId"
|
||||||
|
value="{{ roomId }}"
|
||||||
|
/>
|
||||||
|
|
||||||
<button type="submit" id="join-as-moderator" class="dropdown-item">
|
<button type="submit" id="join-as-moderator" class="dropdown-item">
|
||||||
Moderator
|
Moderator
|
||||||
@ -68,6 +73,11 @@
|
|||||||
name="participantRole"
|
name="participantRole"
|
||||||
value="publisher"
|
value="publisher"
|
||||||
/>
|
/>
|
||||||
|
<input
|
||||||
|
type="hidden"
|
||||||
|
name="roomId"
|
||||||
|
value="{{ roomId }}"
|
||||||
|
/>
|
||||||
|
|
||||||
<button type="submit" id="join-as-publisher" class="dropdown-item">
|
<button type="submit" id="join-as-publisher" class="dropdown-item">
|
||||||
Publisher
|
Publisher
|
||||||
@ -93,7 +103,7 @@
|
|||||||
|
|
||||||
<form action="/room" method="post">
|
<form action="/room" method="post">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="room-id-prefix" class="form-label">Room Prefix</label>
|
<label for="room-id-prefix" class="form-label">Room Prefix *</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="roomIdPrefix"
|
name="roomIdPrefix"
|
||||||
|
|||||||
@ -17,14 +17,30 @@
|
|||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<!-- Left Sidebar Panel -->
|
<!-- Left Sidebar Panel -->
|
||||||
<div id="control-panel" class="d-flex flex-column">
|
<div id="control-panel" class="d-flex flex-column">
|
||||||
<h3>{{ participantRole }}</h3>
|
<span>
|
||||||
|
<span id="participant-role" class="h5">
|
||||||
|
{{#isModerator}}<span class="badge bg-success">Moderator</span
|
||||||
|
>{{/isModerator}}
|
||||||
|
{{^isModerator
|
||||||
|
|
||||||
|
}}<span class="badge bg-secondary">Participant</span
|
||||||
|
>{{/isModerator}}
|
||||||
|
</span>
|
||||||
|
<span id="room-id" class="text-muted">
|
||||||
|
{{ roomId }}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
<!-- Commands -->
|
<!-- Commands -->
|
||||||
<div class="section">
|
<div class="section">
|
||||||
<h5 class="title">Commands</h5>
|
<h5 class="title">Commands</h5>
|
||||||
{{#isModerator}}
|
{{#isModerator}}
|
||||||
<button id="end-meeting-btn" class="btn btn-danger">End Meeting</button>
|
<button id="end-meeting-btn" class="btn btn-danger">
|
||||||
|
End Meeting
|
||||||
|
</button>
|
||||||
{{/isModerator}}
|
{{/isModerator}}
|
||||||
<button id="leave-room-btn" class="btn btn-warning">Leave Room</button>
|
<button id="leave-room-btn" class="btn btn-warning">
|
||||||
|
Leave Room
|
||||||
|
</button>
|
||||||
<button id="toggle-chat-btn" class="btn btn-success">
|
<button id="toggle-chat-btn" class="btn btn-success">
|
||||||
Toggle Chat
|
Toggle Chat
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import { MeetWebhookEvent } from '../../../typings/src/webhook.model';
|
|||||||
interface JoinRoomRequest {
|
interface JoinRoomRequest {
|
||||||
participantRole: ParticipantRole;
|
participantRole: ParticipantRole;
|
||||||
roomUrl: string;
|
roomUrl: string;
|
||||||
|
roomId: string;
|
||||||
participantName?: string;
|
participantName?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -15,6 +16,7 @@ export const joinRoom = (req: Request, res: Response) => {
|
|||||||
const {
|
const {
|
||||||
participantRole,
|
participantRole,
|
||||||
roomUrl,
|
roomUrl,
|
||||||
|
roomId,
|
||||||
participantName = 'User',
|
participantName = 'User',
|
||||||
} = req.body as JoinRoomRequest;
|
} = req.body as JoinRoomRequest;
|
||||||
if (!roomUrl) {
|
if (!roomUrl) {
|
||||||
@ -24,6 +26,7 @@ export const joinRoom = (req: Request, res: Response) => {
|
|||||||
roomUrl,
|
roomUrl,
|
||||||
participantRole,
|
participantRole,
|
||||||
participantName,
|
participantName,
|
||||||
|
roomId,
|
||||||
isModerator: participantRole === 'moderator',
|
isModerator: participantRole === 'moderator',
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@ -44,5 +44,5 @@ server.listen(PORT, () => {
|
|||||||
console.log(`Meet API URL: ${configService.meetApiUrl}`);
|
console.log(`Meet API URL: ${configService.meetApiUrl}`);
|
||||||
console.log('-----------------------------------------');
|
console.log('-----------------------------------------');
|
||||||
console.log('');
|
console.log('');
|
||||||
console.log('Visit http://localhost:3000/ to access the app');
|
console.log(`Visit http://localhost:${PORT}/ to access the app`);
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user