module Reddit.Types.Reddit
  ( Reddit
  , RedditT(..)
  , RedditF(..)
  , runRoute
  , receiveRoute
  , nest
  , failWith
  , withBaseURL
  , withHeaders
  , Modhash(..)
  , LoginDetails(..)
  , POSTWrapped(..)
  , ShouldRateLimit
  , RateLimits(RateLimits, should, info)
  , RateLimitInfo(..)
  , headersToRateLimitInfo
  , ClientParams(..)
  , mkClientParamsHeader
  , mainBaseURL
  , loginBaseURL
  , addAPIType
  ) where

import Reddit.Types.Error

import Control.Applicative
import Control.Monad.IO.Class
import Control.Monad.Trans.Free
import Control.Monad.Trans.Class
import Data.Aeson
import Data.ByteString.Lazy (ByteString)
import Data.Monoid
import Data.Text (Text)
import Data.Time.Clock
import Network.API.Builder hiding (runRoute)
import Network.HTTP.Client hiding (path)
import Network.HTTP.Types
import Prelude
import Text.Read (readMaybe)
import qualified Data.ByteString.Char8 as BS
import qualified Data.Text.Encoding as Text

type Reddit a = RedditT IO a

data RedditF m a where
  FailWith :: APIError RedditError -> RedditF m a
  Nest :: RedditT m b -> (Either (APIError RedditError) b -> a) -> RedditF m a
  NestResuming :: RedditT m b -> (Either (APIError RedditError, Maybe (RedditT m b)) b -> a) -> RedditF m a
  ReceiveRoute :: Receivable b => Route -> (b -> a) -> RedditF m a
  RunRoute :: FromJSON b => Route -> (b -> a) -> RedditF m a
  WithBaseURL :: Text -> RedditT m b -> (b -> a) -> RedditF m a
  WithHeaders :: ([Header] -> [Header]) -> RedditT m b -> (b -> a) -> RedditF m a

instance Functor (RedditF m) where
  fmap :: (a -> b) -> RedditF m a -> RedditF m b
fmap a -> b
_ (FailWith APIError RedditError
x) = APIError RedditError -> RedditF m b
forall (m :: * -> *) a. APIError RedditError -> RedditF m a
FailWith APIError RedditError
x
  fmap a -> b
f (Nest RedditT m b
a Either (APIError RedditError) b -> a
x) = RedditT m b
-> (Either (APIError RedditError) b -> b) -> RedditF m b
forall (m :: * -> *) b a.
RedditT m b
-> (Either (APIError RedditError) b -> a) -> RedditF m a
Nest RedditT m b
a ((a -> b)
-> (Either (APIError RedditError) b -> a)
-> Either (APIError RedditError) b
-> b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> b
f Either (APIError RedditError) b -> a
x)
  fmap a -> b
f (NestResuming RedditT m b
a Either (APIError RedditError, Maybe (RedditT m b)) b -> a
x) = RedditT m b
-> (Either (APIError RedditError, Maybe (RedditT m b)) b -> b)
-> RedditF m b
forall (m :: * -> *) b a.
RedditT m b
-> (Either (APIError RedditError, Maybe (RedditT m b)) b -> a)
-> RedditF m a
NestResuming RedditT m b
a ((a -> b)
-> (Either (APIError RedditError, Maybe (RedditT m b)) b -> a)
-> Either (APIError RedditError, Maybe (RedditT m b)) b
-> b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> b
f Either (APIError RedditError, Maybe (RedditT m b)) b -> a
x)
  fmap a -> b
f (ReceiveRoute Route
r b -> a
x) = Route -> (b -> b) -> RedditF m b
forall b a (m :: * -> *).
Receivable b =>
Route -> (b -> a) -> RedditF m a
ReceiveRoute Route
r ((a -> b) -> (b -> a) -> b -> b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> b
f b -> a
x)
  fmap a -> b
f (RunRoute Route
r b -> a
x) = Route -> (b -> b) -> RedditF m b
forall b a (m :: * -> *).
FromJSON b =>
Route -> (b -> a) -> RedditF m a
RunRoute Route
r ((a -> b) -> (b -> a) -> b -> b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> b
f b -> a
x)
  fmap a -> b
f (WithBaseURL Text
u RedditT m b
a b -> a
x) = Text -> RedditT m b -> (b -> b) -> RedditF m b
forall (m :: * -> *) b a.
Text -> RedditT m b -> (b -> a) -> RedditF m a
WithBaseURL Text
u RedditT m b
a ((a -> b) -> (b -> a) -> b -> b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> b
f b -> a
x)
  fmap a -> b
