@@ -31,12 +31,20 @@ class DownloadCountsBackend {
3131 late CachedValue <Map <String , int >> _thirtyDaysTotals;
3232 var _lastData = (data: < String , int > {}, etag: '' );
3333
34+ late CachedValue <Map <String , int >> _trendScores;
35+ var _lastTrendData = (data: < String , int > {}, etag: '' );
36+
3437 DownloadCountsBackend (this ._db) {
3538 _thirtyDaysTotals = CachedValue (
3639 name: 'thirtyDaysTotalDownloadCounts' ,
3740 maxAge: Duration (days: 14 ),
3841 interval: Duration (minutes: 30 ),
3942 updateFn: _updateThirtyDaysTotals);
43+ _trendScores = CachedValue (
44+ name: 'trendScores' ,
45+ maxAge: Duration (days: 14 ),
46+ interval: Duration (minutes: 30 ),
47+ updateFn: _updateTrendScores);
4048 }
4149
4250 Future <Map <String , int >> _updateThirtyDaysTotals () async {
@@ -74,17 +82,54 @@ class DownloadCountsBackend {
7482 }
7583 }
7684
85+ Future <Map <String , int >> _updateTrendScores () async {
86+ try {
87+ final info = await storageService
88+ .bucket (activeConfiguration.reportsBucketName! )
89+ .infoWithRetry (trendScoreFileName);
90+
91+ if (_lastTrendData.etag == info.etag) {
92+ return _lastTrendData.data;
93+ }
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);
112+ }
113+ rethrow ;
114+ }
115+ }
116+
77117 Future <void > start () async {
78118 await _thirtyDaysTotals.update ();
119+ await _trendScores.update ();
79120 }
80121
81122 Future <void > close () async {
82123 await _thirtyDaysTotals.close ();
124+ await _trendScores.close ();
83125 }
84126
85127 int ? lookup30DaysTotalCounts (String package) =>
86128 _thirtyDaysTotals.isAvailable ? _thirtyDaysTotals.value! [package] : null ;
87129
130+ int ? lookupTrendScore (String package) =>
131+ _trendScores.isAvailable ? _trendScores.value! [package] : null ;
132+
88133 Future <CountData ?> lookupDownloadCountData (String pkg) async {
89134 return (await cache.downloadCounts (pkg).get (() async {
90135 final key = _db.emptyKey.append (DownloadCounts , id: pkg);
0 commit comments