Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions SurveyController.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 10101;
CURRENT_PROJECT_VERSION = 10102;
DEAD_CODE_STRIPPING = YES;
ENABLE_APP_SANDBOX = NO;
ENABLE_PREVIEWS = YES;
Expand All @@ -331,7 +331,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MARKETING_VERSION = 0.1.1;
MARKETING_VERSION = 0.1.2;
PRODUCT_BUNDLE_IDENTIFIER = "com.surveycontroller.mac";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
Expand All @@ -346,7 +346,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 10101;
CURRENT_PROJECT_VERSION = 10102;
DEAD_CODE_STRIPPING = YES;
ENABLE_APP_SANDBOX = NO;
ENABLE_PREVIEWS = NO;
Expand All @@ -360,7 +360,7 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MARKETING_VERSION = 0.1.1;
MARKETING_VERSION = 0.1.2;
PRODUCT_BUNDLE_IDENTIFIER = "com.surveycontroller.mac";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
Expand All @@ -373,9 +373,9 @@
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 10101;
CURRENT_PROJECT_VERSION = 10102;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 0.1.1;
MARKETING_VERSION = 0.1.2;
PRODUCT_BUNDLE_IDENTIFIER = "com.surveycontroller.mac.tests";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = NO;
Expand All @@ -389,9 +389,9 @@
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 10101;
CURRENT_PROJECT_VERSION = 10102;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 0.1.1;
MARKETING_VERSION = 0.1.2;
PRODUCT_BUNDLE_IDENTIFIER = "com.surveycontroller.mac.tests";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = NO;
Expand Down
2 changes: 1 addition & 1 deletion SurveyController/App/AppVersion.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Foundation
/// 应用版本与 GitHub 仓库信息。
public enum AppVersion {
/// 当前版本(与 MARKETING_VERSION 同步)。
public static let version = "0.1.1"
public static let version = "0.1.2"
/// 当前对齐的官方桌面端版本。
public static let alignedOfficialVersion = "4.0.6"

Expand Down
11 changes: 7 additions & 4 deletions SurveyController/Core/Proxy/ProxyPool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public struct OfficialProxyProvider: ProxyProvider {
leases.append(ProxyLease(
address: proxy.address,
expireAt: expireAt,
ttlSufficient: expireAt <= 0 || expireAt - Date().timeIntervalSince1970 > 60
ttlSufficient: expireAt <= 0 || expireAt - Date().timeIntervalSince1970 >= ProxyPool.minTtlSeconds
))
}
return leases
Expand Down Expand Up @@ -134,7 +134,9 @@ public struct CustomProxyProvider: ProxyProvider {
/// 对标 session_policy 的代理池(actor 保证并发安全,替代 Python 锁)。
public actor ProxyPool {
public static let cooldownSeconds: TimeInterval = 45
public static let minTtlSeconds: TimeInterval = 60
/// 纯 HTTP 链路不设置预留时长门槛;仍由 expireAt 判断代理是否已经过期。
/// 对标 HTTP_PROXY_MIN_REMAINING_TTL_SECONDS(官方 aca7b90,#103)。
public static let minTtlSeconds: TimeInterval = 0

private var available: [ProxyLease] = []
private var inUse: Set<String> = []
Expand Down Expand Up @@ -203,8 +205,9 @@ public actor ProxyPool {
if inUse.contains(lease.address) || blocked.contains(lease.address) { return false }
if let until = cooldowns[lease.address], until > Date() { return false }
if lease.expireAt > 0 {
if Date().timeIntervalSince1970 >= lease.expireAt { return false }
if lease.expireAt - Date().timeIntervalSince1970 < Self.minTtlSeconds { return false }
// 对标 proxy_lease_has_sufficient_ttl:剩余时长 >= 门槛才可用。门槛为 0 时,未过期即保留。
let remaining = lease.expireAt - Date().timeIntervalSince1970
if remaining < Self.minTtlSeconds { return false }
}
return true
}
Expand Down
14 changes: 14 additions & 0 deletions SurveyControllerTests/RunEngineTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,20 @@ final class ProxyPoolTests: XCTestCase {
XCTAssertEqual(lease.address, "5.5.5.5:80")
}

/// 对标 test_merge_prefetched_proxy_leases_keeps_future_proxy_without_ttl_floor:
/// 已提取、尚未过期的代理必须使用,不能因客户端预留时长被丢弃。
func test_future_lease_is_kept_without_ttl_floor() async throws {
XCTAssertEqual(ProxyPool.minTtlSeconds, 0)
let now = Date().timeIntervalSince1970
let provider = ScriptedProxyProvider(batches: [[
ProxyLease(address: "1.1.1.1:8000", expireAt: now + 5),
ProxyLease(address: "2.2.2.2:8000", expireAt: now - 1),
]])
let pool = ProxyPool(provider: provider)
let lease = try await pool.acquire()
XCTAssertEqual(lease.address, "1.1.1.1:8000")
}

func test_empty_provider_raises_unavailable() async {
let pool = ProxyPool(provider: ScriptedProxyProvider(batches: []))
do {
Expand Down
Loading