{-# LANGUAGE DataKinds             #-}
{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables   #-}
{-# LANGUAGE TypeApplications      #-}
{-# LANGUAGE TypeFamilies          #-}
{-# LANGUAGE TypeOperators         #-}
{-# LANGUAGE UndecidableInstances  #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Servant.Server.JsonRpc
    ( module Servant.JsonRpc
    ) where
import           Control.Monad.Error.Class (throwError)
import           Data.Aeson                (FromJSON, ToJSON)
import           Data.Proxy                (Proxy (..))
import           GHC.TypeLits              (KnownSymbol)
import           Servant.API               (NoContent)
import           Servant.Server            (HasServer (..), err400)
import           Servant.JsonRpc
instance (KnownSymbol method, FromJSON p, ToJSON e, ToJSON r)
    => HasServer (JsonRpc method p e r) context where
    type ServerT (JsonRpc method p e r) m = p -> m (Either (JsonRpcErr e) r)
    route _ cx = route endpoint cx . fmap f
        where
        f x (Request _ p (Just ix)) = g ix <$> x p
        f _ _                       = throwError err400
        g ix (Right r) = Result ix r
        g ix (Left e)  = Errors (Just ix) e
        endpoint = Proxy @(JsonRpcEndpoint (JsonRpc method p e r))
    hoistServerWithContext _ _ f x p = f $ x p
instance (KnownSymbol method, FromJSON p)
    => HasServer (JsonRpcNotification method p) context where
    type ServerT (JsonRpcNotification method p) m = p -> m NoContent
    route _ cx = route endpoint cx . fmap f
        where
        f x (Request _ p _) = x p
        endpoint = Proxy @(JsonRpcEndpoint (JsonRpcNotification method p))
    hoistServerWithContext _ _ f x p = f $ x p