wpbridge/includes/Performance/RequestDeduplicator.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

118 lines
2.7 KiB
PHP

<?php
/**
* 请求去重器
*
* @package WPBridge
*/
namespace WPBridge\Performance;
use WPBridge\Core\Logger;
// 防止直接访问
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* 请求去重器类
* 防止短时间内重复请求同一源
*/
class RequestDeduplicator {
/**
* 合并窗口时间(秒)
*
* @var int
*/
const MERGE_WINDOW = 5;
/**
* 锁前缀
*
* @var string
*/
const LOCK_PREFIX = 'wpbridge_lock_';
/**
* 尝试获取锁
*
* @param string $source_id 源 ID
* @return bool 是否成功获取锁
*/
public function acquire_lock( string $source_id ): bool {
$lock_key = self::LOCK_PREFIX . $source_id;
// 检查是否已有锁
if ( get_transient( $lock_key ) ) {
Logger::debug( '请求被去重', [ 'source' => $source_id ] );
return false;
}
// 设置锁
set_transient( $lock_key, time(), self::MERGE_WINDOW );
return true;
}
/**
* 释放锁
*
* @param string $source_id 源 ID
*/
public function release_lock( string $source_id ): void {
delete_transient( self::LOCK_PREFIX . $source_id );
}
/**
* 检查是否有锁
*
* @param string $source_id 源 ID
* @return bool
*/
public function has_lock( string $source_id ): bool {
return (bool) get_transient( self::LOCK_PREFIX . $source_id );
}
/**
* 等待锁释放并获取结果
*
* @param string $source_id 源 ID
* @param callable $callback 获取结果的回调
* @param int $max_wait 最大等待时间(秒)
* @return mixed
*/
public function wait_and_get( string $source_id, callable $callback, int $max_wait = 10 ) {
$start = time();
while ( $this->has_lock( $source_id ) ) {
if ( ( time() - $start ) >= $max_wait ) {
Logger::warning( '等待锁超时', [ 'source' => $source_id ] );
break;
}
usleep( 100000 ); // 100ms
}
return $callback();
}
/**
* 带锁执行操作
*
* @param string $source_id 源 ID
* @param callable $callback 操作回调
* @return mixed
*/
public function execute_with_lock( string $source_id, callable $callback ) {
if ( ! $this->acquire_lock( $source_id ) ) {
// 已有请求在进行中,等待结果
return $this->wait_and_get( $source_id, $callback );
}
try {
$result = $callback();
return $result;
} finally {
$this->release_lock( $source_id );
}
}
}