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
|
{- |
Module : Network.IRC.Bot.Limiter
Description : simple rate limiter
Copyright : (c) 2012 Eric Mertens
License : BSD3
Maintainer : jeremy@seereason.com
Stability : stable
Portability : portable
A simple rate limiter.
-}
module Network.IRC.Bot.Limiter
( Limiter(..)
, newLimiter
, limit
)
where
import Control.Concurrent (ThreadId, forkIO, threadDelay)
import Control.Concurrent.SSem (SSem)
import qualified Control.Concurrent.SSem as SSem
import Control.Monad (forever)
data Limiter = Limiter
{ limitsIn :: SSem
, limitsOut :: SSem
, limitsDelay :: Int
, limitsThreadId :: ThreadId
}
-- | Construct a new rate limit control
newLimiter :: Int -- ^ max burst length
-> Int -- ^ delay (in microseconds)
-> IO Limiter
newLimiter burst delay = do
rdy <- SSem.new burst
sent <- SSem.new 0
let l = Limiter { limitsIn = sent
, limitsOut = rdy
, limitsDelay = delay
, limitsThreadId = error "limiter thread not started yet"
}
tid <- forkIO (limiter l)
return $ l { limitsThreadId = tid }
-- | Execute this before sending
limit :: Limiter -> IO ()
limit l = do
SSem.wait (limitsOut l)
SSem.signal (limitsIn l)
-- | Loop which manages the limit timers
limiter :: Limiter -> IO b
limiter l = forever $ do
SSem.wait (limitsIn l)
threadDelay (limitsDelay l)
SSem.signal (limitsOut l)
|