first commit
This commit is contained in:
124
backend/api/pending-call.php
Normal file
124
backend/api/pending-call.php
Normal file
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
/**
|
||||
* GET /api/pending-call
|
||||
*
|
||||
* Called by Caller Android App every 3 seconds to fetch the next pending flash call task.
|
||||
*
|
||||
* Query params:
|
||||
* device_id — Registered device identifier
|
||||
* app_key — Device authentication key
|
||||
*/
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
header('Access-Control-Allow-Methods: GET, OPTIONS');
|
||||
header('Access-Control-Allow-Headers: Content-Type, X-App-Key');
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
||||
http_response_code(204);
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
|
||||
http_response_code(405);
|
||||
echo json_encode(['success' => false, 'message' => 'method_not_allowed']);
|
||||
exit;
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/../includes/Database.php';
|
||||
require_once __DIR__ . '/../includes/Auth.php';
|
||||
require_once __DIR__ . '/../includes/Logger.php';
|
||||
|
||||
// Authenticate — requires device key (Caller Android App)
|
||||
Auth::requireAuth('device');
|
||||
|
||||
$deviceId = $_GET['device_id'] ?? null;
|
||||
|
||||
if (!$deviceId) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['success' => false, 'message' => 'missing_device_id']);
|
||||
RequestLogger::log('pending-call', 'GET', $_GET, 400, 'missing_device_id');
|
||||
exit;
|
||||
}
|
||||
|
||||
$db = Database::getInstance();
|
||||
|
||||
try {
|
||||
// Verify device exists and is active
|
||||
$stmt = $db->prepare(
|
||||
"SELECT id, device_id, is_active FROM caller_devices WHERE device_id = ?"
|
||||
);
|
||||
$stmt->execute([$deviceId]);
|
||||
$device = $stmt->fetch();
|
||||
|
||||
if (!$device || !$device['is_active']) {
|
||||
http_response_code(403);
|
||||
echo json_encode(['success' => false, 'message' => 'device_not_registered_or_inactive']);
|
||||
RequestLogger::log('pending-call', 'GET', $_GET, 403, 'invalid_device');
|
||||
exit;
|
||||
}
|
||||
|
||||
// Update last_seen
|
||||
$stmt = $db->prepare("UPDATE caller_devices SET last_seen = NOW() WHERE device_id = ?");
|
||||
$stmt->execute([$deviceId]);
|
||||
|
||||
// Find oldest pending flash call task
|
||||
// Priority: tasks assigned to this device first, then unassigned tasks
|
||||
$stmt = $db->prepare(
|
||||
"SELECT id, phone, caller_id, expires_at
|
||||
FROM otp_requests
|
||||
WHERE method = 'flash_call'
|
||||
AND status = 'pending'
|
||||
AND expires_at > NOW()
|
||||
AND (device_id IS NULL OR device_id = ?)
|
||||
ORDER BY
|
||||
CASE WHEN device_id = ? THEN 0 ELSE 1 END,
|
||||
created_at ASC
|
||||
LIMIT 1"
|
||||
);
|
||||
$stmt->execute([$deviceId, $deviceId]);
|
||||
$task = $stmt->fetch();
|
||||
|
||||
if (!$task) {
|
||||
echo json_encode(['success' => true, 'task_id' => null]);
|
||||
RequestLogger::log('pending-call', 'GET', $_GET, 200);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Claim this task — update status and assign device
|
||||
$stmt = $db->prepare(
|
||||
"UPDATE otp_requests
|
||||
SET status = 'calling', device_id = ?, updated_at = NOW()
|
||||
WHERE id = ? AND status = 'pending'"
|
||||
);
|
||||
$stmt->execute([$deviceId, $task['id']]);
|
||||
|
||||
// Check if update affected any row (race condition handling)
|
||||
if ($stmt->rowCount() === 0) {
|
||||
// Another device claimed it first
|
||||
echo json_encode(['success' => true, 'task_id' => null]);
|
||||
RequestLogger::log('pending-call', 'GET', $_GET, 200);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Calculate remaining timeout
|
||||
$expiresAt = new \DateTime($task['expires_at']);
|
||||
$now = new \DateTime();
|
||||
$timeoutSeconds = max(10, $expiresAt->getTimestamp() - $now->getTimestamp());
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'task_id' => (int) $task['id'],
|
||||
'phone' => $task['phone'],
|
||||
'caller_id' => $task['caller_id'],
|
||||
'timeout_seconds' => $timeoutSeconds,
|
||||
]);
|
||||
|
||||
RequestLogger::log('pending-call', 'GET', $_GET, 200);
|
||||
|
||||
} catch (\Throwable $e) {
|
||||
error_log('pending-call error: ' . $e->getMessage());
|
||||
http_response_code(500);
|
||||
echo json_encode(['success' => false, 'message' => 'internal_error']);
|
||||
RequestLogger::log('pending-call', 'GET', $_GET, 500, $e->getMessage());
|
||||
}
|
||||
Reference in New Issue
Block a user