f (WithHeaders [Header] -> [Header]
hf RedditT m b
a b -> a
x) = ([Header] -> [Header]) -> RedditT m b -> (b -> b) -> RedditF m b
forall (m :: * -> *) b a.
([Header] -> [Header]) -> RedditT m b -> (b -> a) -> RedditF m a
WithHeaders [Header] -> [Header]
hf RedditT m b
a ((a -> b) -> (b -> a) -> b -> b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> b
f b -> a
x)

newtype RedditT m a = RedditT (FreeT (RedditF m) m a)
  deriving (a -> RedditT m b -> RedditT m a
(a -> b) -> RedditT m a -> RedditT m b
(forall a b. (a -> b) -> RedditT m a -> RedditT m b)
-> (forall a b. a -> RedditT m b -> RedditT m a)
-> Functor (RedditT m)
forall a b. a -> RedditT m b -> RedditT m a
forall a b. (a -> b) -> RedditT m a -> RedditT m b
forall (m :: * -> *) a b.
Monad m =>
a -> RedditT m b -> RedditT m a
forall (m :: * -> *) a b.
Monad m =>
(a -> b) -> RedditT m a -> RedditT m b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> RedditT m b -> RedditT m a
$c<$ :: forall (m :: * -> *) a b.
Monad m =>
a -> RedditT m b -> RedditT m a
fmap :: (a -> b) -> RedditT m a -> RedditT m b
$cfmap :: forall (m :: * -> *) a b.
Monad m =>
(a -> b) -> RedditT m a -> RedditT m b
Functor, Functor (RedditT m)
a -> RedditT m a
Functor (RedditT m)
-> (forall a. a -> RedditT m a)
-> (forall a b. RedditT m (a -> b) -> RedditT m a -> RedditT m b)
-> (forall a b c.
    (a -> b -> c) -> RedditT m a -> RedditT m b -> RedditT m c)
-> (forall a b. RedditT m a -> RedditT m b -> RedditT m b)
-> (forall a b. RedditT m a -> RedditT m b -> RedditT m a)
-> Applicative (RedditT m)
RedditT m a -> RedditT m b -> RedditT m b
RedditT m a -> RedditT m b -> RedditT m a
RedditT m (a -> b) -> RedditT m a -> RedditT m b
(a -> b -> c) -> RedditT m a -> RedditT m b -> RedditT m c
forall a. a -> RedditT m a
forall a b. RedditT m a -> RedditT m b -> RedditT m a
forall a b. RedditT m a -> RedditT m b -> RedditT m b
forall a b. RedditT m (a -> b) -> RedditT m a -> RedditT m b
forall a b c.
(a -> b -> c) -> RedditT m a -> RedditT m b -> RedditT m c
forall (m :: * -> *). Monad m => Functor (RedditT m)
forall (m :: * -> *) a. Monad m => a -> RedditT m a
forall (m :: * -> *) a b.
Monad m =>
RedditT m a -> RedditT m b -> RedditT m a
forall (m :: * -> *) a b.
Monad m =>
RedditT m a -> RedditT m b -> RedditT m b
forall (m :: * -> *) a b.
Monad m =>
RedditT m (a -> b) -> RedditT m a -> RedditT m b
forall (m :: * -> *) a b c.
Monad m =>
(a -> b -> c) -> RedditT m a -> RedditT m b -> RedditT m c
forall (f :: * -> *).
Functor f
-> (forall a. a -> f a)
-> (forall a b. f (a -> b) -> f a -> f b)
-> (forall a b c. (a -> b -> c) -> f a -> f b -> f c)
-> (forall a b. f a -> f b -> f b)
-> (forall a b. f a -> f b -> f a)
-> Applicative f
<* :: RedditT m a -> RedditT m b -> RedditT m a
$c<* :: forall (m :: * -> *) a b.
Monad m =>
RedditT m a -> RedditT m b -> RedditT m a
*> :: RedditT m a -> RedditT m b -> RedditT m b
$c*> :: forall (m :: * -> *) a b.
Monad m =>
RedditT m a -> RedditT m b -> RedditT m b
liftA2 :: (a -> b -> c) -> RedditT m a -> RedditT m b -> RedditT m c
$cliftA2 :: forall (m :: * -> *) a b c.
Monad m =>
(a -> b -> c) -> RedditT m a -> RedditT m b -> RedditT m c
<*> :: RedditT m (a -> b) -> RedditT m a -> RedditT m b
$c<*> :: forall (m :: * -> *) a b.
Monad m =>
RedditT m (a -> b) -> RedditT m a -> RedditT m b
pure :: a -> RedditT m a
$cpure :: forall (m :: * -> *) a. Monad m => a -> RedditT m a
$cp1Applicative :: forall (m :: * -> *). Monad m => Functor (RedditT m)
Applicative, Applicative (RedditT m)
a -> RedditT m a
Applicative (RedditT m)
-> (forall a b. RedditT m a -> (a -> RedditT m b) -> RedditT m b)
-> (forall a b. RedditT m a -> RedditT m b -> RedditT m b)
-> (forall a. a -> RedditT m a)
-> Monad (RedditT m)
RedditT m a -> (a -> RedditT m b) -> RedditT m b
RedditT m a -> RedditT m b -> RedditT m b
forall a. a -> RedditT m a
forall a b. RedditT m a -> RedditT m b -> RedditT m b
forall a b. RedditT m a -> (a -> RedditT m b) -> RedditT m b
forall (m :: * -> *). Monad m => Applicative (RedditT m)
forall (m :: * -> *) a. Monad m => a -> RedditT m a
forall (m :: * -> *) a b.
Monad m =>
RedditT m a -> RedditT m b -> RedditT m b
forall (m :: * -> *) a b.
Monad m =>
RedditT m a -> (a -> RedditT m b) -> RedditT m b
forall (m :: * -> *).
Applicative m
-> (forall a b. m a -> (a -> m b) -> m b)
-> (forall a b. m a -> m b -> m b)
-> (forall a. a -> m a)
-> Monad m
return :: a -> RedditT m a
$creturn :: forall (m :: * -> *) a. Monad m => a -> RedditT m a
>> :: RedditT m a -> RedditT m b -> RedditT m b
$c>> :: forall (m :: * -> *) a b.
Monad m =>
RedditT m a -> RedditT m b -> RedditT m b
>>= :: RedditT m a -> (a -> RedditT m b) -> RedditT m b
$c>>= :: forall (m :: * -> *) a b.
Monad m =>
RedditT m a -> (a -> RedditT m b) -> RedditT m b
$cp1Monad :: forall (m :: * -> *). Monad m => Applicative (RedditT m)
Monad)

