wpbridge/includes/Cache/HealthChecker.php
feibisi 546304fb4a feat: WPBridge v0.2.0 - 完整插件实现
v0.1.0 核心功能:
- 更新源管理 (SourceManager, SourceModel, SourceType)
- 插件/主题更新器 (PluginUpdater, ThemeUpdater)
- 缓存系统 (CacheManager, HealthChecker, FallbackStrategy)
- 安全模块 (Validator, Encryption)
- 管理界面 (AdminPage, templates, CSS, JS)
- 预设源支持 (ArkPress, AspireCloud)

v0.2.0 新增功能:
- 性能优化 (ParallelRequestManager, RequestDeduplicator)
- 条件请求 (ConditionalRequest - ETag/Last-Modified)
- 后台更新 (BackgroundUpdater - WP-Cron)
- Git 平台支持 (GitHub, GitLab, Gitee handlers)
- WP-CLI 命令 (wp bridge source/check/cache/diagnose/config)

安全修复:
- SQL 注入防护 ($wpdb->prepare)
- GET 参数清理 (sanitize_text_field)
- auth_token 加密存储 (AES-256-CBC)
- 缓存键哈希 (md5 + site_url)
- 卸载清理 (uninstall.php)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 19:52:27 +08:00

187 lines
4.5 KiB
PHP
Raw Permalink 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
/**
* 健康检查器
*
* @package WPBridge
*/
namespace WPBridge\Cache;
use WPBridge\UpdateSource\SourceModel;
use WPBridge\UpdateSource\Handlers\HealthStatus;
use WPBridge\Core\Logger;
// 防止直接访问
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* 健康检查器类
*/
class HealthChecker {
/**
* 缓存管理器
*
* @var CacheManager
*/
private CacheManager $cache;
/**
* 健康状态缓存 TTL1 小时)
*
* @var int
*/
const HEALTH_CACHE_TTL = 3600;
/**
* 失败源冷却时间30 分钟)
*
* @var int
*/
const FAILED_COOLDOWN = 1800;
/**
* 构造函数
*/
public function __construct() {
$this->cache = new CacheManager();
}
/**
* 检查源健康状态
*
* @param SourceModel $source 源模型
* @param bool $force 是否强制检查
* @return HealthStatus
*/
public function check( SourceModel $source, bool $force = false ): HealthStatus {
$cache_key = 'health_' . $source->id;
// 检查缓存
if ( ! $force ) {
$cached = $this->cache->get( $cache_key );
if ( false !== $cached && $cached instanceof HealthStatus ) {
return $cached;
}
}
// 检查是否在冷却期
if ( ! $force && $this->is_in_cooldown( $source->id ) ) {
return HealthStatus::failed( __( '源在冷却期内', 'wpbridge' ) );
}
// 执行健康检查
$handler = $source->get_handler();
if ( null === $handler ) {
$status = HealthStatus::failed( __( '无法获取处理器', 'wpbridge' ) );
} else {
$status = $handler->test_connection();
}
// 缓存结果
$ttl = $status->is_healthy() ? self::HEALTH_CACHE_TTL : self::FAILED_COOLDOWN;
$this->cache->set( $cache_key, $status, $ttl );
// 如果失败,设置冷却
if ( ! $status->is_available() ) {
$this->set_cooldown( $source->id );
}
Logger::debug( '健康检查完成', [
'source' => $source->id,
'status' => $status->status,
'time' => $status->response_time,
] );
return $status;
}
/**
* 批量检查源健康状态
*
* @param SourceModel[] $sources 源列表
* @return array<string, HealthStatus>
*/
public function check_all( array $sources ): array {
$results = [];
foreach ( $sources as $source ) {
$results[ $source->id ] = $this->check( $source );
}
return $results;
}
/**
* 获取源健康状态(仅从缓存)
*
* @param string $source_id 源 ID
* @return HealthStatus|null
*/
public function get_status( string $source_id ): ?HealthStatus {
$cached = $this->cache->get( 'health_' . $source_id );
if ( false !== $cached && $cached instanceof HealthStatus ) {
return $cached;
}
return null;
}
/**
* 检查源是否在冷却期
*
* @param string $source_id 源 ID
* @return bool
*/
public function is_in_cooldown( string $source_id ): bool {
$cooldown = $this->cache->get( 'cooldown_' . $source_id );
return false !== $cooldown;
}
/**
* 设置源冷却
*
* @param string $source_id 源 ID
*/
private function set_cooldown( string $source_id ): void {
$this->cache->set( 'cooldown_' . $source_id, time(), self::FAILED_COOLDOWN );
Logger::info( '源进入冷却期', [
'source' => $source_id,
'duration' => self::FAILED_COOLDOWN,
] );
}
/**
* 清除源冷却
*
* @param string $source_id 源 ID
*/
public function clear_cooldown( string $source_id ): void {
$this->cache->delete( 'cooldown_' . $source_id );
}
/**
* 清除所有健康状态缓存
*/
public function clear_all(): void {
global $wpdb;
$wpdb->query(
$wpdb->prepare(
"DELETE FROM {$wpdb->options} WHERE option_name LIKE %s",
$wpdb->esc_like( '_transient_wpbridge_health_' ) . '%'
)
);
$wpdb->query(
$wpdb->prepare(
"DELETE FROM {$wpdb->options} WHERE option_name LIKE %s",
$wpdb->esc_like( '_transient_wpbridge_cooldown_' ) . '%'
)
);
}
}