{-# LANGUAGE OverloadedStrings #-} module Network.YAML.Caller where import qualified Data.Map as M import Data.Object.Yaml import Data.Convertible.Base import qualified Data.ByteString.Char8 as BS import Network import System.IO import Control.Monad import Control.Concurrent import Network.YAML.Base import Network.YAML.Instances import Network.YAML.Server -- | Send any YAML text and return an answer sendYAML :: (BS.ByteString, Int) -- ^ (Hostname, port) -> BS.ByteString -- ^ YAML text -> IO BS.ByteString -- ^ Answer sendYAML (host,port) yaml = withSocketsDo $ do h <- connectTo (BS.unpack host) (PortNumber $ fromIntegral port) hSetBuffering h NoBuffering BS.hPutStrLn h yaml lns <- readHandle h [] hClose h let text = BS.unlines lns return text -- | Call remote method call :: (IsYamlObject a, IsYamlObject b) => (BS.ByteString, Int) -- ^ (Host name, port number) -> BS.ByteString -- ^ Name of method -> a -- ^ Argument for method -> IO b call (host,port) name args = do let c = mkCall name (cs args) s = serialize c text <- sendYAML (host,port) s case unserialize text of Nothing -> fail "No answer" Just x -> return x -- | Similar, but select server on each call callDynamic :: (IsYamlObject a, IsYamlObject b) => (BS.ByteString -> IO (BS.ByteString,Int)) -- ^ Get (Host name, port number) from service name -> BS.ByteString -- ^ Name of the service -> BS.ByteString -- ^ Name of method -> a -- ^ Argument for method -> IO b callDynamic getServer service name args = do srv <- getServer service call srv name args -- | Call a method and put it's result into MVar callF :: (IsYamlObject a, IsYamlObject b) => (BS.ByteString -> IO (BS.ByteString, Int)) -- ^ Get (Host, port) from service name -> BS.ByteString -- ^ Service name -> BS.ByteString -- ^ Method name -> (a, MVar b) -- ^ (Argument, MVar for result) -> IO () callF getServer service name (args, var) = do srv <- getServer service -- putStrLn $ "Calling to " ++ show srv r <- call srv name args putMVar var r -- | Call a method for each argument in the list in parallel -- (it can run method for each argument on another server) callP :: (IsYamlObject a, IsYamlObject b) => (BS.ByteString -> IO (BS.ByteString, Int)) -- ^ Get (Host, port) from service name -> BS.ByteString -- ^ Service name -> BS.ByteString -- ^ Method name -> [a] -- ^ List of arguments -> IO [b] callP getServer service name args = do let n = length args vars <- replicateM n newEmptyMVar mapM (forkIO . callF getServer service name) $ zip args vars mapM takeMVar vars