instance MonadTrans RedditT where
  lift :: m a -> RedditT m a
lift = FreeT (RedditF m) m a -> RedditT m a
forall (m :: * -> *) a. FreeT (RedditF m) m a -> RedditT m a
RedditT (FreeT (RedditF m) m a -> RedditT m a)
-> (m a -> FreeT (RedditF m) m a) -> m a -> RedditT m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. m a -> FreeT (RedditF m) m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift

instance MonadIO m => MonadIO (RedditT m) where
  liftIO :: IO a -> RedditT m a
liftIO = FreeT (RedditF m) m a -> RedditT m a
forall (m :: * -> *) a. FreeT (RedditF m) m a -> RedditT m a
RedditT (FreeT (RedditF m) m a -> RedditT m a)
-> (IO a -> FreeT (RedditF m) m a) -> IO a -> RedditT m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO a -> FreeT (RedditF m) m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO

runRoute :: (FromJSON a, Monad m) => Route -> RedditT m a
runRoute :: Route -> RedditT m a
runRoute Route
r = FreeT (RedditF m) m a -> RedditT m a
forall (m :: * -> *) a. FreeT (RedditF m) m a -> RedditT m a
RedditT (FreeT (RedditF m) m a -> RedditT m a)
-> FreeT (RedditF m) m a -> RedditT m a
forall a b. (a -> b) -> a -> b
$ RedditF m a -> FreeT (RedditF m) m a
forall (f :: * -> *) (m :: * -> *) a.
(Functor f, MonadFree f m) =>
f a -> m a
liftF (RedditF m a -> FreeT (RedditF m) m a)
-> RedditF m a -> FreeT (RedditF m) m a
forall a b. (a -> b) -> a -> b
$ Route -> (a -> a) -> RedditF m a
forall b a (m :: * -> *).
FromJSON b =>
Route -> (b -> a) -> RedditF m a
RunRoute Route
r a -> a
forall a. a -> a
id

receiveRoute :: (Receivable a, Monad m) => Route -> RedditT m a
receiveRoute :: Route -> RedditT m a
receiveRoute Route
r = FreeT (RedditF m) m a -> RedditT m a
forall (m :: * -> *) a. FreeT (RedditF m) m a -> RedditT m a
RedditT (FreeT (RedditF m) m a -> RedditT m a)
-> FreeT (RedditF m) m a -> RedditT m a
forall a b. (a -> b) -> a -> b
$ RedditF m a -> FreeT (RedditF m) m a
forall (f :: * -> *) (m :: * -> *) a.
(Functor f, MonadFree f m) =>
f a -> m a
liftF (RedditF m a -> FreeT (RedditF m) m a)
-> RedditF m a -> FreeT (RedditF m) m a
forall a b. (a -> b) -> a -> b
$ Route -> (a -> a) -> RedditF m a
forall b a (m :: * -> *).
Receivable b =>
Route -> (b -> a) -> RedditF m a
ReceiveRoute Route
r a -> a
forall a. a -> a
id

