Repository navigation
Expand file tree
/
Copy pathUsageEventsMemoryCache.swift
More file actions
97 lines (87 loc) · 3.25 KB
/
Copy pathUsageEventsMemoryCache.swift
File metadata and controls
97 lines (87 loc) · 3.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import Foundation
/// 用量明细的内存 + 磁盘缓存读写,供 ViewModel 调用。
@MainActor
final class UsageEventsMemoryCache {
private var memory: (key: String, store: UsageEventsCache.Store)?
func clearAll() {
memory = nil
UsageEventsCache.clearAll()
}
func clear(startMs: String, endMs: String) {
UsageEventsCache.clear(startMs: startMs, endMs: endMs)
if memory?.key == key(startMs: startMs, endMs: endMs) {
memory = nil
}
}
func load(startMs: String, endMs: String) -> UsageEventsCache.Store? {
let cacheKey = key(startMs: startMs, endMs: endMs)
if let memory, memory.key == cacheKey {
return memory.store
}
guard let store = UsageEventsCache.load(startMs: startMs, endMs: endMs) else { return nil }
// 清理历史 live 轮询堆出来的进行中中间快照
let normalizedEvents = UsageAnalytics.mergeEvents(fresh: store.events, into: [])
let removed = store.events.count - normalizedEvents.count
let normalized = UsageEventsCache.Store(
billingCycleStartMs: store.billingCycleStartMs,
billingCycleEndMs: store.billingCycleEndMs,
totalCount: max(store.totalCount - max(0, removed), normalizedEvents.count),
fetchedAt: store.fetchedAt,
events: normalizedEvents
)
if removed > 0 {
UsageEventsCache.save(
events: normalized.events,
totalCount: normalized.totalCount,
startMs: startMs,
endMs: endMs
)
}
memory = (cacheKey, normalized)
return normalized
}
func save(events: [UsageEvent], totalCount: Int, startMs: String, endMs: String) {
UsageEventsCache.save(events: events, totalCount: totalCount, startMs: startMs, endMs: endMs)
memory = (
key(startMs: startMs, endMs: endMs),
UsageEventsCache.Store(
billingCycleStartMs: startMs,
billingCycleEndMs: endMs,
totalCount: totalCount,
fetchedAt: Date(),
events: events
)
)
}
func page(startMs: String, endMs: String, page: Int, pageSize: Int) -> UsageEventsPage? {
guard UsageEventsCache.canServePage(
startMs: startMs,
endMs: endMs,
page: page,
pageSize: pageSize
) else { return nil }
if let store = load(startMs: startMs, endMs: endMs) {
return UsageEventsPage.slice(
from: store.events,
totalCount: store.totalCount,
page: page,
pageSize: pageSize
)
}
return UsageEventsCache.page(
startMs: startMs,
endMs: endMs,
page: page,
pageSize: pageSize
)
}
func isStale(startMs: String?, endMs: String?, expectedTotal: Int) -> Bool {
guard let startMs, let endMs, let store = load(startMs: startMs, endMs: endMs) else {
return true
}
return store.events.count < expectedTotal
}
private func key(startMs: String, endMs: String) -> String {
"\(startMs)|\(endMs)"
}
}