Update: 2026-06-21 02:53:01
This commit is contained in:
166
backend/bot/worker.php
Normal file
166
backend/bot/worker.php
Normal 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");
|
||||
}
|
||||
Reference in New Issue
Block a user