nest :: Monad m => RedditT m a -> RedditT m (Either (APIError RedditError) a)
nest :: RedditT m a -> RedditT m (Either (APIError RedditError) a)
nest RedditT m a
f = FreeT (RedditF m) m (Either (APIError RedditError) a)
-> RedditT m (Either (APIError RedditError) a)
forall (m :: * -> *) a. FreeT (RedditF m) m a -> RedditT m a
RedditT (FreeT (RedditF m) m (Either (APIError RedditError) a)
 -> RedditT m (Either (APIError RedditError) a))
-> FreeT (RedditF m) m (Either (APIError RedditError) a)
-> RedditT m (Either (APIError RedditError) a)
forall a b. (a -> b) -> a -> b
$ RedditF m (Either (APIError RedditError) a)
-> FreeT (RedditF m) m (Either (APIError RedditError) a)
forall (f :: * -> *) (m :: * -> *) a.
(Functor f, MonadFree f m) =>
f a -> m a
liftF (RedditF m (Either (APIError RedditError) a)
 -> FreeT (RedditF m) m (Either (APIError RedditError) a))
-> RedditF m (Either (APIError RedditError) a)
-> FreeT (RedditF m) m (Either (APIError RedditError) a)
forall a b. (a -> b) -> a -> b
$ RedditT m a
-> (Either (APIError RedditError) a
    -> Either (APIError RedditError) a)
-> RedditF m (Either (APIError RedditError) a)
forall (m :: * -> *) b a.
RedditT m b
-> (Either (APIError RedditError) b -> a) -> RedditF m a
Nest RedditT m a
f Either (APIError RedditError) a -> Either (APIError RedditError) a
forall a. a -> a
id

withBaseURL :: Monad m => Text -> RedditT m a -> RedditT m a
withBaseURL :: Text -> RedditT m a -> RedditT m a
withBaseURL Text
u RedditT m a
f = FreeT (RedditF m) m a -> RedditT m a
forall (m :: * -> *) a. FreeT (RedditF m) m a -> RedditT m a
RedditT (FreeT (RedditF m) m a -> RedditT m a)
-> FreeT (RedditF m) m a -> RedditT m a
forall a b. (a -> b) -> a -> b
$ RedditF m a -> FreeT (RedditF m) m a
forall (f :: * -> *) (m :: * -> *) a.
(Functor f, MonadFree f m) =>
f a -> m a
liftF (RedditF m a -> FreeT (RedditF m) m a)
-> RedditF m a -> FreeT (RedditF m) m a
forall a b. (a -> b) -> a -> b
$ Text -> RedditT m a -> (a -> a) -> RedditF m a
forall (m :: * -> *) b a.
Text -> RedditT m b -> (b -> a) -> RedditF m a
WithBaseURL Text
u RedditT m a
f a -> a
forall a. a -> a
id

withHeaders :: Monad m => ([Header] -> [Header]) -> RedditT m a -> RedditT m a
withHeaders :: ([Header] -> [Header]) -> RedditT m a -> RedditT m a
withHeaders [Header] -> [Header]
u RedditT m a
f = FreeT (RedditF m) m a -> RedditT m a
forall (m :: * -> *) a. FreeT (RedditF m) m a -> RedditT m a
RedditT (FreeT (RedditF m) m a -> RedditT m a)
-> FreeT (RedditF m) m a -> RedditT m a
forall a b. (a -> b) -> a -> b
$ RedditF m a -> FreeT (RedditF m) m a
forall (f :: * -> *) (m :: * -> *) a.
(Functor f, MonadFree f m) =>
f a -> m a
liftF (RedditF m a -> FreeT (RedditF m) m a)
-> RedditF m a -> FreeT (RedditF m) m a
forall a b. (a -> b) -> a -> b
$ ([Header] -> [Header]) -> RedditT m a -> (a -> a) -> RedditF m a
forall (m :: * -> *) b a.
([Header] -> [Header]) -> RedditT m b -> (b -> a) -> RedditF m a
WithHeaders [Header] -> [Header]
u RedditT m a
f a -> a
forall a. a -> a
id

