{- |
Module      :  Data.Conduit.JsonRpc.Internal.Types
Description :  Types used internally to encode requests and responses.
Copyright   :  (c) 2015 Gabriele Sales
-}

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}

module Data.Conduit.JsonRpc.Internal.Types
  ( Request(..)
  , Response(..) )
where

import           Control.Applicative
import           Control.Monad
import           Data.Aeson          hiding (Error)
import           Data.Aeson.Types    (emptyArray)
import           Data.Monoid         as M (mempty)
import           Data.Text           (Text)


data Request a = Request { Request a -> Text
reqMethod :: Text
                         , Request a -> a
reqParams :: a
                         , Request a -> Value
reqId     :: Value }

instance FromJSON (Request Value) where
  parseJSON :: Value -> Parser (Request Value)
parseJSON (Object Object
v) = do
    Text
version <- Object
v Object -> Text -> Parser Text
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"jsonrpc"
    Bool -> Parser ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Text
version Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== (Text
"2.0" :: Text))
    Text -> Value -> Value -> Request Value
forall a. Text -> a -> Value -> Request a
Request (Text -> Value -> Value -> Request Value)
-> Parser Text -> Parser (Value -> Value -> Request Value)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
v Object -> Text -> Parser Text
forall a. FromJSON a => Object -> Text -> Parser a
.:  Text
"method" Parser (Value -> Value -> Request Value)
-> Parser Value -> Parser (Value -> Request Value)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*>
                (Object
v Object -> Text -> Parser (Maybe Value)
forall a. FromJSON a => Object -> Text -> Parser (Maybe a)
.:? Text
"params") Parser (Maybe Value) -> Value -> Parser Value
forall a. Parser (Maybe a) -> a -> Parser a
.!= Value
emptyArray Parser (Value -> Request Value)
-> Parser Value -> Parser (Request Value)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*>
                Object
v Object -> Text -> Parser Value
forall a. FromJSON a => Object -> Text -> Parser a
.:  Text
"id"

  parseJSON Value
_ = Parser (Request Value)
forall a. Monoid a => a
M.mempty

instance ToJSON a => ToJSON (Request a) where
  toJSON :: Request a -> Value
toJSON (Request Text
m a
ps Value
id) =
    [Pair] -> Value
object [ Text
"jsonrpc" Text -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= (Text
"2.0" :: Text)
           , Text
"method"  Text -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Text
m
           , Text
"params"  Text -> Value -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= a -> Value
forall a. ToJSON a => a -> Value
toJSON a
ps
           , Text
"id"      Text -> Value -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Value
id ]


data Response a = Result { Response a -> a
result   :: a
                         , Response a -> Value
resultId :: Value }
                | Error  { Response a -> Int
errCode  :: Int
                         , Response a -> Text
errMsg   :: Text
                         , Response a -> Maybe Value
errRefId :: Maybe Value }
  deriving (Int -> Response a -> ShowS
[Response a] -> ShowS
Response a -> String
(Int -> Response a -> ShowS)
-> (Response a -> String)
-> ([Response a] -> ShowS)
-> Show (Response a)
forall a. Show a => Int -> Response a -> ShowS
forall a. Show a => [Response a] -> ShowS
forall a. Show a => Response a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Response a] -> ShowS
$cshowList :: forall a. Show a => [Response a] -> ShowS
show :: Response a -> String
$cshow :: forall a. Show a => Response a -> String
showsPrec :: Int -> Response a -> ShowS
$cshowsPrec :: forall a. Show a => Int -> Response a -> ShowS
Show)

instance FromJSON a => FromJSON (Response a) where
  parseJSON :: Value -> Parser (Response a)
parseJSON (Object Object
v) = do
    Text
version <- Object
v Object -> Text -> Parser Text
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"jsonrpc"
    Bool -> Parser ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Text
version Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== (Text
"2.0" :: Text))
    Parser (Response a)
fromResult Parser (Response a) -> Parser (Response a) -> Parser (Response a)
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Parser (Response a)
forall a. Parser (Response a)
fromError

    where
      fromResult :: Parser (Response a)
fromResult = a -> Value -> Response a
forall a. a -> Value -> Response a
Result (a -> Value -> Response a)
-> Parser a -> Parser (Value -> Response a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Object
v Object -> Text -> Parser Value
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"result" Parser Value -> (Value -> Parser a) -> Parser a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Value -> Parser a
forall a. FromJSON a => Value -> Parser a
parseJSON)
                          Parser (Value -> Response a) -> Parser Value -> Parser (Response a)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v Object -> Text -> Parser Value
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"id"

      fromError :: Parser (Response a)
fromError = do
        Object
err <- Object
v Object -> Text -> Parser Object
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"error"
        Int -> Text -> Maybe Value -> Response a
forall a. Int -> Text -> Maybe Value -> Response a
Error (Int -> Text -> Maybe Value -> Response a)
-> Parser Int -> Parser (Text -> Maybe Value -> Response a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Object
err Object -> Text -> Parser Int
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"code"
              Parser (Text -> Maybe Value -> Response a)
-> Parser Text -> Parser (Maybe Value -> Response a)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
err Object -> Text -> Parser Text
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"message"
              Parser (Maybe Value -> Response a)
-> Parser (Maybe Value) -> Parser (Response a)
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Object
v   Object -> Text -> Parser (Maybe Value)
forall a. FromJSON a => Object -> Text -> Parser a
.: Text
"id"

  parseJSON Value
_ = Parser (Response a)
forall a. Monoid a => a
mempty

instance ToJSON (Response Value) where
  toJSON :: Response Value -> Value
toJSON (Result Value
x Value
id) = [Pair] -> Value
object [ Text
"jsonrpc" Text -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= (Text
"2.0" :: Text)
                                , Text
"result"  Text -> Value -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Value
x
                                , Text
"id"      Text -> Value -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Value
id ]
  toJSON (Error Int
code Text
msg Maybe Value
id) =
    let err :: Value
err = [Pair] -> Value
object [ Text
"code"    Text -> Int -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Int
code
                     , Text
"message" Text -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Text
msg ]
    in [Pair] -> Value
object [ Text
"jsonrpc" Text -> Text -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= (Text
"2.0" :: Text)
              , Text
"error"   Text -> Value -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Value
err
              , Text
"id"      Text -> Maybe Value -> Pair
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Maybe Value
id ]