module NationStates.RateLimit (
RateLimit(),
newRateLimit,
rateLimit,
setDelay,
) where
import Control.Concurrent
import Control.Exception
import System.Clock
data RateLimit = RateLimit {
_rateLock :: !(MVar TimeSpec),
_rateDelay :: !TimeSpec
}
newRateLimit
:: Rational
-> IO RateLimit
newRateLimit delay' = do
lock <- newMVar $! negate delay
return $ RateLimit lock delay
where
delay = fromSeconds delay'
rateLimit :: RateLimit -> IO a -> IO a
rateLimit (RateLimit lock delay) action =
mask $ \restore -> do
prev <- takeMVar lock
now <- getTime Monotonic
threadDelay' (prev + delay - now) `onException` putMVar lock prev
restore action `finally` (putMVar lock =<< getTime Monotonic)
threadDelay' :: TimeSpec -> IO ()
threadDelay' t = threadDelay . fromInteger $ timeSpecAsNanoSecs t `div` 1000
setDelay :: Rational -> RateLimit -> RateLimit
setDelay delay' (RateLimit lock _) = RateLimit lock (fromSeconds delay')
fromSeconds :: Rational -> TimeSpec
fromSeconds n = fromInteger . ceiling $ n * 1000 * 1000 * 1000