File: Limiter.hs

package info (click to toggle)
haskell-ircbot 0.6.6.1-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 144 kB
  • sloc: haskell: 881; makefile: 2
file content (58 lines) | stat: -rw-r--r-- 1,515 bytes parent folder | download | duplicates (4)
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)