1
1
{-# LANGUAGE RankNTypes, NamedFieldPuns, RecordWildCards #-}
2
+ {-# LANGUAGE DerivingStrategies #-}
3
+ {-# LANGUAGE DeriveGeneric #-}
4
+ {-# LANGUAGE DeriveAnyClass #-}
5
+ {-# OPTIONS_GHC -Wno-orphans #-}
2
6
-- | Download counts
3
7
--
4
8
-- We maintain
@@ -33,12 +37,17 @@ import Distribution.Server.Features.Core
33
37
import Distribution.Server.Features.Users
34
38
35
39
import Distribution.Package
36
- import Distribution.Server.Util.CountingMap (cmFromCSV )
40
+ import Distribution.Server.Util.CountingMap (cmFromCSV , cmToList )
37
41
38
42
import Data.Time.Calendar (Day , addDays )
39
43
import Data.Time.Clock (getCurrentTime , utctDay )
40
44
import Control.Concurrent.Chan
41
45
import Control.Concurrent (forkIO )
46
+ import GHC.Generics (Generic )
47
+ import Data.Aeson (ToJSON )
48
+ import qualified Data.Aeson as Aeson
49
+ import Data.List (sortBy )
50
+ import Data.Function (on )
42
51
43
52
data DownloadFeature = DownloadFeature {
44
53
downloadFeatureInterface :: HackageFeature
@@ -54,6 +63,14 @@ data DownloadResource = DownloadResource {
54
63
topDownloads :: Resource
55
64
}
56
65
66
+ data PackageDownloads = PackageDownloads {
67
+ packageName :: ! String
68
+ , downloads :: ! Int
69
+ }
70
+ deriving stock (Eq , Ord , Generic )
71
+ deriving anyclass (ToJSON )
72
+
73
+
57
74
initDownloadFeature :: ServerEnv
58
75
-> IO (CoreFeature -> UserFeature -> IO DownloadFeature )
59
76
initDownloadFeature serverEnv@ ServerEnv {serverStateDir} = do
@@ -176,10 +193,22 @@ downloadFeature CoreFeature{}
176
193
177
194
updateState inMemState $ RegisterDownload pkg
178
195
196
+
179
197
downloadResource = DownloadResource {
180
- topDownloads = resourceAt " /packages/top.:format"
198
+ topDownloads = (resourceAt " /packages/top.:format" )
199
+ { resourceDesc = [ (GET , " Get top downloaded packages for the last 30 days" )]
200
+ , resourceGet = [ (" json" , serveDownloadTopJSON) ]
201
+ }
181
202
}
182
203
204
+ serveDownloadTopJSON :: DynamicPath -> ServerPartE Response
205
+ serveDownloadTopJSON _ = do
206
+ pkgList <- sortedPackages <$> recentPackageDownloads
207
+ pure $ toResponse $ Aeson. toJSON pkgList
208
+
209
+ sortedPackages :: RecentDownloads -> [PackageDownloads ]
210
+ sortedPackages = fmap (\ (p, c) -> PackageDownloads (unPackageName p) c) . sortBy (flip compare `on` snd ) . cmToList
211
+
183
212
downloadCSV = (resourceAt " /packages/downloads.:format" ) {
184
213
resourceDesc = [ (GET , " Get download counts" )
185
214
, (PUT , " Upload download counts (for import)" )
0 commit comments