krz/domain-dig
an ios app for DNS & SSL analysis
clone: git clone https://gitbay.org/krz/domain-dig.git
v4.8.2: DomainDig/UsageCreditService.swift · raw
1import Foundation
2
3actor UsageCreditService {
4 static let shared = UsageCreditService()
5
6 private struct CreditLedger: Codable {
7 let appVersion: String
8 var remainingByFeature: [UsageCreditFeature: Int]
9 }
10
11 private let storageKey = "usageCredits.ledger"
12 private var ledger: CreditLedger
13
14 init(defaults: UserDefaults = .standard) {
15 if let data = defaults.data(forKey: storageKey),
16 let decoded = try? JSONDecoder().decode(CreditLedger.self, from: data),
17 decoded.appVersion == AppVersion.current {
18 ledger = decoded
19 } else {
20 ledger = Self.makeLedger()
21 if let data = try? JSONEncoder().encode(ledger) {
22 defaults.set(data, forKey: storageKey)
23 }
24 }
25 }
26
27 func status(for feature: UsageCreditFeature) -> UsageCreditStatus {
28 let total = feature.defaultAllowance
29 let remaining = ledger.remainingByFeature[feature] ?? total
30 return UsageCreditStatus(
31 feature: feature,
32 remaining: remaining,
33 total: total,
34 resetContext: "Resets with app version \(ledger.appVersion)"
35 )
36 }
37
38 func allStatuses() -> [UsageCreditStatus] {
39 UsageCreditFeature.allCases.map { status(for: $0) }
40 }
41
42 func canUse(_ feature: UsageCreditFeature) -> Bool {
43 status(for: feature).remaining > 0
44 }
45
46 @discardableResult
47 func consume(_ feature: UsageCreditFeature) -> UsageCreditStatus {
48 let current = ledger.remainingByFeature[feature] ?? feature.defaultAllowance
49 ledger.remainingByFeature[feature] = max(0, current - 1)
50 persist()
51 return status(for: feature)
52 }
53
54 func resetForCurrentVersion() {
55 ledger = Self.makeLedger()
56 persist()
57 }
58
59 private static func makeLedger() -> CreditLedger {
60 CreditLedger(
61 appVersion: AppVersion.current,
62 remainingByFeature: Dictionary(
63 uniqueKeysWithValues: UsageCreditFeature.allCases.map { ($0, $0.defaultAllowance) }
64 )
65 )
66 }
67
68 private func persist(defaults: UserDefaults = .standard) {
69 if let data = try? JSONEncoder().encode(ledger) {
70 defaults.set(data, forKey: storageKey)
71 }
72 }
73}