module Control.Remote.Monad.JSON (
RPC,
method,
notification,
send,
Session,
weakSession,
strongSession,
applicativeSession,
SendAPI(..),
Args(..)
) where
import Control.Monad.Fail()
import Control.Remote.Monad.JSON.Types
import Control.Monad.Catch()
import Control.Natural
import Data.Aeson
import Data.Text(Text)
import Control.Remote.Monad
import qualified Control.Remote.Monad.Packet.Weak as WP
import qualified Control.Remote.Monad.Packet.Strong as SP
import qualified Control.Remote.Monad.Packet.Applicative as AP
import qualified Data.HashMap.Strict as HM
method :: FromJSON a => Text -> Args -> RPC a
method nm args = RPC $ procedure $ Method nm args
notification :: Text -> Args -> RPC ()
notification nm args = RPC $ command $ Notification nm args
runWeakRPC :: (SendAPI ~> IO) -> WP.WeakPacket Notification Method a -> IO a
runWeakRPC f (WP.Command n) = f (Async (toJSON $ NotificationCall $ n))
runWeakRPC f (WP.Procedure m) = do
let tid = 1
v <- f (Sync (toJSON $ mkMethodCall m tid))
res <- parseReply v
parseMethodResult m tid res
runStrongRPC :: (SendAPI ~> IO) -> SP.StrongPacket Notification Method a -> IO a
runStrongRPC f packet = go packet ([]++)
where
go :: forall a . SP.StrongPacket Notification Method a -> ([Notification]->[Notification]) -> IO a
go (SP.Command n cs) ls = go cs (ls . ([n] ++))
go (SP.Done) ls = do
let toSend = (map(toJSON . NotificationCall) (ls []))
() <- sendBatchAsync f toSend
return ()
go (SP.Procedure m) ls = do
let tid = 1
let toSend = (map (toJSON . NotificationCall) (ls []) ) ++ [toJSON $ mkMethodCall m tid]
res <- sendBatchSync f toSend
parseMethodResult m tid res
sendBatchAsync :: (SendAPI ~> IO) -> [Value] -> IO ()
sendBatchAsync _ [] = return ()
sendBatchAsync f [x] = f (Async x)
sendBatchAsync f xs = f (Async (toJSON xs))
sendBatchSync :: (SendAPI ~> IO) -> [Value] -> IO (HM.HashMap IDTag Value)
sendBatchSync f xs = f (Sync (toJSON xs)) >>= parseReply
runApplicativeRPC :: (SendAPI ~> IO) -> AP.ApplicativePacket Notification Method a -> IO a
runApplicativeRPC f packet = do
case AP.superCommand packet of
Just a -> do () <- sendBatchAsync f (map toJSON $ ls0 [])
return a
Nothing -> do
rs <- sendBatchSync f (map toJSON $ ls0 [])
ff0 rs
where
(ls0,ff0) = go packet 1
go :: forall a . AP.ApplicativePacket Notification Method a -> IDTag
-> ([JSONCall]->[JSONCall], (HM.HashMap IDTag Value -> IO a))
go (AP.Pure a ) _tid = (id, \ _ -> return a)
go (AP.Command aps n) tid = (ls . ([(NotificationCall n)] ++), ff)
where (ls,ff) = go aps tid
go (AP.Procedure aps m ) tid = ( ls . ([mkMethodCall m tid]++)
, \ mp -> ff mp <*> parseMethodResult m tid mp
)
where (ls, ff) = go aps (tid + 1)
weakSession :: (SendAPI :~> IO) -> Session
weakSession f = Session $ runMonad (nat $ runWeakRPC (run f))
strongSession :: (SendAPI :~> IO) -> Session
strongSession f = Session $ runMonad (nat $ runStrongRPC (run f))
applicativeSession :: (SendAPI :~> IO) -> Session
applicativeSession f = Session $ runMonad (nat $ runApplicativeRPC (run f))
send :: Session -> RPC a -> IO a
send (Session f) (RPC m) = f # m