- Add Metered and ConvexSol (CoTURN) provider drivers with response validation and caching - Add IceCandidateManager with automatic failover and structured logging - Add IceCandidateProviderInterface and DTOs conforming to RTCIceServer format
86 lines
3.3 KiB
PHP
86 lines
3.3 KiB
PHP
<?php
|
|
|
|
namespace App\Services\IceCandidate;
|
|
|
|
use App\Contracts\IceCandidateProviderInterface;
|
|
use App\DTOs\IceCandidatesDto;
|
|
use App\Services\IceCandidate\Providers\ConvexSolIceCandidateProvider;
|
|
use App\Services\IceCandidate\Providers\MeteredIceCandidateProvider;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Illuminate\Support\Manager;
|
|
use Throwable;
|
|
|
|
class IceCandidateManager extends Manager implements IceCandidateProviderInterface
|
|
{
|
|
public function getDefaultDriver(): string
|
|
{
|
|
return $this->config->get('services.ice.default', 'metered');
|
|
}
|
|
|
|
public function getFallbackDriver(): ?string
|
|
{
|
|
return $this->config->get('services.ice.fallback', 'convexsol');
|
|
}
|
|
|
|
/**
|
|
* Retrieve ICE candidates with automatic failover and structured logging.
|
|
*/
|
|
public function getIceCandidates(): IceCandidatesDto
|
|
{
|
|
$primaryDriver = $this->getDefaultDriver();
|
|
|
|
try {
|
|
return $this->driver($primaryDriver)->getIceCandidates();
|
|
} catch (Throwable $primaryException) {
|
|
$fallbackDriver = $this->getFallbackDriver();
|
|
|
|
if ($fallbackDriver && $fallbackDriver !== $primaryDriver) {
|
|
Log::warning("Primary ICE candidate provider [{$primaryDriver}] failed: {$primaryException->getMessage()}. Falling back to [{$fallbackDriver}].", [
|
|
'primary_driver' => $primaryDriver,
|
|
'fallback_driver' => $fallbackDriver,
|
|
'error' => $primaryException->getMessage(),
|
|
]);
|
|
|
|
try {
|
|
return $this->driver($fallbackDriver)->getIceCandidates();
|
|
} catch (Throwable $fallbackException) {
|
|
Log::error("Fallback ICE candidate provider [{$fallbackDriver}] also failed: {$fallbackException->getMessage()}. Using default STUN servers.", [
|
|
'primary_error' => $primaryException->getMessage(),
|
|
'fallback_error' => $fallbackException->getMessage(),
|
|
]);
|
|
|
|
return IceCandidatesDto::defaultStun();
|
|
}
|
|
}
|
|
|
|
Log::error("ICE candidate provider [{$primaryDriver}] failed without fallback: {$primaryException->getMessage()}. Using default STUN servers.", [
|
|
'error' => $primaryException->getMessage(),
|
|
]);
|
|
|
|
return IceCandidatesDto::defaultStun();
|
|
}
|
|
}
|
|
|
|
protected function createMeteredDriver(): IceCandidateProviderInterface
|
|
{
|
|
$config = $this->config->get('services.ice.providers.metered', [
|
|
'url' => $this->config->get('services.metered.url'),
|
|
'key' => $this->config->get('services.metered.key'),
|
|
]);
|
|
|
|
return new MeteredIceCandidateProvider($config);
|
|
}
|
|
|
|
protected function createConvexsolDriver(): IceCandidateProviderInterface
|
|
{
|
|
$config = $this->config->get('services.ice.providers.convexsol', [
|
|
'username' => $this->config->get('services.convexsol.username'),
|
|
'password' => $this->config->get('services.convexsol.password'),
|
|
'turn_urls' => $this->config->get('services.convexsol.turn_urls'),
|
|
'stun_urls' => $this->config->get('services.convexsol.stun_urls'),
|
|
]);
|
|
|
|
return new ConvexSolIceCandidateProvider($config);
|
|
}
|
|
}
|