module Network.Discord.Rest.Prelude where
import Control.Concurrent (threadDelay)
import Control.Concurrent.STM
import Data.Aeson
import Data.Default
import Data.Hashable
import Data.Monoid ((<>))
import Data.Time.Clock.POSIX
import Network.HTTP.Req (Option, Scheme(..), (=:))
import System.Log.Logger
import qualified Control.Monad.State as St
import Network.Discord.Types
baseURL :: String
baseURL = "https://discordapp.com/api/v6"
class Hashable a => RateLimit a where
getRateLimit :: a -> DiscordM (Maybe Int)
getRateLimit req = do
DiscordState {getRateLimits=rl} <- St.get
now <- St.liftIO (fmap round getPOSIXTime :: IO Int)
St.liftIO . atomically $ do
rateLimits <- readTVar rl
case lookup (hash req) rateLimits of
Nothing -> return Nothing
Just a
| a >= now -> return $ Just a
| otherwise -> modifyTVar' rl (delete $ hash req) >> return Nothing
setRateLimit :: a -> Int -> DiscordM ()
setRateLimit req reset = do
DiscordState {getRateLimits=rl} <- St.get
St.liftIO . atomically . modifyTVar rl $ insert (hash req) reset
waitRateLimit :: a -> DiscordM ()
waitRateLimit endpoint = do
rl <- getRateLimit endpoint
case rl of
Nothing -> return ()
Just a -> do
now <- St.liftIO (fmap round getPOSIXTime :: IO Int)
St.liftIO $ do
infoM "Discord-hs.Rest" "Waiting for rate limit to reset..."
threadDelay $ 1000000 * (a now)
putStrLn "Done"
return ()
class DoFetch a where
doFetch :: a -> DiscordM Fetched
data Fetchable = forall a. (DoFetch a, Hashable a) => Fetch a
instance DoFetch Fetchable where
doFetch (Fetch a) = doFetch a
instance Hashable Fetchable where
hashWithSalt s (Fetch a) = hashWithSalt s a
instance Eq Fetchable where
(Fetch a) == (Fetch b) = hash a == hash b
data Fetched = forall a. (FromJSON a) => SyncFetched a
data Range = Range { after :: Snowflake, before :: Snowflake, limit :: Int}
instance Default Range where
def = Range 0 18446744073709551615 100
toQueryString :: Range -> Option 'Https
toQueryString (Range a b l)
= "after" =: show a
<> "before" =: show b
<> "limit" =: show l