-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | KRPC remote procedure call protocol implementation. -- -- KRPC remote procedure call protocol implementation. -- --
-- 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:
--
-- -- 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: -- --
-- 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