-- | wrappers around the RPC calls {-# LANGUAGE PatternGuards #-} module Bitcoin.RPC.Call where -------------------------------------------------------------------------------- import Data.Word import Text.JSON import Text.JSON.Types import Control.Monad.Reader import System.Random import Bitcoin.Misc.Unique import Bitcoin.RPC.JSON import Bitcoin.RPC.HTTP -------------------------------------------------------------------------------- -- | Type of an RPC call (without arguments) type Call a = ReaderT BitcoinURI IO (Either String a) -- | Executes the "call monad" runCalls :: BitcoinURI -> ReaderT BitcoinURI IO a -> IO a runCalls uri action = runReaderT action uri -------------------------------------------------------------------------------- -- | Creates a unique request id, using a combination of a counter and a random number. newRequestId :: IO String newRequestId = do a <- randomRIO (1000000000,9999999999::Word64) b <- newUnique return (show a ++ ":" ++ show b) -------------------------------------------------------------------------------- -- | Things which can be converted to an RPC call parameter list. class ParamList l where paramListJSON :: l -> [JSValue] instance ParamList () where paramListJSON _ = [] instance JSON a => ParamList [a] where paramListJSON xs = map showJSON xs instance (JSON a, JSON b) => ParamList (a,b) where paramListJSON (x,y) = [showJSON x, showJSON y] instance (JSON a, JSON b, JSON c) => ParamList (a,b,c) where paramListJSON (x,y,z) = [showJSON x, showJSON y, showJSON z] instance (JSON a, JSON b, JSON c, JSON d) => ParamList (a,b,c,d) where paramListJSON (x,y,z,w) = [showJSON x, showJSON y, showJSON z, showJSON w] instance (JSON a, JSON b, JSON c, JSON d, JSON e) => ParamList (a,b,c,d,e) where paramListJSON (x,y,z,w,u) = [showJSON x, showJSON y, showJSON z, showJSON w, showJSON u] instance (JSON a, JSON b, JSON c, JSON d, JSON e, JSON f) => ParamList (a,b,c,d,e,f) where paramListJSON (x,y,z,w,u,v) = [showJSON x, showJSON y, showJSON z, showJSON w, showJSON u, showJSON v] -------------------------------------------------------------------------------- -- | Generic API call makeCall :: ParamList l => String -> l -> (JSValue -> Maybe a) -> Call a makeCall method params parseResponse = do uri <- ask lift $ do reqid <- newRequestId let pars = paramListJSON params let req = Request method pars reqid :: Request JSValue -- print req eiresp <- rpcCall uri req case eiresp of Left err -> return (Left err) Right (Response result mberror respid) | respid /= reqid -> return (Left "response id does not match request id") | Just err <- mberror -> return (Left "err") | Just x <- parseResponse result -> return (Right x) | otherwise -> return (Left "cannot parse response") --------------------------------------------------------------------------------