failWith :: Monad m => APIError RedditError -> RedditT m a
failWith :: APIError RedditError -> RedditT m a
failWith = FreeT (RedditF m) m a -> RedditT m a
forall (m :: * -> *) a. FreeT (RedditF m) m a -> RedditT m a
RedditT (FreeT (RedditF m) m a -> RedditT m a)
-> (APIError RedditError -> FreeT (RedditF m) m a)
-> APIError RedditError
-> RedditT m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. RedditF m a -> FreeT (RedditF m) m a
forall (f :: * -> *) (m :: * -> *) a.
(Functor f, MonadFree f m) =>
f a -> m a
liftF (RedditF m a -> FreeT (RedditF m) m a)
-> (APIError RedditError -> RedditF m a)
-> APIError RedditError
-> FreeT (RedditF m) m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. APIError RedditError -> RedditF m a
forall (m :: * -> *) a. APIError RedditError -> RedditF m a
FailWith

newtype Modhash = Modhash Text
  deriving (Int -> Modhash -> ShowS
[Modhash] -> ShowS
Modhash -> String
(Int -> Modhash -> ShowS)
-> (Modhash -> String) -> ([Modhash] -> ShowS) -> Show Modhash
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Modhash] -> ShowS
$cshowList :: [Modhash] -> ShowS
show :: Modhash -> String
$cshow :: Modhash -> String
showsPrec :: Int -> Modhash -> ShowS
$cshowsPrec :: Int -> Modhash -> ShowS
Show, ReadPrec [Modhash]
ReadPrec Modhash
Int -> ReadS Modhash
ReadS [Modhash]
(Int -> ReadS Modhash)
-> ReadS [Modhash]
-> ReadPrec Modhash
-> ReadPrec [Modhash]
-> Read Modhash
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [Modhash]
$creadListPrec :: ReadPrec [Modhash]
readPrec :: ReadPrec Modhash
$creadPrec :: ReadPrec Modhash
readList :: ReadS [Modhash]
$creadList :: ReadS [Modhash]
readsPrec :: Int -> ReadS Modhash
$creadsPrec :: Int -> ReadS Modhash
Read, Modhash -> Modhash -> Bool
(Modhash -> Modhash -> Bool)
-> (Modhash -> Modhash -> Bool) -> Eq Modhash
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Modhash -> Modhash -> Bool
$c/= :: Modhash -> Modhash -> Bool
== :: Modhash -> Modhash -> Bool
$c== :: Modhash -> Modhash -> Bool
Eq)

instance FromJSON Modhash where
  parseJSON :: Value -> Parser Modhash
parseJSON (Object Object
o) =
    Text -> Modhash
Modhash (Text -> Modhash) -> Parser Text -> Parser Modhash
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ((Object
o Object -> Key -> Parser Object
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"json") Parser Object -> (Object -> Parser Object) -> Parser Object
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Object -> Key -> Parser Object
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"data") Parser Object -> (Object -> Parser Text) -> Parser Text
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Object -> Key -> Parser Text
forall a. FromJSON a => Object -> Key -> Parser a
.: Key
"modhash"))
  parseJSON Value
_ = Parser Modhash
forall a. Monoid a => a
mempty

data LoginDetails = LoginDetails Modhash CookieJar
  deriving (Int -> LoginDetails -> ShowS
[LoginDetails] -> ShowS
LoginDetails -> String
(Int -> LoginDetails -> ShowS)
-> (LoginDetails -> String)
-> ([LoginDetails] -> ShowS)
-> Show LoginDetails
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [LoginDetails] -> ShowS
$cshowList :: [LoginDetails] -> ShowS
show :: LoginDetails -> String
$cshow :: LoginDetails -> String
showsPrec :: Int -> LoginDetails -> ShowS
$cshowsPrec :: Int -> LoginDetails -> ShowS
Show)

instance Receivable LoginDetails where
  receive :: Response ByteString -> Either (APIError e) LoginDetails
receive Response ByteString
x = do
    (Response ByteString
resp, JSONResponse Modhash
mh) <- Response ByteString
-> Either (APIError e) (Response ByteString, JSONResponse Modhash)
forall r e.
(Receivable r, ErrorReceivable e) =>
Response ByteString -> Either (APIError e) r
receive Response ByteString
x
    LoginDetails -> Either (APIError e) LoginDetails
forall (m :: * -> *) a. Monad m => a -> m a
return (LoginDetails -> Either (APIError e) LoginDetails)
-> LoginDetails -> Either (APIError e) LoginDetails
forall a b. (a -> b) -> a -> b
$ Modhash -> CookieJar -> LoginDetails
LoginDetails (JSONResponse Modhash -> Modhash
forall a. JSONResponse a -> a
unwrapJSON JSONResponse Modhash
mh) (Response ByteString -> CookieJar
forall body. Response body -> CookieJar
responseCookieJar (Response ByteString
resp :: Response ByteString))

