false, 'error' => $msg]); exit; } if ($_SERVER['REQUEST_METHOD'] !== 'GET') { fail(405, 'GET only'); } $cfg = require __DIR__ . '/config.php'; $symbol = (string)($_GET['symbol'] ?? $cfg['symbols'][0]); if (!in_array($symbol, $cfg['symbols'], true)) { fail(400, 'unknown symbol'); } $what = (string)($_GET['what'] ?? 'all'); try { $pdo = new PDO($cfg['db_dsn'], $cfg['db_user'], $cfg['db_pass'], [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, ]); } catch (PDOException $e) { fail(500, 'db unavailable'); } $out = ['ok' => true, 'server_time' => gmdate('Y-m-d H:i:s')]; try { $st = $pdo->prepare( 'SELECT price, prev_price, tick_at, TIMESTAMPDIFF(SECOND, tick_at, UTC_TIMESTAMP()) AS age_sec FROM live_price WHERE symbol = :s' ); $st->execute([':s' => $symbol]); $row = $st->fetch(PDO::FETCH_ASSOC); $out['price'] = $row === false ? null : [ 'price' => (float)$row['price'], 'prev_price' => $row['prev_price'] === null ? null : (float)$row['prev_price'], 'tick_at' => $row['tick_at'], 'age_sec' => (int)$row['age_sec'], ]; if ($what !== 'price') { $st = $pdo->prepare( 'SELECT r.timeframe, r.payload, r.updated_at, TIMESTAMPDIFF(SECOND, r.updated_at, UTC_TIMESTAMP()) AS age_sec FROM signal_reports r JOIN (SELECT timeframe, MAX(id) AS mid FROM signal_reports WHERE symbol = :s GROUP BY timeframe) x ON x.mid = r.id' ); $st->execute([':s' => $symbol]); $reports = []; foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $r) { $p = json_decode((string)$r['payload'], true); if (is_array($p)) { $p['stored_at'] = $r['updated_at']; $p['age_sec'] = (int)$r['age_sec']; $reports[$r['timeframe']] = $p; } } $out['reports'] = $reports; } } catch (PDOException $e) { error_log('api.php: ' . $e->getMessage()); fail(500, 'db error'); } echo json_encode($out, JSON_UNESCAPED_UNICODE);