-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | KRPC remote procedure call protocol implementation. -- -- KRPC remote procedure call protocol implementation. -- -- -- -- @package krpc @version 0.2.0.0 -- | This module provides straightforward implementation of KRPC protocol. -- In many situations KRPC should be prefered since it gives more -- safe, convenient and high level api. -- --
--   See http://www.bittorrent.org/beps/bep_0005.html#krpc-protocol
--   
module Remote.KRPC.Protocol -- | Errors used to signal that some error occurred while processing a -- procedure call. Error may be send only from server to client but not -- in the opposite direction. -- -- Errors are encoded as bencoded dictionary: -- --
--   { "y" : "e", "e" : [<error_code>, <human_readable_error_reason>] }
--   
data KError -- | Some error doesn't fit in any other category. GenericError :: ByteString -> KError errorMessage :: KError -> ByteString -- | Occur when server fail to process procedure call. ServerError :: ByteString -> KError errorMessage :: KError -> ByteString -- | Malformed packet, invalid arguments or bad token. ProtocolError :: ByteString -> KError errorMessage :: KError -> ByteString -- | Occur when client trying to call method server don't know. MethodUnknown :: ByteString -> KError errorMessage :: KError -> ByteString type ErrorCode = Int errorCode :: KError -> ErrorCode mkKError :: ErrorCode -> ByteString -> KError -- | Query used to signal that caller want to make procedure call to callee -- and pass arguments in. Therefore query may be only sent from client to -- server but not in the opposite direction. -- -- Queries are encoded as bencoded dictionary: -- --
--   { "y" : "q", "q" : "<method_name>", "a" : [<arg1>, <arg2>, ...] }
--   
data KQuery type MethodName = ByteString type ParamName = ByteString kquery :: MethodName -> [(ParamName, BEncode)] -> KQuery -- | KResponse used to signal that callee successufully process a procedure -- call and to return values from procedure. KResponse should not be sent -- if error occurred during RPC. Thus KResponse may be only sent from -- server to client. -- -- Responses are encoded as bencoded dictionary: -- --
--   { "y" : "r", "r" : [<val1>, <val2>, ...] }
--   
data KResponse type ValName = ByteString kresponse :: [(ValName, BEncode)] -> KResponse sendMessage :: BEncodable msg => msg -> KRemoteAddr -> KRemote -> IO () recvResponse :: KRemote -> IO (Either KError KResponse) type KRemote = Socket type KRemoteAddr = (HostAddress, PortNumber) withRemote :: (MonadBaseControl IO m, MonadIO m) => (KRemote -> m a) -> m a -- | Run server using a given port. Method invocation should be done -- manually. remoteServer :: (MonadBaseControl IO remote, MonadIO remote) => PortNumber -> (KRemoteAddr -> KQuery -> remote (Either KError KResponse)) -> remote () -- | Convert bencoded value to raw bytestring according to the -- specification. encode :: BEncode -> ByteString -- | The same as encode but takes any bencodable value. encoded :: BEncodable a => a -> ByteString -- | Try to convert raw bytestring to bencoded value according to -- specification. decode :: ByteString -> Result BEncode -- | The same as decode but returns any bencodable value. decoded :: BEncodable a => ByteString -> Result a -- | See an example of implementation here Assoc toBEncode :: BEncodable a => a -> BEncode -- | See an example of implementation here reqKey. fromBEncode :: BEncodable a => BEncode -> Result a instance Show KError instance Read KError instance Eq KError instance Ord KError instance Show KQuery instance Read KQuery instance Eq KQuery instance Ord KQuery instance Show KResponse instance Read KResponse instance Eq KResponse instance Ord KResponse instance BEncodable KResponse instance BEncodable KQuery instance BEncodable KError -- | This module provides safe remote procedure call. One important point -- is exceptions and errors, so be able handle them properly we need to -- investigate a bit about how this all works. Internally, in order to -- make method invokation KRPC makes the following steps: -- -- -- -- If every other error occurred caller get the GenericError. All -- errors returned by callee are throwed as ordinary haskell exceptions -- at caller side. Make sure that both callee and caller uses the same -- method signatures and everything should be ok: this KRPC -- implementation provides some level of safety through types. Also note -- that both caller and callee use plain UDP, so KRPC is unreliable. -- -- Consider one tiny example. From now caller = client and -- callee = server or remote. -- -- Somewhere we have to define all procedure signatures. Imagine that -- this is a library shared between client and server: -- --
--   factorialMethod :: Method Int Int
--   factorialMethod = method "factorial" ["x"] ["y"]
--   
-- -- Otherwise you can define this code in both client and server of -- course. But in this case you might get into troubles: you can get -- MethodUnknown or ProtocolError if name or type of method -- will mismatch after not synced changes in client or server code. -- -- Now let's define our client-side: -- --
--   main = withRemote  $ \remote -> do
--      result <- call remote (0, 6000) factorialMethod 4
--      assert (result == 24) $ print "Success!"
--   
-- -- It basically open socket with withRemote and make all the other -- steps in call as describe above. And finally our server-side: -- --
--   factorialImpl :: Int -> Int
--   factorialImpl n = product [1..n]
--   
--   main = runServer [factorialMethod $ return . factorialImpl]
--   
-- -- Here we implement method signature from that shared lib and run server -- with runServer by passing method table in. -- -- For async API use async package, old API have been removed. -- -- For more examples see exsamples or tests -- directories. -- -- For protocol details see Protocol module. module Remote.KRPC -- | Method datatype used to describe name, parameters and return values of -- procedure. Client use a method to invoke, server -- implements the method to make the actual work. -- -- We use the following fantom types to ensure type-safiety: -- -- -- -- To pass raw dictionaries you should specify empty param list: -- --
--   method "my_method" [] [] :: Method BEncode BEncode
--   
-- -- In this case you should handle dictionary extraction by hand, both in -- client and server. data Method param result Method :: MethodName -> [ParamName] -> [ValName] -> Method param result -- | Name used in query. methodName :: Method param result -> MethodName -- | Name of each parameter in right to left order. methodParams :: Method param result -> [ParamName] -- | Name of each return value in right to left order. methodVals :: Method param result -> [ValName] -- | Makes method signature. Note that order of parameters and return -- values are not important as long as corresponding names and types are -- match. For exsample this is the equal definitions: -- --
--   methodA : Method (Foo, Bar) (Baz, Quux)
--   methodA = method "mymethod" ["a", "b"] ["c", "d"]
--   
-- --
--   methodA : Method (Bar, Foo) (Quux, Baz)
--   methodB = method "mymethod" ["b", "a"] ["d", "c"]
--   
method :: MethodName -> [ParamName] -> [ValName] -> Method param result -- | Identity procedure signature. Could be used for echo servers. -- Implemented as: -- --
--   idM = method "id" ["x"] ["y"]
--   
idM :: Method a a -- | Address of remote can be called by client. type RemoteAddr = KRemoteAddr -- | Represent any error mentioned by protocol specification that -- call, await might throw. For more details see -- Protocol. data RPCException RPCException :: KError -> RPCException -- | Makes remote procedure call. Throws RPCException on any error -- occurred. call :: (MonadBaseControl IO host, MonadIO host) => (BEncodable param, BEncodable result) => RemoteAddr -> Method param result -> param -> host result -- | Procedure signature and implementation binded up. type MethodHandler remote = (MethodName, HandlerBody remote) -- | Assign method implementation to the method signature. (==>) :: (BEncodable param, BEncodable result) => Monad remote => Method param result -> (param -> remote result) -> MethodHandler remote -- | Similar to ==>@ but additionally pass caller address. (==>@) :: (BEncodable param, BEncodable result) => Monad remote => Method param result -> (KRemoteAddr -> param -> remote result) -> MethodHandler remote -- | Run RPC server on specified port by using list of handlers. Server -- will dispatch procedure specified by callee, but note that it will not -- create new thread for each connection. server :: (MonadBaseControl IO remote, MonadIO remote) => PortNumber -> [MethodHandler remote] -> remote () -- | The same as call but use already opened socket. call_ :: (MonadBaseControl IO host, MonadIO host) => (BEncodable param, BEncodable result) => Remote -> RemoteAddr -> Method param result -> param -> host result withRemote :: (MonadBaseControl IO m, MonadIO m) => (KRemote -> m a) -> m a instance Typeable RPCException instance Eq (Method param result) instance Ord (Method param result) instance Generic (Method param result) instance Show RPCException instance Eq RPCException instance Datatype D1Method instance Constructor C1_0Method instance Selector S1_0_0Method instance Selector S1_0_1Method instance Selector S1_0_2Method instance Exception RPCException instance (Typeable a, Typeable b) => Show (Method a b) instance BEncodable (Method a b) -- | This module provides message scheme validation for core protocol -- messages from Procotol. This module should be used with -- Protocol, otherwise (if you are using KRPC) this module -- seems to be useless. module Remote.KRPC.Scheme -- | Used to validate any message by its scheme -- -- forall m. m validate scheme m class KMessage message scheme | message -> scheme where validate = (==) . scheme scheme :: KMessage message scheme => message -> scheme validate :: KMessage message scheme => message -> scheme -> Bool data KQueryScheme KQueryScheme :: MethodName -> Set ParamName -> KQueryScheme qscMethod :: KQueryScheme -> MethodName qscParams :: KQueryScheme -> Set ParamName methodQueryScheme :: Method a b -> KQueryScheme newtype KResponseScheme KResponseScheme :: Set ValName -> KResponseScheme rscVals :: KResponseScheme -> Set ValName methodRespScheme :: Method a b -> KResponseScheme instance Show KQueryScheme instance Read KQueryScheme instance Eq KQueryScheme instance Ord KQueryScheme instance Show KResponseScheme instance Read KResponseScheme instance Eq KResponseScheme instance Ord KResponseScheme instance KMessage KResponse KResponseScheme instance KMessage KQuery KQueryScheme instance KMessage KError ErrorCode