Update: 2026-06-21 02:53:01

This commit is contained in:
Hamza-Ayed
2026-06-21 02:53:02 +03:00
parent b2fae9ec66
commit 2ac086d1fd
3 changed files with 276 additions and 0 deletions

166
backend/bot/worker.php Normal file
View File

@@ -0,0 +1,166 @@
<?php
require_once __DIR__ . '/../core/bootstrap.php';
require_once __DIR__ . '/../functions.php';
try {
$con = Database::get('main');
} catch (Exception $e) {
http_response_code(500);
echo json_encode(['status' => 'failure', 'message' => 'Database connection failed']);
exit;
}
// =========================================================
// backend/bot/worker.php
// Endpoint for the standalone Android Bot (Worker Node)
// Handles Wallet Payments (ShamCash) and Competitor Pricing
// =========================================================
// 1. Security & Configuration
$SECRET_KEY = getenv('BOT_SECRET_KEY') ?: 'SIRO_BOT_SUPER_SECRET_123';
$ALLOWED_DEVICES = ['SHAM_CASH_BOT_01', 'PRICE_SCRAPER_BOT_01'];
$method = $_SERVER['REQUEST_METHOD'];
// 2. Validate Security (HMAC-SHA256 Signature)
function validateSignature($device_id, $ts, $sig, $secret_key) {
// Prevent replay attacks (valid for 5 minutes)
if (abs(time() - $ts) > 300) {
return false;
}
// Generate the expected signature
$expected_sig = hash_hmac('sha256', $device_id . $ts, $secret_key);
// Secure comparison to prevent timing attacks
return hash_equals($expected_sig, $sig);
}
if ($method === 'GET') {
// ---------------------------------------------------------
// GET: Fetch Pending Task for the Bot
// ---------------------------------------------------------
$device_id = filterRequest('device_id');
$ts = filterRequest('ts');
$sig = filterRequest('sig');
if (!$device_id || !$ts || !$sig) {
jsonError("Missing security parameters");
exit;
}
if (!in_array($device_id, $ALLOWED_DEVICES)) {
jsonError("Device not authorized: " . $device_id);
exit;
}
if (!validateSignature($device_id, $ts, $sig, $SECRET_KEY)) {
jsonError("Invalid signature or expired timestamp");
exit;
}
// Check Redis Queue for tasks
// Queue Name: queue:bot:tasks (Using Main Redis)
$taskJson = $redis->rpop('queue:bot:tasks');
if ($taskJson) {
$task = json_decode($taskJson, true);
echo json_encode([
"status" => "success",
"has_task" => true,
"task" => $task
]);
} else {
echo json_encode([
"status" => "success",
"has_task" => false
]);
}
exit;
} elseif ($method === 'POST') {
// ---------------------------------------------------------
// POST: Submit Result from the Bot
// ---------------------------------------------------------
// Read raw JSON body
$input = json_decode(file_get_contents('php://input'), true);
if (!$input) {
jsonError("Invalid JSON body");
exit;
}
$device_id = $input['device_id'] ?? null;
$ts = $input['ts'] ?? null;
$sig = $input['sig'] ?? null;
$task_id = $input['task_id'] ?? null;
$task_status = $input['status'] ?? null; // 'success' or 'failed'
$result_data = $input['result_data'] ?? [];
if (!$device_id || !$ts || !$sig || !$task_id || !$task_status) {
jsonError("Missing required parameters");
exit;
}
if (!in_array($device_id, $ALLOWED_DEVICES)) {
jsonError("Device not authorized");
exit;
}
if (!validateSignature($device_id, $ts, $sig, $SECRET_KEY)) {
jsonError("Invalid signature or expired timestamp");
exit;
}
$task_type = $input['type'] ?? 'payment';
// Process the result based on task type
if ($task_status === 'success') {
if ($task_type === 'price_check') {
$app_name = $result_data['app'] ?? 'unknown';
$price = (float)($result_data['price'] ?? 0);
$distance_km = (float)($result_data['distance_km'] ?? 0);
$start_lat = (float)($result_data['start_lat'] ?? 0);
$start_lng = (float)($result_data['start_lng'] ?? 0);
$end_lat = (float)($result_data['end_lat'] ?? 0);
$end_lng = (float)($result_data['end_lng'] ?? 0);
// 1. Save to MySQL
$stmt = $con->prepare("
INSERT INTO competitor_prices
(app_name, start_lat, start_lng, end_lat, end_lng, distance_km, price)
VALUES (?, ?, ?, ?, ?, ?, ?)
");
$stmt->execute([$app_name, $start_lat, $start_lng, $end_lat, $end_lng, $distance_km, $price]);
// 2. Save to Redis (Calculate Price Per KM)
if ($distance_km > 0 && $price > 0) {
$pricePerKm = $price / $distance_km;
// Store in Redis (Main) to be used by Pricing Engine
// Store recent 50 prices for the app
$redis->lpush("competitor:price_history:$app_name", $pricePerKm);
$redis->ltrim("competitor:price_history:$app_name", 0, 49);
error_log("[Bot Worker] Price Check $app_name: Dist $distance_km, Price $price");
}
} else {
// It's a payment task
$transaction_id = $result_data['transaction_id'] ?? 'N/A';
// TODO: Update MySQL driver balance/payout status
// $stmt = $con->prepare("UPDATE payouts SET status = 'paid', transaction_ref = ? WHERE task_id = ?");
// $stmt->execute([$transaction_id, $task_id]);
error_log("[Bot Worker] Task $task_id SUCCESS on $device_id. Ref: $transaction_id");
}
} else {
$error_msg = $result_data['error'] ?? 'Unknown Error';
error_log("[Bot Worker] Task $task_id FAILED on $device_id. Reason: $error_msg");
// Optional: Re-queue the task if it failed due to a temporary issue
}
echo json_encode(["status" => "success", "message" => "Result recorded successfully"]);
exit;
} else {
http_response_code(405);
jsonError("Method Not Allowed");
}