185 lines
8.3 KiB
PHP
185 lines
8.3 KiB
PHP
<?php
|
|
/**
|
|
* CRON worker: processes queued rewards jobs.
|
|
*
|
|
* Example cron:
|
|
* */
|
|
|
|
if (php_sapi_name() !== 'cli') {
|
|
if (!isset($_SERVER['REMOTE_ADDR']) || $_SERVER['REMOTE_ADDR'] !== '127.0.0.1') {
|
|
die('Access denied - tylko z CLI lub localhost');
|
|
}
|
|
}
|
|
|
|
error_reporting(E_ALL);
|
|
ini_set('display_errors', 1);
|
|
ini_set('log_errors', 1);
|
|
|
|
require_once __DIR__ . '/../administration/includes/config.php';
|
|
|
|
if (!isset($pdo) || !($pdo instanceof PDO)) {
|
|
die("DB not initialized\n");
|
|
}
|
|
|
|
function logLine($s) {
|
|
echo '[' . date('Y-m-d H:i:s') . '] ' . $s . "\n";
|
|
}
|
|
|
|
$limit = 50;
|
|
|
|
// Claim jobs (simple approach: select queued and update to processing)
|
|
$stmt = $pdo->prepare("SELECT id, payload_json, attempts FROM rewards_jobs WHERE status = 'queued' ORDER BY created_at ASC LIMIT :lim");
|
|
$stmt->bindValue(':lim', $limit, PDO::PARAM_INT);
|
|
$stmt->execute();
|
|
$jobs = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
foreach ($jobs as $job) {
|
|
$jobId = (int) $job['id'];
|
|
|
|
// optimistic lock
|
|
$upd = $pdo->prepare("UPDATE rewards_jobs SET status = 'processing', attempts = attempts + 1 WHERE id = :id AND status = 'queued'");
|
|
$upd->execute([':id' => $jobId]);
|
|
if ($upd->rowCount() === 0) continue;
|
|
|
|
$payload = json_decode($job['payload_json'], true);
|
|
if (!$payload) {
|
|
$fail = $pdo->prepare("UPDATE rewards_jobs SET status = 'failed', last_error = :err WHERE id = :id");
|
|
$fail->execute([':id' => $jobId, ':err' => 'Invalid payload JSON']);
|
|
continue;
|
|
}
|
|
|
|
// TODO: tutaj wstaw Waszą logikę nagród:
|
|
// - policz nagrodę na podstawie stawki/rate, wyniku, itd.
|
|
// - dopisz transakcje do tabeli `transactions`
|
|
// - zaktualizuj `user_stats.balance`
|
|
// - zwróć strukturę pod animacje w UI (np. coins, xp, items)
|
|
|
|
$winnerId = (int)($payload['winnerUserId'] ?? 0);
|
|
$loserId = (int)($payload['loserUserId'] ?? 0);
|
|
$isDraw = !empty($payload['isDraw']);
|
|
$leftUserId = (int)($payload['players']['left']['userId'] ?? 0);
|
|
$rightUserId = (int)($payload['players']['right']['userId'] ?? 0);
|
|
|
|
if ($isDraw && ($leftUserId <= 0 || $rightUserId <= 0)) {
|
|
$fail = $pdo->prepare("UPDATE rewards_jobs SET status = 'failed', last_error = :err WHERE id = :id");
|
|
$fail->execute([':id' => $jobId, ':err' => 'Draw payload missing players.left/right userId']);
|
|
continue;
|
|
}
|
|
if (!$isDraw && ($winnerId <= 0 || $loserId <= 0)) {
|
|
$fail = $pdo->prepare("UPDATE rewards_jobs SET status = 'failed', last_error = :err WHERE id = :id");
|
|
$fail->execute([':id' => $jobId, ':err' => 'Payload missing winnerUserId/loserUserId']);
|
|
continue;
|
|
}
|
|
|
|
// Minimalny przykład: +1.00 dla zwycięzcy, +0.20 dla przegranego
|
|
// TODO: podmień na Waszą logikę (stawka/rate/ligy/tabele nagród)
|
|
$winnerReward = 1.00;
|
|
$loserReward = 0.20;
|
|
$drawRefund = 1.00;
|
|
|
|
$matchId = (int)($payload['matchId'] ?? 0);
|
|
$score = (string)($payload['score'] ?? '');
|
|
|
|
try {
|
|
$pdo->beginTransaction();
|
|
|
|
// ensure user_stats exists
|
|
$insStatsStmt = $pdo->prepare("INSERT IGNORE INTO user_stats (user_id, balance, matches_played, matches_won, matches_lost, matches_draw, tournaments_played, tournaments_won, leagues_participated, total_income, total_expenses, total_transactions, account_status)
|
|
VALUES (?, 0, 0,0,0,0,0,0,0,0,0,0,'active')");
|
|
if ($isDraw) {
|
|
$insStatsStmt->execute([$leftUserId]);
|
|
$insStatsStmt->execute([$rightUserId]);
|
|
} else {
|
|
$insStatsStmt->execute([$winnerId]);
|
|
$insStatsStmt->execute([$loserId]);
|
|
}
|
|
|
|
// Insert transactions (if table exists)
|
|
// Schema inferred from mds/transactions_add_example.sql: (user_id, type, amount, title, description, category)
|
|
$pdo->exec("CREATE TABLE IF NOT EXISTS transactions (
|
|
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
|
user_id BIGINT UNSIGNED NOT NULL,
|
|
type VARCHAR(20) NOT NULL,
|
|
amount DECIMAL(12,2) NOT NULL,
|
|
title VARCHAR(255) NOT NULL,
|
|
description TEXT NULL,
|
|
category VARCHAR(50) NULL,
|
|
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
INDEX idx_user_created (user_id, created_at)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");
|
|
|
|
$tx = $pdo->prepare("INSERT INTO transactions (user_id, type, amount, title, description, category) VALUES (?, 'income', ?, ?, ?, ?)");
|
|
|
|
if ($isDraw) {
|
|
$updDraw = $pdo->prepare("UPDATE user_stats
|
|
SET balance = balance + ?,
|
|
matches_played = matches_played + 1,
|
|
matches_draw = matches_draw + 1,
|
|
total_income = total_income + ?,
|
|
total_transactions = total_transactions + 1
|
|
WHERE user_id = ?");
|
|
$updDraw->execute([$drawRefund, $drawRefund, $leftUserId]);
|
|
$updDraw->execute([$drawRefund, $drawRefund, $rightUserId]);
|
|
|
|
$titleD = 'Ping-Pong 1v1 - remis (zwrot stawki)';
|
|
$descD = 'Mecz #' . $matchId . ' wynik ' . $score;
|
|
$tx->execute([$leftUserId, $drawRefund, $titleD, $descD, 'match']);
|
|
$tx->execute([$rightUserId, $drawRefund, $titleD, $descD, 'match']);
|
|
|
|
$result = [
|
|
'draw' => [
|
|
'left' => ['userId' => $leftUserId, 'reward' => (float)$drawRefund, 'currency' => 'balance'],
|
|
'right' => ['userId' => $rightUserId, 'reward' => (float)$drawRefund, 'currency' => 'balance'],
|
|
],
|
|
'animation' => ['type' => 'coins', 'durationMs' => 2500],
|
|
'match' => ['matchId' => $matchId, 'score' => $score]
|
|
];
|
|
} else {
|
|
// Update stats + balance for winner/loser only when match is decisive.
|
|
$pdo->prepare("UPDATE user_stats
|
|
SET balance = balance + ?,
|
|
matches_played = matches_played + 1,
|
|
matches_won = matches_won + 1,
|
|
total_income = total_income + ?,
|
|
total_transactions = total_transactions + 1
|
|
WHERE user_id = ?")
|
|
->execute([$winnerReward, $winnerReward, $winnerId]);
|
|
|
|
$pdo->prepare("UPDATE user_stats
|
|
SET balance = balance + ?,
|
|
matches_played = matches_played + 1,
|
|
matches_lost = matches_lost + 1,
|
|
total_income = total_income + ?,
|
|
total_transactions = total_transactions + 1
|
|
WHERE user_id = ?")
|
|
->execute([$loserReward, $loserReward, $loserId]);
|
|
|
|
$titleW = 'Ping-Pong 1v1 - wygrana';
|
|
$descW = 'Mecz #' . $matchId . ' wynik ' . $score;
|
|
$tx->execute([$winnerId, $winnerReward, $titleW, $descW, 'match']);
|
|
|
|
$titleL = 'Ping-Pong 1v1 - udział';
|
|
$descL = 'Mecz #' . $matchId . ' wynik ' . $score;
|
|
$tx->execute([$loserId, $loserReward, $titleL, $descL, 'match']);
|
|
|
|
$result = [
|
|
'winner' => ['userId' => $winnerId, 'reward' => (float)$winnerReward, 'currency' => 'balance'],
|
|
'loser' => ['userId' => $loserId, 'reward' => (float)$loserReward, 'currency' => 'balance'],
|
|
'animation' => ['type' => 'coins', 'durationMs' => 2500],
|
|
'match' => ['matchId' => $matchId, 'score' => $score]
|
|
];
|
|
}
|
|
|
|
$ok = $pdo->prepare("UPDATE rewards_jobs SET status = 'done', result_json = :res, last_error = NULL WHERE id = :id");
|
|
$ok->execute([':id' => $jobId, ':res' => json_encode($result, JSON_UNESCAPED_UNICODE)]);
|
|
|
|
$pdo->commit();
|
|
logLine("Job #$jobId done");
|
|
} catch (Throwable $e) {
|
|
if ($pdo->inTransaction()) $pdo->rollBack();
|
|
$fail = $pdo->prepare("UPDATE rewards_jobs SET status = 'failed', last_error = :err WHERE id = :id");
|
|
$fail->execute([':id' => $jobId, ':err' => $e->getMessage()]);
|
|
logLine("Job #$jobId failed: " . $e->getMessage());
|
|
}
|
|
}
|