Add Contabo Object Storage support for Meet egress recordings.
Deploy Ladill Meet / deploy (push) Successful in 49s
Deploy Ladill Meet / deploy (push) Successful in 49s
Use a dedicated meet-recordings S3 disk with path-style endpoints for Contabo, and pass force_path_style through to LiveKit egress uploads. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+7
-3
@@ -45,16 +45,20 @@ LIVEKIT_API_KEY=
|
||||
LIVEKIT_API_SECRET=
|
||||
|
||||
# --- Recordings & AI ---
|
||||
MEET_RECORDINGS_DISK=local
|
||||
# Use meet-recordings disk when LiveKit egress writes to Contabo Object Storage.
|
||||
MEET_RECORDINGS_DISK=meet-recordings
|
||||
MEET_RECORDING_MAX_MB=512
|
||||
# Server-side recording via LiveKit Egress (recommended for production)
|
||||
MEET_EGRESS_ENABLED=false
|
||||
MEET_EGRESS_WEBHOOK_URL=
|
||||
# Contabo Object Storage (S3-compatible). Keys: Object Storage panel → Account → Security & Access.
|
||||
# Endpoint examples: https://eu2.contabostorage.com https://sin1.contabostorage.com
|
||||
MEET_EGRESS_S3_BUCKET=
|
||||
MEET_EGRESS_S3_REGION=
|
||||
MEET_EGRESS_S3_REGION=default
|
||||
MEET_EGRESS_S3_ENDPOINT=https://eu2.contabostorage.com
|
||||
MEET_EGRESS_S3_USE_PATH_STYLE=true
|
||||
MEET_EGRESS_S3_ACCESS_KEY=
|
||||
MEET_EGRESS_S3_SECRET=
|
||||
MEET_EGRESS_S3_ENDPOINT=
|
||||
MEET_AI_DRIVER=openai
|
||||
MEET_AI_API_KEY=
|
||||
MEET_AI_MODEL=gpt-4o-mini
|
||||
|
||||
@@ -90,7 +90,7 @@ class LiveKitEgressService
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string>|null
|
||||
* @return array<string, bool|string>|null
|
||||
*/
|
||||
protected function s3UploadConfig(): ?array
|
||||
{
|
||||
@@ -103,7 +103,8 @@ class LiveKitEgressService
|
||||
|
||||
$config = [
|
||||
'bucket' => $bucket,
|
||||
'region' => (string) ($egress['region'] ?? 'us-east-1'),
|
||||
'region' => (string) ($egress['region'] ?? 'default'),
|
||||
'force_path_style' => (bool) ($egress['force_path_style'] ?? true),
|
||||
];
|
||||
|
||||
foreach (['access_key', 'secret', 'session_token', 'endpoint', 'assume_role_arn', 'assume_role_external_id'] as $key) {
|
||||
|
||||
@@ -60,6 +60,23 @@ return [
|
||||
'report' => false,
|
||||
],
|
||||
|
||||
// Contabo (or other S3-compatible) bucket for Meet recordings — same creds as LiveKit egress.
|
||||
'meet-recordings' => [
|
||||
'driver' => 's3',
|
||||
'key' => env('MEET_EGRESS_S3_ACCESS_KEY', env('AWS_ACCESS_KEY_ID')),
|
||||
'secret' => env('MEET_EGRESS_S3_SECRET', env('AWS_SECRET_ACCESS_KEY')),
|
||||
'region' => env('MEET_EGRESS_S3_REGION', env('AWS_DEFAULT_REGION', 'default')),
|
||||
'bucket' => env('MEET_EGRESS_S3_BUCKET', env('AWS_BUCKET')),
|
||||
'url' => env('MEET_EGRESS_S3_URL', env('AWS_URL')),
|
||||
'endpoint' => env('MEET_EGRESS_S3_ENDPOINT', env('AWS_ENDPOINT')),
|
||||
'use_path_style_endpoint' => filter_var(
|
||||
env('MEET_EGRESS_S3_USE_PATH_STYLE', env('AWS_USE_PATH_STYLE_ENDPOINT', true)),
|
||||
FILTER_VALIDATE_BOOL,
|
||||
),
|
||||
'throw' => false,
|
||||
'report' => false,
|
||||
],
|
||||
|
||||
'qr' => [
|
||||
'driver' => 'local',
|
||||
'root' => storage_path('app/private/qr'),
|
||||
|
||||
+5
-1
@@ -121,9 +121,13 @@ return [
|
||||
'access_key' => env('MEET_EGRESS_S3_ACCESS_KEY', env('AWS_ACCESS_KEY_ID')),
|
||||
'secret' => env('MEET_EGRESS_S3_SECRET', env('AWS_SECRET_ACCESS_KEY')),
|
||||
'session_token' => env('MEET_EGRESS_S3_SESSION_TOKEN'),
|
||||
'region' => env('MEET_EGRESS_S3_REGION', env('AWS_DEFAULT_REGION', 'us-east-1')),
|
||||
'region' => env('MEET_EGRESS_S3_REGION', env('AWS_DEFAULT_REGION', 'default')),
|
||||
'bucket' => env('MEET_EGRESS_S3_BUCKET', env('AWS_BUCKET')),
|
||||
'endpoint' => env('MEET_EGRESS_S3_ENDPOINT', env('AWS_ENDPOINT')),
|
||||
'force_path_style' => filter_var(
|
||||
env('MEET_EGRESS_S3_USE_PATH_STYLE', env('AWS_USE_PATH_STYLE_ENDPOINT', true)),
|
||||
FILTER_VALIDATE_BOOL,
|
||||
),
|
||||
'assume_role_arn' => env('MEET_EGRESS_S3_ASSUME_ROLE_ARN'),
|
||||
'assume_role_external_id' => env('MEET_EGRESS_S3_ASSUME_ROLE_EXTERNAL_ID'),
|
||||
],
|
||||
|
||||
@@ -203,6 +203,28 @@ class MeetLiveKitEgressRecordingTest extends TestCase
|
||||
$this->assertSame('encoder crashed', $recording->failure_reason);
|
||||
}
|
||||
|
||||
public function test_s3_upload_config_uses_contabo_path_style_defaults(): void
|
||||
{
|
||||
config([
|
||||
'meet.recordings.egress.s3.bucket' => 'ladill-meet',
|
||||
'meet.recordings.egress.s3.endpoint' => 'https://eu2.contabostorage.com',
|
||||
'meet.recordings.egress.s3.region' => 'default',
|
||||
'meet.recordings.egress.s3.force_path_style' => true,
|
||||
'meet.recordings.egress.s3.access_key' => 'access',
|
||||
'meet.recordings.egress.s3.secret' => 'secret',
|
||||
]);
|
||||
|
||||
$service = app(LiveKitEgressService::class);
|
||||
$method = new \ReflectionMethod($service, 's3UploadConfig');
|
||||
$method->setAccessible(true);
|
||||
$config = $method->invoke($service);
|
||||
|
||||
$this->assertSame('ladill-meet', $config['bucket']);
|
||||
$this->assertSame('https://eu2.contabostorage.com', $config['endpoint']);
|
||||
$this->assertSame('default', $config['region']);
|
||||
$this->assertTrue($config['force_path_style']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{0: Session, 1: Participant}
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user