This commit is contained in:
Marcos Rodriguez Velez 2024-12-12 23:38:41 -04:00
parent ed8b8e32ae
commit 2ee82f8dc9
4 changed files with 80 additions and 54 deletions

View File

@ -85,5 +85,16 @@ extension MarketAPI {
return marketDataEntry return marketDataEntry
} }
static func fetchMarketData(currency: String, completion: @escaping (Result<MarketData, Error>) -> ()) {
Task {
do {
let marketData = try await fetchMarketData(currency: currency)
completion(.success(marketData))
} catch {
completion(.failure(error))
}
}
}
} }

View File

@ -30,42 +30,46 @@ struct MarketWidgetProvider: TimelineProvider {
let currentDate = Date() let currentDate = Date()
var entries: [MarketWidgetEntry] = [] var entries: [MarketWidgetEntry] = []
var marketDataEntry = MarketWidgetEntry(date: currentDate, marketData: MarketData(nextBlock: "...", sats: "...", price: "...", rate: 0)) let marketDataEntry = MarketWidgetEntry(date: currentDate, marketData: MarketData(nextBlock: "...", sats: "...", price: "...", rate: 0))
entries.append(marketDataEntry) // Initial entry with no data entries.append(marketDataEntry) // Initial placeholder entry
Task { let userPreferredCurrency = Currency.getUserPreferredCurrency()
let userPreferredCurrency = Currency.getUserPreferredCurrency() fetchMarketDataWithRetry(currency: userPreferredCurrency, retries: 3) { marketData in
let entry = await fetchMarketDataWithRetry(currency: userPreferredCurrency, retries: 3) let entry = MarketWidgetEntry(date: Date(), marketData: marketData)
entries.append(entry) entries.append(entry)
let timeline = Timeline(entries: entries, policy: .atEnd) let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline) completion(timeline)
} }
} }
private func fetchMarketDataWithRetry(currency: String, retries: Int) async -> MarketWidgetEntry { private func fetchMarketDataWithRetry(currency: String, retries: Int, completion: @escaping (MarketData) -> ()) {
var marketData = MarketData(nextBlock: "...", sats: "...", price: "...", rate: 0) var attempt = 0
for attempt in 0..<retries { func attemptFetch() {
do { attempt += 1
print("Attempt \(attempt + 1) to fetch market data.") print("Attempt \(attempt) to fetch market data.")
let fetchedData = try await fetchMarketData(currency: currency)
marketData = fetchedData MarketAPI.fetchMarketData(currency: currency) { result in
print("Successfully fetched market data on attempt \(attempt + 1).") switch result {
break case .success(let marketData):
} catch { print("Successfully fetched market data on attempt \(attempt).")
print("Fetch market data failed (attempt \(attempt + 1)): \(error.localizedDescription)") completion(marketData)
try? await Task.sleep(nanoseconds: UInt64(2 * 1_000_000_000)) // Wait 2 seconds before retrying case .failure(let error):
print("Fetch market data failed (attempt \(attempt)): \(error.localizedDescription)")
if attempt < retries {
DispatchQueue.global().asyncAfter(deadline: .now() + 2) {
attemptFetch()
}
} else {
print("Failed to fetch market data after \(retries) attempts.")
let fallbackData = MarketData(nextBlock: "...", sats: "...", price: "...", rate: 0)
completion(fallbackData)
}
}
} }
} }
let marketDataEntry = MarketWidgetEntry(date: Date(), marketData: marketData) attemptFetch()
return marketDataEntry
}
private func fetchMarketData(currency: String) async throws -> MarketData {
let marketData = try await MarketAPI.fetchMarketData(currency: currency)
return marketData
} }
} }

View File