newtype POSTWrapped a = POSTWrapped a
  deriving (Int -> POSTWrapped a -> ShowS
[POSTWrapped a] -> ShowS
POSTWrapped a -> String
(Int -> POSTWrapped a -> ShowS)
-> (POSTWrapped a -> String)
-> ([POSTWrapped a] -> ShowS)
-> Show (POSTWrapped a)
forall a. Show a => Int -> POSTWrapped a -> ShowS
forall a. Show a => [POSTWrapped a] -> ShowS
forall a. Show a => POSTWrapped a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [POSTWrapped a] -> ShowS
$cshowList :: forall a. Show a => [POSTWrapped a] -> ShowS
show :: POSTWrapped a -> String
$cshow :: forall a. Show a => POSTWrapped a -> String
showsPrec :: Int -> POSTWrapped a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> POSTWrapped a -> ShowS
Show, ReadPrec [POSTWrapped a]
ReadPrec (POSTWrapped a)
Int -> ReadS (POSTWrapped a)
ReadS [POSTWrapped a]
(Int -> ReadS (POSTWrapped a))
-> ReadS [POSTWrapped a]
-> ReadPrec (POSTWrapped a)
-> ReadPrec [POSTWrapped a]
-> Read (POSTWrapped a)
forall a. Read a => ReadPrec [POSTWrapped a]
forall a. Read a => ReadPrec (POSTWrapped a)
forall a. Read a => Int -> ReadS (POSTWrapped a)
forall a. Read a => ReadS [POSTWrapped a]
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [POSTWrapped a]
$creadListPrec :: forall a. Read a => ReadPrec [POSTWrapped a]
readPrec :: ReadPrec (POSTWrapped a)
$creadPrec :: forall a. Read a => ReadPrec (POSTWrapped a)
readList :: ReadS [POSTWrapped a]
$creadList :: forall a. Read a => ReadS [POSTWrapped a]
readsPrec :: Int -> ReadS (POSTWrapped a)
$creadsPrec :: forall a. Read a => Int -> ReadS (POSTWrapped a)
Read, POSTWrapped a -> POSTWrapped a -> Bool
(POSTWrapped a -> POSTWrapped a -> Bool)
-> (POSTWrapped a -> POSTWrapped a -> Bool) -> Eq (POSTWrapped a)
forall a. Eq a => POSTWrapped a -> POSTWrapped a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: POSTWrapped a -> POSTWrapped a -> Bool
$c/= :: forall a. Eq a => POSTWrapped a -> POSTWrapped a -> Bool
== :: POSTWrapped a -> POSTWrapped a -> Bool
$c== :: forall a. Eq a => POSTWrapped a -> POSTWrapped a -> Bool
Eq)

instance Functor POSTWrapped where
  fmap :: (a -> b) -> POSTWrapped a -> POSTWrapped b
fmap a -> b
f (POSTWrapped a
a) = b -> POSTWrapped b
forall a. a -> POSTWrapped a
POSTWrapped (a -> b
f a
a)

data RateLimits =
  RateLimits { RateLimits -> Bool
should :: ShouldRateLimit
             , RateLimits -> Maybe RateLimitInfo
info :: Maybe RateLimitInfo }
  deriving (Int -> RateLimits -> ShowS
[RateLimits] -> ShowS
RateLimits -> String
(Int -> RateLimits -> ShowS)
-> (RateLimits -> String)
-> ([RateLimits] -> ShowS)
-> Show RateLimits
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [RateLimits] -> ShowS
$cshowList :: [RateLimits] -> ShowS
show :: RateLimits -> String
$cshow :: RateLimits -> String
showsPrec :: Int -> RateLimits -> ShowS
$cshowsPrec :: Int -> RateLimits -> ShowS
Show, ReadPrec [RateLimits]
ReadPrec RateLimits
Int -> ReadS RateLimits
ReadS [RateLimits]
(Int -> ReadS RateLimits)
-> ReadS [RateLimits]
-> ReadPrec RateLimits
-> ReadPrec [RateLimits]
-> Read RateLimits
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [RateLimits]
$creadListPrec :: ReadPrec [RateLimits]
readPrec :: ReadPrec RateLimits
$creadPrec :: ReadPrec RateLimits
readList :: ReadS [RateLimits]
$creadList :: ReadS [RateLimits]
readsPrec :: Int -> ReadS RateLimits
$creadsPrec :: Int -> ReadS RateLimits
Read, RateLimits -> RateLimits -> Bool
(RateLimits -> RateLimits -> Bool)
-> (RateLimits -> RateLimits -> Bool) -> Eq RateLimits
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: RateLimits -> RateLimits -> Bool
$c/= :: RateLimits -> RateLimits -> Bool
== :: RateLimits -> RateLimits -> Bool
$c== :: RateLimits -> RateLimits -> Bool
Eq)

