courier 0.1.1.1 → 0.1.1.2
raw patch · 5 files changed
+90/−20 lines, 5 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Control.Concurrent.Mailbox: instance Eq (Mailbox m)
- Network.Endpoints: boundEndpointNames :: Endpoint -> TVar (Set Name)
- Network.Endpoints: endpointInbound :: Endpoint -> Mailbox Message
- Network.Endpoints: endpointOutbound :: Endpoint -> Mailbox Envelope
- Network.Endpoints: envelopeMessage :: Envelope -> Message
- Network.Endpoints: instance Constructor C1_0Name
- Network.Endpoints: instance Datatype D1Name
- Network.Endpoints: instance Eq Envelope
- Network.Endpoints: instance Eq Name
- Network.Endpoints: instance Exception BindException
- Network.Endpoints: instance Generic Name
- Network.Endpoints: instance Ord Name
- Network.Endpoints: instance Serialize Name
- Network.Endpoints: instance Show BindException
- Network.Endpoints: instance Show Envelope
- Network.Endpoints: instance Show Name
- Network.Endpoints: instance Typeable BindException
- Network.Endpoints: messageDestination :: Envelope -> Name
- Network.Endpoints: messageOrigin :: Envelope -> Maybe Name
- Network.RPC: instance Constructor C1_0RPCMessageType
- Network.RPC: instance Constructor C1_0RequestId
- Network.RPC: instance Constructor C1_1RPCMessageType
- Network.RPC: instance Datatype D1RPCMessageType
- Network.RPC: instance Datatype D1RequestId
- Network.RPC: instance Enum RPCMessageType
- Network.RPC: instance Eq RPCMessageType
- Network.RPC: instance Eq Request
- Network.RPC: instance Eq RequestId
- Network.RPC: instance Eq Response
- Network.RPC: instance Generic RPCMessageType
- Network.RPC: instance Generic RequestId
- Network.RPC: instance Serialize RPCMessageType
- Network.RPC: instance Serialize Request
- Network.RPC: instance Serialize RequestId
- Network.RPC: instance Serialize Response
- Network.RPC: instance Show RPCMessageType
- Network.RPC: instance Show Request
- Network.RPC: instance Show RequestId
- Network.RPC: instance Show Response
- Network.RPC: requestArgs :: Request -> Message
- Network.RPC: requestCaller :: Request -> Name
- Network.RPC: requestId :: Request -> RequestId
- Network.RPC: requestMethod :: Request -> Method
- Network.RPC: responseFrom :: Response -> Name
- Network.RPC: responseId :: Response -> RequestId
- Network.RPC: responseValue :: Response -> Message
- Network.Transport: bind :: Transport -> Endpoint -> Name -> IO Binding
- Network.Transport: bindingName :: Binding -> Name
- Network.Transport: connect :: Transport -> Endpoint -> Name -> IO Connection
- Network.Transport: disconnect :: Connection -> IO ()
- Network.Transport: dispatch :: Transport -> Endpoint -> IO Dispatcher
- Network.Transport: instance Exception TransportException
- Network.Transport: instance Show TransportException
- Network.Transport: instance Typeable TransportException
- Network.Transport: shutdown :: Transport -> IO ()
- Network.Transport: stop :: Dispatcher -> IO ()
- Network.Transport: unbind :: Binding -> IO ()
- Network.Transport.Sockets: connectionDestination :: SocketConnection -> TMVar Name
- Network.Transport.Sockets: disconnectSocket :: SocketConnection -> IO ()
- Network.Transport.Sockets: instance Constructor C1_0SocketMessage
- Network.Transport.Sockets: instance Constructor C1_1SocketMessage
- Network.Transport.Sockets: instance Datatype D1SocketMessage
- Network.Transport.Sockets: instance Exception ResolverException
- Network.Transport.Sockets: instance Generic SocketMessage
- Network.Transport.Sockets: instance Serialize SocketMessage
- Network.Transport.Sockets: instance Show ResolverException
- Network.Transport.Sockets: instance Typeable ResolverException
- Network.Transport.Sockets: receiveSocketMessage :: SocketConnection -> IO Message
- Network.Transport.Sockets: sendSocketMessage :: SocketConnection -> Message -> IO ()
+ Control.Concurrent.Mailbox: instance GHC.Classes.Eq (Control.Concurrent.Mailbox.Mailbox m)
+ Network.Endpoints: [boundEndpointNames] :: Endpoint -> TVar (Set Name)
+ Network.Endpoints: [endpointInbound] :: Endpoint -> Mailbox Message
+ Network.Endpoints: [endpointOutbound] :: Endpoint -> Mailbox Envelope
+ Network.Endpoints: [envelopeMessage] :: Envelope -> Message
+ Network.Endpoints: [messageDestination] :: Envelope -> Name
+ Network.Endpoints: [messageOrigin] :: Envelope -> Maybe Name
+ Network.Endpoints: instance Data.Serialize.Serialize Network.Endpoints.Name
+ Network.Endpoints: instance GHC.Classes.Eq Network.Endpoints.Envelope
+ Network.Endpoints: instance GHC.Classes.Eq Network.Endpoints.Name
+ Network.Endpoints: instance GHC.Classes.Ord Network.Endpoints.Name
+ Network.Endpoints: instance GHC.Exception.Exception Network.Endpoints.BindException
+ Network.Endpoints: instance GHC.Generics.Constructor Network.Endpoints.C1_0Name
+ Network.Endpoints: instance GHC.Generics.Datatype Network.Endpoints.D1Name
+ Network.Endpoints: instance GHC.Generics.Generic Network.Endpoints.Name
+ Network.Endpoints: instance GHC.Show.Show Network.Endpoints.BindException
+ Network.Endpoints: instance GHC.Show.Show Network.Endpoints.Envelope
+ Network.Endpoints: instance GHC.Show.Show Network.Endpoints.Name
+ Network.RPC: [requestArgs] :: Request -> Message
+ Network.RPC: [requestCaller] :: Request -> Name
+ Network.RPC: [requestId] :: Request -> RequestId
+ Network.RPC: [requestMethod] :: Request -> Method
+ Network.RPC: [responseFrom] :: Response -> Name
+ Network.RPC: [responseId] :: Response -> RequestId
+ Network.RPC: [responseValue] :: Response -> Message
+ Network.RPC: handleAll :: Endpoint -> Name -> (Method -> Message -> IO Message) -> IO HandleSite
+ Network.RPC: hearAll :: Endpoint -> Name -> IO (Method, Message, Reply Message)
+ Network.RPC: hearAllTimeout :: Endpoint -> Name -> Int -> IO (Maybe (Method, Message, Reply Message))
+ Network.RPC: instance Data.Serialize.Serialize Network.RPC.RPCMessageType
+ Network.RPC: instance Data.Serialize.Serialize Network.RPC.Request
+ Network.RPC: instance Data.Serialize.Serialize Network.RPC.RequestId
+ Network.RPC: instance Data.Serialize.Serialize Network.RPC.Response
+ Network.RPC: instance GHC.Classes.Eq Network.RPC.RPCMessageType
+ Network.RPC: instance GHC.Classes.Eq Network.RPC.Request
+ Network.RPC: instance GHC.Classes.Eq Network.RPC.RequestId
+ Network.RPC: instance GHC.Classes.Eq Network.RPC.Response
+ Network.RPC: instance GHC.Enum.Enum Network.RPC.RPCMessageType
+ Network.RPC: instance GHC.Generics.Constructor Network.RPC.C1_0RPCMessageType
+ Network.RPC: instance GHC.Generics.Constructor Network.RPC.C1_0RequestId
+ Network.RPC: instance GHC.Generics.Constructor Network.RPC.C1_1RPCMessageType
+ Network.RPC: instance GHC.Generics.Datatype Network.RPC.D1RPCMessageType
+ Network.RPC: instance GHC.Generics.Datatype Network.RPC.D1RequestId
+ Network.RPC: instance GHC.Generics.Generic Network.RPC.RPCMessageType
+ Network.RPC: instance GHC.Generics.Generic Network.RPC.RequestId
+ Network.RPC: instance GHC.Show.Show Network.RPC.RPCMessageType
+ Network.RPC: instance GHC.Show.Show Network.RPC.Request
+ Network.RPC: instance GHC.Show.Show Network.RPC.RequestId
+ Network.RPC: instance GHC.Show.Show Network.RPC.Response
+ Network.Transport: [bind] :: Transport -> Endpoint -> Name -> IO Binding
+ Network.Transport: [bindingName] :: Binding -> Name
+ Network.Transport: [connect] :: Transport -> Endpoint -> Name -> IO Connection
+ Network.Transport: [disconnect] :: Connection -> IO ()
+ Network.Transport: [dispatch] :: Transport -> Endpoint -> IO Dispatcher
+ Network.Transport: [shutdown] :: Transport -> IO ()
+ Network.Transport: [stop] :: Dispatcher -> IO ()
+ Network.Transport: [unbind] :: Binding -> IO ()
+ Network.Transport: instance GHC.Exception.Exception Network.Transport.TransportException
+ Network.Transport: instance GHC.Show.Show Network.Transport.TransportException
+ Network.Transport: withCompleteNetwork :: Transport -> [Name] -> Endpoint -> Name -> IO () -> IO ()
+ Network.Transport: withConnections :: Transport -> Endpoint -> [Name] -> IO () -> IO ()
+ Network.Transport.Sockets: [connectionDestination] :: SocketConnection -> TMVar Name
+ Network.Transport.Sockets: [disconnectSocket] :: SocketConnection -> IO ()
+ Network.Transport.Sockets: [receiveSocketMessage] :: SocketConnection -> IO Message
+ Network.Transport.Sockets: [sendSocketMessage] :: SocketConnection -> Message -> IO ()
+ Network.Transport.Sockets: instance Data.Serialize.Serialize Network.Transport.Sockets.SocketMessage
+ Network.Transport.Sockets: instance GHC.Exception.Exception Network.Transport.Sockets.ResolverException
+ Network.Transport.Sockets: instance GHC.Generics.Constructor Network.Transport.Sockets.C1_0SocketMessage
+ Network.Transport.Sockets: instance GHC.Generics.Constructor Network.Transport.Sockets.C1_1SocketMessage
+ Network.Transport.Sockets: instance GHC.Generics.Datatype Network.Transport.Sockets.D1SocketMessage
+ Network.Transport.Sockets: instance GHC.Generics.Generic Network.Transport.Sockets.SocketMessage
+ Network.Transport.Sockets: instance GHC.Show.Show Network.Transport.Sockets.ResolverException
Files
- changes.md +5/−0
- courier.cabal +1/−1
- src/Network/RPC.hs +52/−2
- src/Network/Transport.hs +26/−12
- src/Network/Transport/Sockets/TCP.hs +6/−5
changes.md view
@@ -1,3 +1,8 @@+0.1.1.2++ * Updated README with better working example+ * Removed warning about TCP/IP transport; it's working again+ 0.1.1.1 There are significant changes in this release, due to a complete rewrite of TCP connection handling, and,
courier.cabal view
@@ -1,5 +1,5 @@ name: courier-version: 0.1.1.1+version: 0.1.1.2 synopsis: A message-passing library for simplifying network applications description: Inspired by Erlang's simple message-passing facilities, courier provides roughly similar capabilities. Applications simply create one or more endpoints,
src/Network/RPC.hs view
@@ -47,10 +47,13 @@ methodSelector, hear, hearTimeout,+ hearAll,+ hearAllTimeout, Reply, HandleSite, handle,+ handleAll, hangup, Request(..),@@ -326,6 +329,12 @@ then Just (caller,rid,args) else Nothing +anySelector :: Message -> Maybe (Name,RequestId,Method,Message)+anySelector msg =+ case decode msg of+ Left _ -> Nothing+ Right (Request rid caller method args) -> Just (caller,rid,method,args)+ {-| Wait for a single incoming request to invoke the indicated 'Method' on the specified 'Endpoint'. Return both the method arguments and a 'Reply' function useful for sending@@ -345,7 +354,6 @@ reply caller rid result = do sendMessage endpoint caller $ encode $ Response rid name result - {-| Same as 'hear', except return 'Nothing' if no request received within the specified timeout (measured in microseconds), or return a 'Just' instance containing both the@@ -362,6 +370,34 @@ sendMessage endpoint caller $ encode $ Response rid name result {-|+A variant of 'hear', except it listens for any incoming RPC request on the specified 'Endpoint'.+-}+hearAll :: Endpoint -> Name -> IO (Method,Message,Reply Message)+hearAll endpoint name = do+ (caller,rid,method,args) <- selectMessage endpoint anySelector+ return (method,args,reply caller rid)+ where+ reply caller rid result =+ sendMessage endpoint caller $ encode $ Response rid name result+ anySelector msg =+ case decode msg of+ Left _ -> Nothing+ Right (Request rid caller method args) -> Just (caller,rid,method,args)++{-|+A variant of 'hearTimeout', except it listens for any incoming RPC request on the specified 'Endpoint'+-}+hearAllTimeout :: Endpoint -> Name -> Int -> IO (Maybe (Method,Message,Reply Message))+hearAllTimeout endpoint name timeout = do+ req <- selectMessageTimeout endpoint timeout anySelector+ case req of+ Just (caller,rid,method,args) -> return $ Just (method,args, reply caller rid)+ Nothing -> return Nothing+ where+ reply caller rid result = do+ sendMessage endpoint caller $ encode $ Response rid name result++{-| A 'HandleSite' is a just reference to the actual handler of a specific method. Mostly for invoking 'hangup' on the handler, once it is no longer needed. -}@@ -373,12 +409,26 @@ -} handle :: Endpoint -> Name -> Method -> (Message -> IO Message) -> IO HandleSite handle endpoint name method fn = do- task <- async $ handleCall+ task <- async handleCall return $ HandleSite name task where handleCall = do (args,reply) <- hear endpoint name method result <- fn args+ reply result+ handleCall++{-|+Handle all RPCs on the specified 'Endpoint' until 'hangup' is called on the returned 'HandleSite'+-}+handleAll :: Endpoint -> Name -> (Method -> Message -> IO Message) -> IO HandleSite+handleAll endpoint name fn = do+ task <- async handleCall+ return $ HandleSite name task+ where+ handleCall = do+ (method,args,reply) <- hearAll endpoint name+ result <- fn method args reply result handleCall
src/Network/Transport.hs view
@@ -69,6 +69,9 @@ withConnection3, withConnection4, + withConnections,+ withCompleteNetwork+ ) where -- local imports@@ -264,25 +267,36 @@ A helper for ensuring that 2 'Connection's are maintained during execution of a function. -} withConnection2 :: Transport -> Endpoint -> Name -> Name -> IO () -> IO ()-withConnection2 transport endpoint name1 name2 fn =- withConnection transport endpoint name1 $- withConnection transport endpoint name2 fn+withConnection2 transport endpoint name1 name2 = withConnections transport endpoint [name1,name2] {-| A helper for ensuring that 3 'Connection's are maintained during execution of a function. -} withConnection3 :: Transport -> Endpoint -> Name -> Name -> Name -> IO () -> IO ()-withConnection3 transport endpoint name1 name2 name3 fn =- withConnection transport endpoint name1 $- withConnection transport endpoint name2 $- withConnection transport endpoint name3 fn+withConnection3 transport endpoint name1 name2 name3 = withConnections transport endpoint [name1,name2,name3] {-| A helper for ensuring that 4 'Connection's are maintained during execution of a function. -} withConnection4 :: Transport -> Endpoint -> Name -> Name -> Name -> Name -> IO () -> IO ()-withConnection4 transport endpoint name1 name2 name3 name4 fn =- withConnection transport endpoint name1 $- withConnection transport endpoint name2 $- withConnection transport endpoint name3 $- withConnection transport endpoint name4 fn+withConnection4 transport endpoint name1 name2 name3 name4 = withConnections transport endpoint [name1,name2,name3,name4]++--+-- Various helpers+--+withConnections :: Transport -> Endpoint -> [Name] -> IO () -> IO ()+withConnections _ _ [] fn = fn+withConnections transport endpoint (destination:destinations) fn =+ withConnection transport endpoint destination $+ withConnections transport endpoint destinations fn++{-|+This is a helper designed to create a complete network, where there are+enough connections to ensure every endpoint has a connection to every other endpoint.+-}+withCompleteNetwork :: Transport -> [Name] -> Endpoint -> Name -> IO () -> IO ()+withCompleteNetwork _ [] _ _ fn = fn+withCompleteNetwork transport(destination:destinations) endpoint origin fn =+ if destination == origin+ then withConnections transport endpoint destinations fn+ else withCompleteNetwork transport destinations endpoint origin fn
src/Network/Transport/Sockets/TCP.hs view
@@ -51,7 +51,7 @@ vPeers <- newTVar M.empty mailboxes <- newTVar M.empty return Transport {- bind = tcpBind mailboxes family resolver,+ bind = tcpBind mailboxes family resolver vPeers, dispatch = dispatcher mailboxes, connect = socketConnect mailboxes $ tcpConnect family resolver, shutdown = tcpShutdown vPeers@@ -81,9 +81,8 @@ tcpSocketResolver6 :: Name -> IO [NS.SockAddr] tcpSocketResolver6 = socketResolver6 NS.Stream -tcpBind :: Mailboxes -> NS.Family -> Resolver -> Endpoint -> Name -> IO Binding-tcpBind mailboxes family resolver endpoint name = do- vConnections <- atomically $ newTVar M.empty+tcpBind :: Mailboxes -> NS.Family -> Resolver -> SocketConnections -> Endpoint -> Name -> IO Binding+tcpBind mailboxes family resolver vConnections endpoint name = do listener <- async $ tcpListen mailboxes family resolver vConnections endpoint name return Binding { bindingName = name,@@ -102,7 +101,9 @@ connection <- tcpConnection peer msngr <- async $ messenger mailboxes endpoint connection let conn = Connection {- disconnect = cancel msngr+ disconnect = do+ atomically $ modifyTVar vConnections $ M.delete peerAddress+ cancel msngr } maybeOldConn <- atomically $ do connections <- readTVar vConnections