You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
7.8 KiB
7.8 KiB
PlugNMeet Webhook Integration - Quick Setup Guide
Overview
This project implements automatic webhook integration with PlugNMeet to handle live session events in real-time.
Features
✅ Room Management
- Automatically close sessions when room ends
- Real-time session status updates
✅ Participant Tracking
- Track when users join/leave sessions
- Maintain accurate online status
✅ Recording Management
- Automatically download completed recordings
- Generate video thumbnails
- Save to database with metadata
Prerequisites
Required Software
# Install FFmpeg (required for video thumbnail generation)
sudo apt-get update
sudo apt-get install ffmpeg
# Verify installation
ffmpeg -version
Django Settings
Ensure these settings are configured in your settings.py:
# PlugNMeet Configuration
PLUGNMEET_SERVER_URL = "https://your-plugnmeet-server.com"
PLUGNMEET_API_KEY = "your-api-key"
PLUGNMEET_API_SECRET = "your-api-secret"
PLUGNMEET_TIMEOUT = 10.0
# Media files (for recordings)
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
PlugNMeet Server Configuration
Configure webhook in your PlugNMeet server settings:
# plugnmeet config.yaml
webhooks:
- url: "https://your-django-backend.com/api/course/plugnmeet/webhook/"
events:
- room_finished
- participant_joined
- participant_left
- end_recording
Webhook Endpoint
URL: https://your-domain.com/api/course/plugnmeet/webhook/
Method: POST
Security: HMAC SHA256 signature verification
Events Handled
1. room_finished
- Closes the live session
- Marks all participants as offline
- Sets
ended_attimestamp
2. participant_joined
- Creates
LiveSessionUserentry - Sets user as online
- Records join timestamp
3. participant_left
- Updates
LiveSessionUserentry - Sets user as offline
- Records exit timestamp
4. end_recording
- Fetches recording from PlugNMeet
- Downloads recording file
- Saves to
LiveSessionRecordingmodel - Generates video thumbnail (if applicable)
Testing
Using the Test Script
# Test room_finished event
python scripts/test_webhook.py room_finished
# Test participant_joined event
python scripts/test_webhook.py participant_joined
# Test participant_left event
python scripts/test_webhook.py participant_left
# Test end_recording event
python scripts/test_webhook.py end_recording
# Dry run (show payload without sending)
python scripts/test_webhook.py room_finished --dry-run
Manual Testing with cURL
#!/bin/bash
# Configuration
SECRET="your-api-secret"
URL="https://your-domain.com/api/course/plugnmeet/webhook/"
# Sample payload
PAYLOAD='{
"event": "room_finished",
"room": {
"identity": "test-room-20240101120000"
}
}'
# Calculate signature
SIGNATURE=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "$SECRET" -hex | cut -d' ' -f2)
# Send request
curl -X POST "$URL" \
-H "Content-Type: application/webhook+json" \
-H "Hash-Token: $SIGNATURE" \
-d "$PAYLOAD"
Monitoring
Check Logs
# Django logs
tail -f logs/django.log | grep "PlugNMeet Webhook"
# Specific events
tail -f logs/django.log | grep "end_recording"
tail -f logs/django.log | grep "participant_joined"
Log Messages
[PlugNMeet Webhook] Received webhook request
[PlugNMeet Webhook] Processing event=room_finished
[PlugNMeet Webhook] Session closed - session_id=123 room_id=test-room
[PlugNMeet Webhook] User sessions closed - session_id=123 count=5
[PlugNMeet Webhook] Event processed successfully - event=room_finished
Recording Download Logs
[PlugNMeet Webhook] end_recording - room_id=test-room recording_id=rec_123
[PlugNMeet Webhook] Fetching recording info - recording_id=rec_123
[PlugNMeet Webhook] Getting download token - recording_id=rec_123
[PlugNMeet Webhook] Downloading recording file - recording_id=rec_123
[PlugNMeet Webhook] File downloaded - size=524288000 bytes
[PlugNMeet Webhook] Recording saved - recording_id=456 file=recording.mp4
[PlugNMeet Webhook] Thumbnail generated - recording_id=456
Database Models
CourseLiveSession
{
'id': 123,
'course': Course instance,
'room_id': 'test-room-20240101120000',
'subject': 'Test Session',
'started_at': datetime,
'ended_at': datetime, # Set by webhook
}
LiveSessionUser
{
'id': 456,
'session': CourseLiveSession instance,
'user': User instance,
'role': 'participant' or 'moderator',
'entered_at': datetime, # Set by webhook
'exited_at': datetime, # Set by webhook
'is_online': True/False, # Updated by webhook
}
LiveSessionRecording
{
'id': 789,
'session': CourseLiveSession instance,
'title': 'Test Session - Recording',
'file': FileField, # Downloaded by webhook
'file_time': DurationField,
'recording_type': 'video' or 'voice',
'thumbnail': ImageField, # Generated by webhook
'is_active': True,
}
Troubleshooting
Webhook Not Receiving Events
- Check PlugNMeet server configuration
- Verify webhook URL is accessible from PlugNMeet server
- Check firewall rules
- Review PlugNMeet server logs
Signature Verification Failed
- Ensure
PLUGNMEET_API_SECRETmatches PlugNMeet config - Check for extra whitespace in settings
- Verify request is coming from PlugNMeet server
Recording Download Failed
- Check PlugNMeet server is accessible
- Verify recording exists:
POST /auth/recording/recordingInfo - Check disk space
- Review media directory permissions
Thumbnail Generation Failed
- Verify ffmpeg is installed:
ffmpeg -version - Check ffmpeg has permissions to read/write temp files
- Review video file format (mp4, webm, mkv supported)
- Check server resources (CPU, memory)
File Upload Errors
# Check media directory permissions
ls -la media/
chmod -R 755 media/
# Check Django settings
python manage.py shell
>>> from django.conf import settings
>>> print(settings.MEDIA_ROOT)
>>> print(settings.MEDIA_URL)
Performance Considerations
Disk Space
- Monitor disk space for recordings
- Implement cleanup policy for old recordings
- Consider using external storage (S3, MinIO)
Processing Time
- Large recordings may take time to download
- Thumbnail generation adds 1-3 seconds per video
- Consider async processing for large files (Celery)
Concurrent Webhooks
- Django handles webhooks synchronously by default
- For high-traffic scenarios, consider:
- Queue system (Celery, RQ)
- Async views (Django 4.1+)
- Horizontal scaling
Migration from Polling
The old polling approach has been deprecated and commented out:
# OLD (Deprecated) - in apps/course/views/course.py
# def _sync_room_status_with_plugnmeet(self, course: Course):
# client = PlugNMeetClient()
# response = client.is_room_active(active_session.room_id)
# ...
# NEW (Webhook-based)
# Room status is automatically updated via webhooks
# No polling required
Security Best Practices
- ✅ Signature Verification: Always enabled (HMAC SHA256)
- ✅ HTTPS Only: Webhook endpoint requires HTTPS
- ✅ IP Whitelist: Consider restricting to PlugNMeet server IP
- ✅ Rate Limiting: Implement rate limiting on webhook endpoint
- ✅ Input Validation: All webhook payloads are validated
- ✅ Error Handling: Comprehensive error handling and logging
Support
For issues or questions:
- Check logs:
logs/django.log - Review documentation:
docs/plugnmeet_webhook.md - Test with script:
scripts/test_webhook.py - Check PlugNMeet docs: https://www.plugnmeet.org/docs