Safe Haskell | Safe-Inferred |
---|---|
Language | Haskell2010 |
Network.TypedProtocol.Driver
Synopsis
- data Driver ps dstate m = Driver {
- sendMessage :: forall (pr :: PeerRole) (st :: ps) (st' :: ps). PeerHasAgency pr st -> Message ps st st' -> m ()
- recvMessage :: forall (pr :: PeerRole) (st :: ps). PeerHasAgency pr st -> dstate -> m (SomeMessage st, dstate)
- startDState :: dstate
- data SomeMessage (st :: ps) where
- SomeMessage :: Message ps st st' -> SomeMessage st
- runPeerWithDriver :: forall ps (st :: ps) pr dstate m a. Monad m => Driver ps dstate m -> Peer ps pr st m a -> dstate -> m (a, dstate)
- runPipelinedPeerWithDriver :: forall ps (st :: ps) pr dstate m a. MonadAsync m => Driver ps dstate m -> PeerPipelined ps pr st m a -> dstate -> m (a, dstate)
Introduction
A Peer
is a particular implementation of an agent that engages in a
typed protocol. To actually run one we need a source and sink for the typed
protocol messages. These are provided by a Channel
and a Codec
. The
Channel
represents one end of an untyped duplex message transport, and
the Codec
handles conversion between the typed protocol messages and
the untyped channel.
So given the Peer
and a compatible Codec
and Channel
we can run the
peer in some appropriate monad. The peer and codec have to agree on
the same protocol and role in that protocol. The codec and channel have to
agree on the same untyped medium, e.g. text or bytes. All three have to
agree on the same monad in which they will run.
This module provides drivers for normal and pipelined peers. There is very little policy involved here so typically it should be possible to use these drivers, and customise things by adjusting the peer, or codec or channel.
It is of course possible to write custom drivers and the code for these ones
may provide a useful starting point. The runDecoder
function may be a
helpful utility for use in custom drives.
data Driver ps dstate m Source #
Constructors
Driver | |
Fields
|
data SomeMessage (st :: ps) where Source #
When decoding a Message
we only know the expected "from" state. We
cannot know the "to" state as this depends on the message we decode. To
resolve this we use the SomeMessage
wrapper which uses an existential
type to hide the "to" state.
Constructors
SomeMessage :: Message ps st st' -> SomeMessage st |
Normal peers
runPeerWithDriver :: forall ps (st :: ps) pr dstate m a. Monad m => Driver ps dstate m -> Peer ps pr st m a -> dstate -> m (a, dstate) Source #
Run a peer with the given driver.
This runs the peer to completion (if the protocol allows for termination).
Pipelined peers
runPipelinedPeerWithDriver :: forall ps (st :: ps) pr dstate m a. MonadAsync m => Driver ps dstate m -> PeerPipelined ps pr st m a -> dstate -> m (a, dstate) Source #
Run a pipelined peer with the given driver.
This runs the peer to completion (if the protocol allows for termination).
Unlike normal peers, running pipelined peers rely on concurrency, hence the
MonadAsync
constraint.