@ -30,7 +30,7 @@ struct MarketView: View {
HStack(alignment: .center, spacing: 0, content: { HStack(alignment: .center, spacing: 0, content: {
Text("Sats/\(Currency.getUserPreferredCurrency())").bold().lineLimit(1).font(Font.system(size:11, weight: .medium, design: .default)).foregroundColor(.textColor) Text("Sats/\(Currency.getUserPreferredCurrency())").bold().lineLimit(1).font(Font.system(size:11, weight: .medium, design: .default)).foregroundColor(.textColor)
Spacer() Spacer()
Text(marketData.sats == "..." ? "..." : marketData.sats).padding(EdgeInsets(top: 2, leading: 4, bottom: 2, trailing: 4)).lineLimit(1).minimumScaleFactor(0.1).foregroundColor(.widgetBackground).font(Font.system(size:11, weight: .semibold, design: .default)).background(Color(red: 0.97, green: 0.21, blue: 0.38)).overlay( Text( marketData.sats).padding(EdgeInsets(top: 2, leading: 4, bottom: 2, trailing: 4)).lineLimit(1).minimumScaleFactor(0.1).foregroundColor(.widgetBackground).font(Font.system(size:11, weight: .semibold, design: .default)).background(Color(red: 0.97, green: 0.21, blue: 0.38)).overlay(
RoundedRectangle(cornerRadius: 4.0) RoundedRectangle(cornerRadius: 4.0)
.stroke(Color.containerRed, lineWidth: 4.0)) .stroke(Color.containerRed, lineWidth: 4.0))
}) })
@ -38,7 +38,7 @@ struct MarketView: View {
HStack(alignment: .center, spacing: 0, content: { HStack(alignment: .center, spacing: 0, content: {
Text("Price").bold().lineLimit(1).font(Font.system(size:11, weight: . medium, design: .default)).foregroundColor(.textColor) Text("Price").bold().lineLimit(1).font(Font.system(size:11, weight: . medium, design: .default)).foregroundColor(.textColor)
Spacer() Spacer()
Text(marketData.price == "..." ? "..." : marketData.price).padding(EdgeInsets(top: 2, leading: 4, bottom: 2, trailing: 4)).lineLimit(1).minimumScaleFactor(0.1).foregroundColor(.widgetBackground).font(Font.system(size:11, weight: .semibold, design: .default)).background(Color(red: 0.29, green: 0.86, blue: 0.73)).overlay( Text( marketData.price).padding(EdgeInsets(top: 2, leading: 4, bottom: 2, trailing: 4)).lineLimit(1).minimumScaleFactor(0.1).foregroundColor(.widgetBackground).font(Font.system(size:11, weight: .semibold, design: .default)).background(Color(red: 0.29, green: 0.86, blue: 0.73)).overlay(
RoundedRectangle(cornerRadius:4.0) RoundedRectangle(cornerRadius:4.0)
.stroke(Color.containerGreen, lineWidth: 4.0)) .stroke(Color.containerGreen, lineWidth: 4.0))
}) })

View File

@ -48,43 +48,54 @@ struct WalletInformationAndMarketWidgetProvider: TimelineProvider {
let timeline = Timeline(entries: entries, policy: .atEnd) let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline) completion(timeline)
} else { } else {
Task { let userPreferredCurrency = Currency.getUserPreferredCurrency()
let userPreferredCurrency = Currency.getUserPreferredCurrency() let allWalletsBalance = WalletData(balance: UserDefaultsGroup.getAllWalletsBalance(), latestTransactionTime: UserDefaultsGroup.getAllWalletsLatestTransactionTime())
let allwalletsBalance = WalletData(balance: UserDefaultsGroup.getAllWalletsBalance(), latestTransactionTime: UserDefaultsGroup.getAllWalletsLatestTransactionTime())
var retryCount = 0 fetchMarketDataWithRetry(currency: userPreferredCurrency, retries: 3) { marketData in
let maxRetries = 3 let entry = WalletInformationAndMarketWidgetEntry(date: Date(), marketData: marketData, allWalletsBalance: allWalletsBalance)
var success = false Task {
await entryStore.setLastSuccessfulEntry(entry)
entries.append(entry)
let timeline = Timeline(entries: entries, policy: .atEnd)
completion(timeline)
}
}
}
}
while retryCount < maxRetries && !success { private func fetchMarketDataWithRetry(currency: String, retries: Int, completion: @escaping (MarketData) -> ()) {
do { var attempt = 0
print("Fetching market data for currency: \(userPreferredCurrency)")
let result = try await MarketAPI.fetchMarketData(currency: userPreferredCurrency) func attemptFetch() {
let entry = WalletInformationAndMarketWidgetEntry(date: Date(), marketData: result, allWalletsBalance: allwalletsBalance) attempt += 1
await entryStore.setLastSuccessfulEntry(entry) print("Attempt \(attempt) to fetch market data.")
entries.append(entry)
success = true MarketAPI.fetchMarketData(currency: currency) { result in
} catch { switch result {
retryCount += 1 case .success(let marketData):
print("Error fetching market data: \(error.localizedDescription). Retry \(retryCount)/\(maxRetries)") print("Successfully fetched market data on attempt \(attempt).")
if retryCount == maxRetries { completion(marketData)
print("Max retries reached. Blacklisting server.") case .failure(let error):
print("Error fetching market data: \(error.localizedDescription). Retry \(attempt)/\(retries)")
if attempt < retries {
DispatchQueue.global().asyncAfter(deadline: .now() + 2) {
attemptFetch()
}
} else {
print("Max retries reached.")
Task {
if let lastEntry = await entryStore.getLastSuccessfulEntry() { if let lastEntry = await entryStore.getLastSuccessfulEntry() {
print("Using last successful entry.") completion(lastEntry.marketData)
entries.append(lastEntry)
} else { } else {
print("Using placeholder entry as fallback.") completion(WalletInformationAndMarketWidgetEntry.placeholder.marketData)
entries.append(WalletInformationAndMarketWidgetEntry.placeholder)
} }
} }
} }
} }
let timeline = Timeline(entries: entries, policy: .atEnd)
print("Submitting timeline with \(entries.count) entries.")
completion(timeline)
} }
} }
attemptFetch()
} }
} }