Skip to content

Commit d5ccbdf

Browse files
authored
Merge pull request #313 from synonymdev/fix/price-widget-resilience
fix: price widget decoding + port resilience from Android PR #581
2 parents a1a1e37 + 6c27c30 commit d5ccbdf

File tree

1 file changed

+32
-4
lines changed

1 file changed

+32
-4
lines changed

Bitkit/Services/Widgets/PriceService.swift

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,21 @@ public struct TradingPair {
1212
struct PriceResponse: Codable {
1313
let price: Double
1414
let timestamp: Double
15+
16+
init(from decoder: Decoder) throws {
17+
let container = try decoder.container(keyedBy: CodingKeys.self)
18+
timestamp = try container.decode(Double.self, forKey: .timestamp)
19+
20+
// Handle price as either String or Double
21+
if let priceString = try? container.decode(String.self, forKey: .price) {
22+
guard let priceValue = Double(priceString) else {
23+
throw DecodingError.dataCorruptedError(forKey: .price, in: container, debugDescription: "Price string is not a valid number")
24+
}
25+
price = priceValue
26+
} else {
27+
price = try container.decode(Double.self, forKey: .price)
28+
}
29+
}
1530
}
1631

1732
struct CandleResponse: Codable {
@@ -47,6 +62,7 @@ enum PriceServiceError: Error {
4762
case invalidPair
4863
case networkError
4964
case decodingError
65+
case noPriceDataAvailable
5066
}
5167

5268
// MARK: - Trading Pairs Constants
@@ -140,24 +156,36 @@ class PriceService {
140156
}
141157

142158
/// Fetches fresh data from API (always hits the network)
159+
/// Individual pair failures are logged but don't fail the entire request - only fails if ALL pairs fail
143160
@discardableResult
144161
private func fetchFreshData(pairs: [String], period: GraphPeriod) async throws -> [PriceData] {
145-
let priceDataArray = try await withThrowingTaskGroup(of: PriceData.self) { group in
162+
let priceDataArray = await withTaskGroup(of: PriceData?.self) { group in
146163
var results: [PriceData] = []
147164

148165
for pairName in pairs {
149166
group.addTask {
150-
try await self.fetchPairData(pairName: pairName, period: period)
167+
do {
168+
return try await self.fetchPairData(pairName: pairName, period: period)
169+
} catch {
170+
Logger.warn("Failed to fetch price data for \(pairName): \(error.localizedDescription)")
171+
return nil
172+
}
151173
}
152174
}
153175

154-
for try await priceData in group {
155-
results.append(priceData)
176+
for await priceData in group {
177+
if let data = priceData {
178+
results.append(data)
179+
}
156180
}
157181

158182
return results
159183
}
160184

185+
guard !priceDataArray.isEmpty else {
186+
throw PriceServiceError.noPriceDataAvailable
187+
}
188+
161189
return priceDataArray
162190
}
163191

0 commit comments

Comments
 (0)