{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE Trustworthy         #-}

-------------------------------------------------------------------
-- |
-- Module    : Network.MessagePackRpc.Client
-- Copyright : (c) Hideyuki Tanaka, 2010-2015
-- License   : BSD3
--
-- Maintainer:  Hideyuki Tanaka <tanaka.hideyuki@gmail.com>
-- Stability :  experimental
-- Portability: portable
--
-- This module is client library of MessagePack-RPC.
-- The specification of MessagePack-RPC is at
-- <http://redmine.msgpack.org/projects/msgpack/wiki/RPCProtocolSpec>.
--
-- A simple example:
--
-- > import Network.MessagePackRpc.Client
-- >
-- > add :: Int -> Int -> Client Int
-- > add = call "add"
-- >
-- > main = execClient "localhost" 5000 $ do
-- >   ret <- add 123 456
-- >   liftIO $ print ret
--
--------------------------------------------------------------------

module Network.MessagePack.Client.Basic (
  -- * MessagePack Client type
    Client
  , ClientT
  , execClient

  -- * Call RPC method
  , call

  -- * RPC error
  , RpcError (..)
  , RpcType (..)
  ) where

import qualified Control.Monad.State.Strict          as CMS
import qualified Data.ByteString                     as S
import           Data.Conduit                        (($$+))
import           Data.Conduit.Network                (appSink, appSource,
                                                      clientSettings,
                                                      runTCPClient)

import           Network.MessagePack.Client.Internal
import           Network.MessagePack.Types.Client
import           Network.MessagePack.Types.Error


execClient :: S.ByteString -> Int -> Client a -> IO a
execClient :: ByteString -> Int -> Client a -> IO a
execClient ByteString
host Int
port Client a
client =
  ClientSettings -> (AppData -> IO a) -> IO a
forall a. ClientSettings -> (AppData -> IO a) -> IO a
runTCPClient (Int -> ByteString -> ClientSettings
clientSettings Int
port ByteString
host) ((AppData -> IO a) -> IO a) -> (AppData -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \AppData
ad -> do
    (SealedConduitT () ByteString IO ()
rsrc, ()
_) <- AppData -> ConduitT () ByteString IO ()
forall ad (m :: * -> *) i.
(HasReadWrite ad, MonadIO m) =>
ad -> ConduitT i ByteString m ()
appSource AppData
ad ConduitT () ByteString IO ()
-> Sink ByteString IO ()
-> IO (SealedConduitT () ByteString IO (), ())
forall (m :: * -> *) a b.
Monad m =>
Source m a -> Sink a m b -> m (SealedConduitT () a m (), b)
$$+ () -> Sink ByteString IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
    StateT (Connection IO) IO a -> Connection IO -> IO a
forall (m :: * -> *) s a. Monad m => StateT s m a -> s -> m a
CMS.evalStateT (Client a -> StateT (Connection IO) IO a
forall (m :: * -> *) a. ClientT m a -> StateT (Connection m) m a
runClientT Client a
client) Connection :: forall (m :: * -> *).
SealedConduitT () ByteString m ()
-> ConduitT ByteString Void m () -> Int -> [Text] -> Connection m
Connection
      { connSource :: SealedConduitT () ByteString IO ()
connSource = SealedConduitT () ByteString IO ()
rsrc
      , connSink :: Sink ByteString IO ()
connSink   = AppData -> Sink ByteString IO ()
forall ad (m :: * -> *) o.
(HasReadWrite ad, MonadIO m) =>
ad -> ConduitT ByteString o m ()
appSink AppData
ad
      , connMsgId :: Int
connMsgId  = Int
0
      , connMths :: [Text]
connMths   = []
      }