Files
Hamza-AyedandClaude Opus 5 4d8414c96b feat: استيراد كود سيرو إلى تريبز (سيرو @ecfe7568) — بلا تعديل
قرار المالك 2026-07-27: باك إند سيرو PHP هو المعتمد، وتطبيقاته المجرّبة
ميدانياً تحل محل إعادة البناء المؤرشفة. سيرو نفسه لم يُمسّ.

الخريطة:
  backend · payment_server · loction_server · ride_server ·
  passenger_server · docker · dashboard · stress_test  → الجذر
  siro_rider  → apps/rider          siro_driver  → apps/driver
  siro_admin  → dashboards/admin    siro_service → dashboards/service
  android_bot → apps/android_bot    socialBot    → apps/socialBot

نُسخ المتعقَّب في git سيرو فقط عبر `git archive` (3,198 ملفاً / ~169 م.ب)
لا `cp -r` — فاستُثنيت مخلفات البناء تلقائياً. بلا أي تعديل محتوى عمداً:
كل ما يلي يصير فرقاً مقروءاً مقابل المصدر.

لم يُستورد وسببه: siromove.com (الموقع التسويقي يبقى marketing/ في تريبز،
سيرو فيه 8 ملفات) · docs و planning (تريبز له docs/ الخاص) · deploy.sh
(ليس نشراً على سيرفر بل `git add . && git push origin --all` — فخّ في
مستودع آخر) · transit_dashboard (بانتظار قرار مصير backend-transit و
dashboards/transit-web).

⚠️ لا يبني بعد — ثلاثة نواقص متوقعة ومقصودة:
1. `.env` و `lib/env/env.g.dart` غير متعقَّبين في سيرو (أسرار لكل مستأجر):
   كل تطبيق فلاتر يحتاج .env خاصاً ثم توليد env.g.dart بـ build_runner.
2. إعدادات Firebase (9 ملفات google-services.json و GoogleService-Info.plist)
   يستبعدها .gitignore تريبز — ولكل مستأجر مشروع Firebase خاص أصلاً.
3. apps/driver في سيرو يشير إلى `../../Intaleq/packages/get` خارج المستودع →
   يجب ضمّ الحزم داخله أسوة بـ apps/rider.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 05:14:13 +03:00

129 lines
4.3 KiB
PHP

<?php
// ═══════════════════════════════════════════════════════════════
// driver/ride/create_call_session.php
// PURPOSE : Create a WebRTC call session and notify passenger via FCM
// APP : driver
// AUTH : JWT:driver
// ═══════════════════════════════════════════════════════════════
declare(strict_types=1);
require_once __DIR__ . '/../../../connect.php';
try {
if ($role !== 'driver' || empty($user_id)) {
printFailure('Unauthorized access');
exit;
}
$rideId = $_POST['ride_id'] ?? null;
if (!$rideId) {
printFailure('Ride ID is required');
exit;
}
// 1. Verify ride details and retrieve associated passenger
$stmt = $con->prepare("
SELECT r.id, r.passenger_id, d.first_name, d.last_name
FROM ride r
JOIN driver d ON d.id = r.driver_id
WHERE r.id = :rid AND r.driver_id = :did AND r.status IN ('accepted', 'arrived', 'started', 'begin', 'Begin', 'Apply', 'apply', 'Applied', 'applied')
LIMIT 1
");
$stmt->execute([':rid' => $rideId, ':did' => $user_id]);
$ride = $stmt->fetch();
if (!$ride) {
printFailure('No active ride found matching request', 404);
exit;
}
$passengerId = $ride['passenger_id'];
$callerName = trim($encryptionHelper->decryptData($ride['first_name'] ?? '') . ' ' . $encryptionHelper->decryptData($ride['last_name'] ?? ''));
// 2. Query Node.js signaling server to establish session
$url = (getenv('VOICE_CALL_SERVER_URL') ?: 'https://calls.intaleqapp.com') . '/sessions';
$apiKey = getenv('VOICE_CALL_API_KEY') ?: '';
$ch = curl_init($url);
$payload = json_encode([
'ride_id' => (string)$rideId,
'driver_id' => (string)$user_id,
'passenger_id' => (string)$passengerId
]);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_HTTPHEADER => [
"x-api-key: $apiKey",
"Content-Type: application/json"
],
CURLOPT_TIMEOUT => 5,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_SSL_VERIFYHOST => 2
]);
$result = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200) {
error_log("[driver_create_call_session.php] Signaling server session mapping failed: $result (HTTP $httpCode)");
printFailure('Signaling server error', 502);
exit;
}
$sessionData = json_decode($result, true);
if (!isset($sessionData['session_id'])) {
printFailure('Invalid response schema from signaling server');
exit;
}
$sessionId = $sessionData['session_id'];
// 3. Dispatch data-only FCM call trigger to Passenger
$stmtToken = $con->prepare("
SELECT token
FROM tokens
WHERE passengerID = :pid
ORDER BY id DESC
LIMIT 1
");
$stmtToken->execute([':pid' => $passengerId]);
$passengerTokenRow = $stmtToken->fetch();
if ($passengerTokenRow && !empty($passengerTokenRow['token'])) {
$decryptedToken = $encryptionHelper->decryptData($passengerTokenRow['token']);
sendFcmNotification(
$decryptedToken,
'Incoming Call',
'Incoming WebRTC voice call',
[
'type' => 'incoming_call',
'session_id' => (string)$sessionId,
'caller_name' => $callerName,
'caller_avatar' => '',
'ride_id' => (string)$rideId
],
'incoming_call',
'ding'
);
}
echo json_encode([
'status' => 'success',
'message' => 'Call session created successfully',
'data' => [
'session_id' => $sessionId,
'expires_in' => $sessionData['expires_in'] ?? 60
]
], JSON_UNESCAPED_UNICODE);
exit;
} catch (Throwable $e) {
error_log("[driver_create_call_session.php] Critical exception: " . $e->getMessage());
printFailure('Server error', 500);
}