-
-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathStats.hs
88 lines (78 loc) · 2.79 KB
/
Stats.hs
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
module Stats (statsMiddleware) where
import Prelude
import Control.Concurrent
import Control.Concurrent.STM
import qualified Network.Wai as Wai
import qualified Data.ByteString.Char8 as BC
import Data.Maybe
import Data.Map (Map)
import qualified Data.Map as Map
import Control.Monad
import Control.Monad.Trans (liftIO)
import qualified Data.Text as T
import Control.Monad.Trans.Resource (runResourceT)
import Foundation (DBPool, withDBPool, BitloveEnv)
import Model.Stats (addCounter)
import Model.Download (InfoHash (InfoHash))
type Key = (T.Text, BC.ByteString)
type StatsBuffer = TVar (Map Key (TVar Integer))
statsMiddleware :: BitloveEnv -> DBPool -> IO Wai.Middleware
statsMiddleware env pool = do
tBuf <- newTVarIO Map.empty
return $ \app req respond ->
do liftIO $ countRequest env pool tBuf req
app req respond
countRequest :: BitloveEnv -> DBPool -> StatsBuffer -> Wai.Request -> IO ()
countRequest env pool tBuf req
| "/static/" `BC.isPrefixOf` Wai.rawPathInfo req =
-- Ignore static resources
return ()
| Wai.rawPathInfo req == "/by-enclosure.json" =
-- Track referrer for API calls
let referrer = fromMaybe "" $ "Referer" `lookup` Wai.requestHeaders req
in increaseCounter pool tBuf ("by-enclosure.json", referrer) 1
| otherwise =
-- All others: just method & path
let kind = "ui/" `T.append` T.pack (show env)
info = Wai.requestMethod req `BC.append`
" " `BC.append`
Wai.rawPathInfo req
in increaseCounter pool tBuf (kind, info) 1
increaseCounter :: DBPool -> StatsBuffer -> Key -> Integer -> IO ()
increaseCounter pool tBuf key increment = do
isNew <-
atomically $ do
buf <- readTVar tBuf
case key `Map.lookup` buf of
Nothing ->
do tIncrement <- newTVar increment
writeTVar tBuf $ Map.insert key tIncrement buf
return True
Just tIncrement ->
do modifyTVar tIncrement (+ increment)
return False
when isNew $ do
_ <- forkIO $ do
threadDelay second
flushCounter pool tBuf key
return ()
second :: Int
second = 1000000
flushCounter :: DBPool -> StatsBuffer -> Key -> IO ()
flushCounter pool tBuf key = do
increment <-
atomically $ do
buf <- readTVar tBuf
increment <- maybe (return 0) readTVar $
key `Map.lookup` buf
writeTVar tBuf $ Map.delete key buf
return increment
let (kind, info) = key
case increment of
increment'
| increment' > 0 ->
runResourceT $
withDBPool pool $
addCounter kind (InfoHash info) increment'
_ ->
putStrLn $ "Warning: stale counter for " ++ show key