type ShouldRateLimit = Bool

data RateLimitInfo = RateLimitInfo { RateLimitInfo -> Integer
used :: Integer
                                   , RateLimitInfo -> Integer
remaining :: Integer
                                   , RateLimitInfo -> UTCTime
resetTime :: UTCTime }
  deriving (Int -> RateLimitInfo -> ShowS
[RateLimitInfo] -> ShowS
RateLimitInfo -> String
(Int -> RateLimitInfo -> ShowS)
-> (RateLimitInfo -> String)
-> ([RateLimitInfo] -> ShowS)
-> Show RateLimitInfo
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [RateLimitInfo] -> ShowS
$cshowList :: [RateLimitInfo] -> ShowS
show :: RateLimitInfo -> String
$cshow :: RateLimitInfo -> String
showsPrec :: Int -> RateLimitInfo -> ShowS
$cshowsPrec :: Int -> RateLimitInfo -> ShowS
Show, ReadPrec [RateLimitInfo]
ReadPrec RateLimitInfo
Int -> ReadS RateLimitInfo
ReadS [RateLimitInfo]
(Int -> ReadS RateLimitInfo)
-> ReadS [RateLimitInfo]
-> ReadPrec RateLimitInfo
-> ReadPrec [RateLimitInfo]
-> Read RateLimitInfo
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [RateLimitInfo]
$creadListPrec :: ReadPrec [RateLimitInfo]
readPrec :: ReadPrec RateLimitInfo
$creadPrec :: ReadPrec RateLimitInfo
readList :: ReadS [RateLimitInfo]
$creadList :: ReadS [RateLimitInfo]
readsPrec :: Int -> ReadS RateLimitInfo
$creadsPrec :: Int -> ReadS RateLimitInfo
Read, RateLimitInfo -> RateLimitInfo -> Bool
(RateLimitInfo -> RateLimitInfo -> Bool)
-> (RateLimitInfo -> RateLimitInfo -> Bool) -> Eq RateLimitInfo
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: RateLimitInfo -> RateLimitInfo -> Bool
$c/= :: RateLimitInfo -> RateLimitInfo -> Bool
== :: RateLimitInfo -> RateLimitInfo -> Bool
$c== :: RateLimitInfo -> RateLimitInfo -> Bool
Eq)

headersToRateLimitInfo :: ResponseHeaders -> UTCTime -> Maybe RateLimitInfo
headersToRateLimitInfo :: [Header] -> UTCTime -> Maybe RateLimitInfo
headersToRateLimitInfo [Header]
hs UTCTime
now =
  Integer -> Integer -> UTCTime -> RateLimitInfo
RateLimitInfo (Integer -> Integer -> UTCTime -> RateLimitInfo)
-> Maybe Integer -> Maybe (Integer -> UTCTime -> RateLimitInfo)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe Integer
rlUsed Maybe (Integer -> UTCTime -> RateLimitInfo)
-> Maybe Integer -> Maybe (UTCTime -> RateLimitInfo)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Maybe Integer
rlRemaining Maybe (UTCTime -> RateLimitInfo)
-> Maybe UTCTime -> Maybe RateLimitInfo
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Maybe UTCTime
rlResetTime'
  where (Maybe Integer
rlUsed, Maybe Integer
rlRemaining, Maybe Integer
rlResetTime) =
          (HeaderName -> Maybe Integer)
-> (HeaderName, HeaderName, HeaderName)
-> (Maybe Integer, Maybe Integer, Maybe Integer)
forall t c. (t -> c) -> (t, t, t) -> (c, c, c)
trimap HeaderName -> Maybe Integer
extract (HeaderName
"x-ratelimit-used", HeaderName
"x-ratelimit-remaining", HeaderName
"x-ratelimit-reset")
        rlResetTime' :: Maybe UTCTime
rlResetTime' = (Integer -> UTCTime) -> Maybe Integer -> Maybe UTCTime
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\Integer
s -> NominalDiffTime -> UTCTime -> UTCTime
addUTCTime (Integer -> NominalDiffTime
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
s) UTCTime
now) Maybe Integer
rlResetTime
        extract :: HeaderName -> Maybe Integer
extract HeaderName
s = HeaderName -> [Header] -> Maybe ByteString
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup HeaderName
s [Header]
hs Maybe ByteString -> (ByteString -> Maybe Integer) -> Maybe Integer
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= String -> Maybe Integer
forall a. Read a => String -> Maybe a
readMaybe (String -> Maybe Integer)
-> (ByteString -> String) -> ByteString -> Maybe Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> String
BS.unpack
        trimap :: (t -> c) -> (t, t, t) -> (c, c, c)
