114 خطوط
4.6 KiB
PHP
114 خطوط
4.6 KiB
PHP
<?php
|
|
|
|
namespace App\Services\VoIP;
|
|
|
|
use App\Models\Setting;
|
|
|
|
class SocketProvider implements VoIPProviderInterface
|
|
{
|
|
public function initiateCall(string $phone, ?string $callerId = null): array
|
|
{
|
|
$host = Setting::where('key', 'voip_socket_host')->value('value');
|
|
$port = (int) (Setting::where('key', 'voip_socket_port')->value('value') ?: 0);
|
|
$token = Setting::where('key', 'voip_socket_token')->value('value');
|
|
$timeout = (float) (Setting::where('key', 'voip_socket_timeout')->value('value') ?: 5);
|
|
|
|
if (! $host || ! $port) {
|
|
return [
|
|
'success' => false,
|
|
'provider_call_id' => null,
|
|
'message' => 'میزبان یا پورت سوکت تنظیم نشده است',
|
|
'status' => 'configuration_error',
|
|
];
|
|
}
|
|
|
|
$connection = @stream_socket_client("tcp://{$host}:{$port}", $errorCode, $errorMessage, $timeout);
|
|
if (! $connection) {
|
|
return [
|
|
'success' => false,
|
|
'provider_call_id' => null,
|
|
'message' => $errorMessage ?: 'اتصال سوکت برقرار نشد',
|
|
'status' => 'connection_failed',
|
|
'error_code' => $errorCode,
|
|
];
|
|
}
|
|
|
|
stream_set_timeout($connection, (int) ceil($timeout));
|
|
$providerCallId = 'socket_'.uniqid();
|
|
$payload = [
|
|
'type' => 'call.initiate',
|
|
'provider_call_id' => $providerCallId,
|
|
'phone' => $phone,
|
|
'caller_id' => $callerId,
|
|
'token' => $token,
|
|
];
|
|
|
|
fwrite($connection, json_encode($payload, JSON_UNESCAPED_UNICODE)."\n");
|
|
$line = fgets($connection);
|
|
fclose($connection);
|
|
|
|
$response = $line ? json_decode($line, true) : [];
|
|
|
|
return [
|
|
'success' => ($response['success'] ?? false) === true,
|
|
'provider_call_id' => $response['provider_call_id'] ?? $providerCallId,
|
|
'message' => $response['message'] ?? 'درخواست تماس از راه سوکت ارسال شد',
|
|
'status' => $response['status'] ?? 'initiated',
|
|
'raw' => $response,
|
|
];
|
|
}
|
|
|
|
public function getCallStatus(string $providerCallId): array
|
|
{
|
|
return [
|
|
'status' => 'pending',
|
|
'provider_call_id' => $providerCallId,
|
|
];
|
|
}
|
|
|
|
public function getRecordingUrl(string $providerCallId): ?string
|
|
{
|
|
$template = Setting::where('key', 'voip_socket_recording_url')->value('value');
|
|
|
|
return $template ? str_replace('{id}', $providerCallId, $template) : null;
|
|
}
|
|
|
|
public function testConnection(): array
|
|
{
|
|
$missing = [];
|
|
foreach (['voip_socket_host', 'voip_socket_port'] as $key) {
|
|
if (! Setting::where('key', $key)->value('value')) {
|
|
$missing[] = $key;
|
|
}
|
|
}
|
|
|
|
if ($missing !== []) {
|
|
return ['ok' => false, 'message' => 'تنظیمات اتصال سوکت کامل نیست.', 'missing' => $missing];
|
|
}
|
|
|
|
$host = Setting::where('key', 'voip_socket_host')->value('value');
|
|
$port = (int) Setting::where('key', 'voip_socket_port')->value('value');
|
|
$token = Setting::where('key', 'voip_socket_token')->value('value');
|
|
$timeout = (float) (Setting::where('key', 'voip_socket_timeout')->value('value') ?: 5);
|
|
$started = microtime(true);
|
|
$connection = @stream_socket_client("tcp://{$host}:{$port}", $errorCode, $errorMessage, $timeout);
|
|
if (! $connection) {
|
|
return ['ok' => false, 'message' => $errorMessage ?: "اتصال سوکت برقرار نشد ({$errorCode})", 'missing' => []];
|
|
}
|
|
stream_set_timeout($connection, (int) ceil($timeout));
|
|
fwrite($connection, json_encode(['type' => 'health.check', 'token' => $token], JSON_UNESCAPED_UNICODE)."\n");
|
|
$line = fgets($connection);
|
|
$meta = stream_get_meta_data($connection);
|
|
fclose($connection);
|
|
$response = $line ? json_decode($line, true) : null;
|
|
$ok = is_array($response) && (($response['success'] ?? false) === true || ($response['status'] ?? '') === 'ok');
|
|
$latency = (int) round((microtime(true) - $started) * 1000);
|
|
return [
|
|
'ok' => $ok,
|
|
'message' => $ok ? "اتصال و handshake سوکت موفق بود ({$latency} میلیثانیه)." : ($meta['timed_out'] ? 'پاسخ health-check سوکت timeout شد.' : 'سوکت باز شد اما پاسخ health-check معتبر نبود.'),
|
|
'missing' => [],
|
|
'latency_ms' => $latency,
|
|
];
|
|
}
|
|
}
|