Skip to content

Commit 9dbab4e

Browse files
committed
refactor and check casts
1 parent d8be4e6 commit 9dbab4e

File tree

1 file changed

+61
-45
lines changed

1 file changed

+61
-45
lines changed

app/lib/service/download_counts/backend.dart

Lines changed: 61 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class DownloadCountsBackend {
2929
final DatastoreDB _db;
3030

3131
late CachedValue<Map<String, int>> _thirtyDaysTotals;
32-
var _lastData = (data: <String, int>{}, etag: '');
32+
var _lastDownloadsData = (data: <String, int>{}, etag: '');
3333

3434
late CachedValue<Map<String, int>> _trendScores;
3535
var _lastTrendData = (data: <String, int>{}, etag: '');
@@ -48,70 +48,86 @@ class DownloadCountsBackend {
4848
}
4949

5050
Future<Map<String, int>> _updateThirtyDaysTotals() async {
51+
return _fetchAndUpdateCachedData(
52+
fileName: downloadCounts30DaysTotalsFileName,
53+
currentCachedData: _lastDownloadsData,
54+
updateCache: (data) => _lastDownloadsData = data,
55+
errorContext: 'trend scores');
56+
}
57+
58+
Future<Map<String, int>> _updateTrendScores() async {
59+
return _fetchAndUpdateCachedData(
60+
fileName: trendScoreFileName,
61+
currentCachedData: _lastTrendData,
62+
updateCache: (data) => _lastTrendData = data,
63+
errorContext: 'trend scores');
64+
}
65+
66+
Future<Map<String, int>> _fetchAndUpdateCachedData({
67+
required String fileName,
68+
required ({Map<String, int> data, String etag}) currentCachedData,
69+
required void Function(({Map<String, int> data, String etag}) newData)
70+
updateCache,
71+
required String errorContext,
72+
}) async {
5173
try {
5274
final info = await storageService
5375
.bucket(activeConfiguration.reportsBucketName!)
54-
.infoWithRetry(downloadCounts30DaysTotalsFileName);
76+
.infoWithRetry(fileName);
5577

56-
if (_lastData.etag == info.etag) {
57-
return _lastData.data;
78+
if (currentCachedData.etag == info.etag) {
79+
return currentCachedData.data;
5880
}
59-
final data = (await storageService
60-
.bucket(activeConfiguration.reportsBucketName!)
61-
.readWithRetry(
62-
downloadCounts30DaysTotalsFileName,
63-
(input) async => await input
64-
.transform(utf8.decoder)
65-
.transform(json.decoder)
66-
.single as Map<String, dynamic>,
67-
))
68-
.cast<String, int>();
69-
_lastData = (data: data, etag: info.etag);
81+
82+
final rawData = await storageService
83+
.bucket(activeConfiguration.reportsBucketName!)
84+
.readWithRetry(
85+
fileName,
86+
(input) async => await input
87+
.transform(utf8.decoder)
88+
.transform(json.decoder)
89+
.single,
90+
);
91+
92+
final data = _parseJsonToMapStringInt(rawData, fileName);
93+
94+
final newData = (data: data, etag: info.etag);
95+
updateCache(newData);
7096
return data;
7197
} on FormatException catch (e, st) {
72-
logger.severe('Error loading 30-days total download counts:', e, st);
98+
logger.severe('Error parsing $errorContext: $e', e, st);
7399
rethrow;
74100
} on DetailedApiRequestError catch (e, st) {
75101
if (e.status != 404) {
76102
logger.severe(
77-
'Failed to load $downloadCounts30DaysTotalsFileName, error : ',
78-
e,
79-
st);
103+
'Failed to load $fileName ($errorContext), error : $e', e, st);
80104
}
81105
rethrow;
106+
} on TypeError catch (e, st) {
107+
logger.severe('Type error during processing $errorContext: $e', e, st);
108+
rethrow;
82109
}
83110
}
84111

85-
Future<Map<String, int>> _updateTrendScores() async {
86-
try {
87-
final info = await storageService
88-
.bucket(activeConfiguration.reportsBucketName!)
89-
.infoWithRetry(trendScoreFileName);
112+
Map<String, int> _parseJsonToMapStringInt(dynamic rawJson, String fileName) {
113+
if (rawJson is! Map) {
114+
throw FormatException(
115+
'Expected JSON for $fileName to be a Map, but got ${rawJson.runtimeType}');
116+
}
90117

91-
if (_lastTrendData.etag == info.etag) {
92-
return _lastTrendData.data;
118+
final Map<String, int> result = {};
119+
for (final entry in rawJson.entries) {
120+
if (entry.key is! String) {
121+
throw FormatException(
122+
'Expected map keys for $fileName to be String, but found ${entry.key.runtimeType}');
93123
}
94-
final data = (await storageService
95-
.bucket(activeConfiguration.reportsBucketName!)
96-
.readWithRetry(
97-
trendScoreFileName,
98-
(input) async => await input
99-
.transform(utf8.decoder)
100-
.transform(json.decoder)
101-
.single as Map<String, dynamic>,
102-
))
103-
.cast<String, int>();
104-
_lastTrendData = (data: data, etag: info.etag);
105-
return data;
106-
} on FormatException catch (e, st) {
107-
logger.severe('Error package trend scores:', e, st);
108-
rethrow;
109-
} on DetailedApiRequestError catch (e, st) {
110-
if (e.status != 404) {
111-
logger.severe('Failed to load $trendScoreFileName, error : ', e, st);
124+
if (entry.value is! int) {
125+
throw FormatException(
126+
'Expected map value for key "${entry.key}" in $fileName to be int, but got ${entry.value.runtimeType}');
112127
}
113-
rethrow;
128+
result[entry.key as String] = entry.value as int;
114129
}
130+
return result;
115131
}
116132

117133
Future<void> start() async {

0 commit comments

Comments
 (0)