trimap t -> c
f (t
a, t
b, t
c) = (t -> c
f t
a, t -> c
f t
b, t -> c
f t
c)

data ClientParams = ClientParams Text Text
  deriving (Int -> ClientParams -> ShowS
[ClientParams] -> ShowS
ClientParams -> String
(Int -> ClientParams -> ShowS)
-> (ClientParams -> String)
-> ([ClientParams] -> ShowS)
-> Show ClientParams
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ClientParams] -> ShowS
$cshowList :: [ClientParams] -> ShowS
show :: ClientParams -> String
$cshow :: ClientParams -> String
showsPrec :: Int -> ClientParams -> ShowS
$cshowsPrec :: Int -> ClientParams -> ShowS
Show, ReadPrec [ClientParams]
ReadPrec ClientParams
Int -> ReadS ClientParams
ReadS [ClientParams]
(Int -> ReadS ClientParams)
-> ReadS [ClientParams]
-> ReadPrec ClientParams
-> ReadPrec [ClientParams]
-> Read ClientParams
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [ClientParams]
$creadListPrec :: ReadPrec [ClientParams]
readPrec :: ReadPrec ClientParams
$creadPrec :: ReadPrec ClientParams
readList :: ReadS [ClientParams]
$creadList :: ReadS [ClientParams]
readsPrec :: Int -> ReadS ClientParams
$creadsPrec :: Int -> ReadS ClientParams
Read, ClientParams -> ClientParams -> Bool
(ClientParams -> ClientParams -> Bool)
-> (ClientParams -> ClientParams -> Bool) -> Eq ClientParams
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ClientParams -> ClientParams -> Bool
$c/= :: ClientParams -> ClientParams -> Bool
== :: ClientParams -> ClientParams -> Bool
$c== :: ClientParams -> ClientParams -> Bool
Eq, Eq ClientParams
Eq ClientParams
-> (ClientParams -> ClientParams -> Ordering)
-> (ClientParams -> ClientParams -> Bool)
-> (ClientParams -> ClientParams -> Bool)
-> (ClientParams -> ClientParams -> Bool)
-> (ClientParams -> ClientParams -> Bool)
-> (ClientParams -> ClientParams -> ClientParams)
-> (ClientParams -> ClientParams -> ClientParams)
-> Ord ClientParams
ClientParams -> ClientParams -> Bool
ClientParams -> ClientParams -> Ordering
ClientParams -> ClientParams -> ClientParams
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: ClientParams -> ClientParams -> ClientParams
$cmin :: ClientParams -> ClientParams -> ClientParams
max :: ClientParams -> ClientParams -> ClientParams
$cmax :: ClientParams -> ClientParams -> ClientParams
>= :: ClientParams -> ClientParams -> Bool
$c>= :: ClientParams -> ClientParams -> Bool
> :: ClientParams -> ClientParams -> Bool
$c> :: ClientParams -> ClientParams -> Bool
<= :: ClientParams -> ClientParams -> Bool
$c<= :: ClientParams -> ClientParams -> Bool
< :: ClientParams -> ClientParams -> Bool
$c< :: ClientParams -> ClientParams -> Bool
compare :: ClientParams -> ClientParams -> Ordering
$ccompare :: ClientParams -> ClientParams -> Ordering
$cp1Ord :: Eq ClientParams
Ord)

mkClientParamsHeader :: ClientParams -> (HeaderName, BS.ByteString)
mkClientParamsHeader :: ClientParams -> Header
mkClientParamsHeader (ClientParams Text
i Text
s) = (HeaderName
"Authorization", Text -> ByteString
Text.encodeUtf8 (Text -> ByteString) -> Text -> ByteString
forall a b. (a -> b) -> a -> b
$ Text
i Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
":" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
s)

addAPIType :: Route -> Route
addAPIType :: Route -> Route
addAPIType (Route [Text]
fs [URLParam]
ps ByteString
m) = [Text] -> [URLParam] -> ByteString -> Route
Route [Text]
fs (Text
"api_type" Text -> Text -> URLParam
forall a. ToQuery a => Text -> a -> URLParam
=. (Text
"json" :: Text) URLParam -> [URLParam] -> [URLParam]
forall a. a -> [a] -> [a]
: [URLParam]
ps) ByteString
m

mainBaseURL :: Text
mainBaseURL :: Text
mainBaseURL = Text
"https://api.reddit.com"

loginBaseURL :: Text
loginBaseURL :: Text
loginBaseURL = Text
"https://ssl.reddit.com"