Files
Bitcoin-Monitoring/test1/PriceService.swift
2025-10-31 16:50:27 +08:00

187 lines
5.6 KiB
Swift
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.
//
// PriceService.swift
// Bitcoin Monitoring
//
// Created by Mark on 2025/10/28.
//
import Foundation
// API
class PriceService: ObservableObject {
private let baseURL = "https://api.binance.com/api/v3/ticker/price"
private var session: URLSession // var 便
private let appSettings: AppSettings
@MainActor
init(appSettings: AppSettings) {
self.appSettings = appSettings
self.session = Self.createURLSession(
proxyEnabled: appSettings.proxyEnabled,
proxyHost: appSettings.proxyHost,
proxyPort: appSettings.proxyPort
)
}
//
func fetchPrice(for symbol: CryptoSymbol) async throws -> Double {
let urlString = "\(baseURL)?symbol=\(symbol.apiSymbol)"
guard let url = URL(string: urlString) else {
throw PriceError.invalidURL
}
//
let (data, response) = try await session.data(from: url)
//
guard let httpResponse = response as? HTTPURLResponse else {
throw PriceError.invalidResponse
}
guard httpResponse.statusCode == 200 else {
throw PriceError.serverError(httpResponse.statusCode)
}
// JSON
let decoder = JSONDecoder()
let priceResponse = try decoder.decode(TickerPriceResponse.self, from: data)
// Double
guard let price = Double(priceResponse.price) else {
throw PriceError.invalidPrice
}
return price
}
// MARK: -
/**
* URLSession
* - Parameters:
* - proxyEnabled:
* - proxyHost:
* - proxyPort:
* - Returns: URLSession
*/
private static func createURLSession(proxyEnabled: Bool, proxyHost: String, proxyPort: Int) -> URLSession {
let configuration = URLSessionConfiguration.default
//
if proxyEnabled {
let proxyDict = createProxyDictionary(
host: proxyHost,
port: proxyPort
)
configuration.connectionProxyDictionary = proxyDict
#if DEBUG
print("🌐 [PriceService] 已配置代理: \(proxyHost):\(proxyPort)")
#endif
}
//
configuration.timeoutIntervalForRequest = 15.0
configuration.timeoutIntervalForResource = 30.0
return URLSession(configuration: configuration)
}
/**
*
* - Parameters:
* - host:
* - port:
* - Returns:
*/
private static func createProxyDictionary(host: String, port: Int) -> [AnyHashable: Any] {
return [
kCFNetworkProxiesHTTPEnable: 1,
kCFNetworkProxiesHTTPProxy: host,
kCFNetworkProxiesHTTPPort: port,
kCFNetworkProxiesHTTPSEnable: 1,
kCFNetworkProxiesHTTPSProxy: host,
kCFNetworkProxiesHTTPSPort: port
]
}
/**
*
*/
@MainActor
func updateNetworkConfiguration() {
// MainActor
let proxyEnabled = appSettings.proxyEnabled
let proxyHost = appSettings.proxyHost
let proxyPort = appSettings.proxyPort
// URLSession
let newSession = Self.createURLSession(
proxyEnabled: proxyEnabled,
proxyHost: proxyHost,
proxyPort: proxyPort
)
self.session = newSession
#if DEBUG
print("🔄 [PriceService] 网络配置已更新 - 代理: \(proxyEnabled ? "\(proxyHost):\(proxyPort)" : "未启用")")
#endif
}
/**
*
* - Returns:
*/
func testProxyConnection() async -> Bool {
let proxyEnabled = await MainActor.run {
return appSettings.proxyEnabled
}
guard proxyEnabled else {
#if DEBUG
print("🌐 [PriceService] 代理未启用,无需测试连接")
#endif
return true
}
do {
//
_ = try await fetchPrice(for: .btc)
#if DEBUG
print("✅ [PriceService] 代理连接测试成功")
#endif
return true
} catch {
#if DEBUG
print("❌ [PriceService] 代理连接测试失败: \(error.localizedDescription)")
#endif
return false
}
}
}
//
enum PriceError: Error, LocalizedError {
case invalidURL
case invalidResponse
case serverError(Int)
case invalidPrice
case networkError(Error)
var errorDescription: String? {
switch self {
case .invalidURL:
return "无效的URL"
case .invalidResponse:
return "无效的响应"
case .serverError(let code):
return "服务器错误,状态码:\(code)"
case .invalidPrice:
return "无效的价格数据"
case .networkError(let error):
return "网络错误:\(error.localizedDescription)"
}
}
}