NAC_Blockchain/nac-quantum-browser/app/service/ExplorerApi.php

190 lines
5.7 KiB
PHP
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
declare(strict_types=1);
namespace app\service;
/**
* NAC 量子浏览器 API 服务层
* 所有对后端 9551 端口的调用均在此类完成
* 前端模板不直接调用任何外部接口
*/
class ExplorerApi
{
// 后端 API 地址(服务端调用,不暴露给前端)
private static string $apiBase = 'http://127.0.0.1:9551';
private static int $timeout = 5;
/**
* 通用 GET 请求
*/
private static function get(string $path, array $params = []): ?array
{
$url = self::$apiBase . $path;
if (!empty($params)) {
$url .= '?' . http_build_query($params);
}
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => self::$timeout,
CURLOPT_CONNECTTIMEOUT => 3,
CURLOPT_HTTPHEADER => ['Accept: application/json'],
CURLOPT_FOLLOWLOCATION => false,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($body === false || $status < 200 || $status >= 300) {
return null;
}
$json = json_decode($body, true);
return is_array($json) ? $json : null;
}
/**
* 获取网络统计数据
* 从 /health + /api/v1/blocks/latest 组合(/api/v1/network/stats 不存在)
*/
public static function getStats(): array
{
$health = self::get('/health');
$latest = self::get('/api/v1/blocks/latest');
$h = $health['data'] ?? [];
$b = $latest['data'] ?? [];
return [
'currentBlock' => $b['number'] ?? ($h['block']['height'] ?? 0),
'cbppConsensus' => $h['cbpp_consensus'] ?? ($b['cbppConsensus'] ?? 'unknown'),
'csnpNetwork' => $h['csnp_network'] ?? 'unknown',
'constitutionLayer' => $h['constitution_layer'] ?? ($b['constitutionLayer'] ?? false),
'fluidBlockMode' => $h['fluid_block_mode'] ?? ($b['isFluid'] ?? false),
'nvmVersion' => $h['nvm_version'] ?? 'N/A',
'chainId' => 20260131,
'network' => 'mainnet',
'nodeCount' => 1,
'totalTransactions' => 0,
'totalAddresses' => 0,
'totalAssets' => 0,
'tps' => 0,
'avgBlockTime' => 3.0,
'latestValidator' => $b['validator'] ?? 'N/A',
'latestHash' => $b['hash'] ?? '',
];
}
/**
* 获取区块列表
* API 返回格式: {data: {blocks: [], total: N}}
* 注意blocks 中的 txCount 字段来自 transactionCount
*/
public static function getBlocks(int $limit = 20, int $page = 1): array
{
$res = self::get('/api/v1/blocks', ['limit' => $limit, 'page' => $page]);
if ($res && isset($res['data']['blocks'])) {
// 统一字段名transactionCount → txCount
$blocks = array_map(function ($b) {
$b['txCount'] = $b['transactionCount'] ?? $b['txCount'] ?? 0;
return $b;
}, $res['data']['blocks']);
return [
'blocks' => $blocks,
'total' => $res['data']['total'] ?? count($blocks),
'page' => $page,
'limit' => $limit,
];
}
return ['blocks' => [], 'total' => 0, 'page' => 1, 'limit' => $limit];
}
/**
* 获取单个区块详情
*/
public static function getBlock(int $number): ?array
{
$res = self::get('/api/v1/blocks/' . $number);
return $res['data'] ?? null;
}
/**
* 获取最新区块
*/
public static function getLatestBlock(): ?array
{
$res = self::get('/api/v1/blocks/latest');
return $res['data'] ?? null;
}
/**
* 搜索(区块号/交易哈希/地址)
*/
public static function search(string $query): ?array
{
return self::get('/api/v1/search', ['q' => $query]);
}
/**
* 获取地址信息
*/
public static function getAddress(string $address): ?array
{
$res = self::get('/api/v1/addresses/' . urlencode($address));
return $res['data'] ?? null;
}
/**
* 健康检查
*/
public static function health(): ?array
{
$res = self::get('/health');
return $res['data'] ?? null;
}
// ===== 工具函数 =====
/**
* 格式化时间戳
*/
public static function formatTime(int $ts): string
{
return date('Y-m-d H:i:s', $ts);
}
/**
* 多久前
*/
public static function timeAgo(int $ts): string
{
$diff = time() - $ts;
if ($diff < 60) return $diff . ' 秒前';
if ($diff < 3600) return floor($diff / 60) . ' 分钟前';
if ($diff < 86400) return floor($diff / 3600) . ' 小时前';
return floor($diff / 86400) . ' 天前';
}
/**
* 截断哈希显示
*/
public static function shortHash(string $hash, int $front = 10, int $back = 8): string
{
if (strlen($hash) <= $front + $back + 3) return $hash;
return substr($hash, 0, $front) . '...' . substr($hash, -$back);
}
/**
* 状态徽章样式
*/
public static function statusBadge(string $status): string
{
return match ($status) {
'active', 'connected', 'ok' => 'badge bg-success',
'unknown' => 'badge bg-secondary',
default => 'badge bg-danger',
};
}
}