CRM/backend/app/Services/VoIP/SocketProvider.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,
];
}
}