typed-protocols-examples
Safe HaskellNone
LanguageHaskell2010

Network.TypedProtocol.Driver.Simple

Description

Drivers for running Peers with a Codec and a Channel.

Synopsis

Introduction

A Peer is a particular implementation of an agent that engages in a typed protocol. To actualy 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.

runPeer :: forall ps (st :: ps) (pr :: PeerRole) failure bytes m a. (MonadThrow m, Exception failure) => Tracer m (TraceSendRecv ps) -> Codec ps failure m bytes -> Channel m bytes -> Peer ps pr 'NonPipelined st m a -> m (a, Maybe bytes) Source #

Run a peer with the given channel via the given codec.

This runs the peer to completion (if the protocol allows for termination).

data TraceSendRecv ps where Source #

Structured Tracer output for runPeer and derivitives.

Constructors

TraceSendMsg :: forall ps. AnyMessage ps -> TraceSendRecv ps 
TraceRecvMsg :: forall ps. AnyMessage ps -> TraceSendRecv ps 

Instances

Instances details
Show (AnyMessage ps) => Show (TraceSendRecv ps) Source # 
Instance details

Defined in Network.TypedProtocol.Driver.Simple

data Role Source #

Constructors

Client 
Server 

Instances

Instances details
Show Role Source # 
Instance details

Defined in Network.TypedProtocol.Driver.Simple

Methods

showsPrec :: Int -> Role -> ShowS #

show :: Role -> String #

showList :: [Role] -> ShowS #

Pipelined peers

runPipelinedPeer :: forall ps (st :: ps) (pr :: PeerRole) failure bytes m a. (MonadAsync m, MonadThrow m, Exception failure) => Tracer m (TraceSendRecv ps) -> Codec ps failure m bytes -> Channel m bytes -> PeerPipelined ps pr st m a -> m (a, Maybe bytes) Source #

Run a pipelined peer with the given channel via the given codec.

This runs the peer to completion (if the protocol allows for termination).

Unlike normal peers, running pipelined peers rely on concurrency, hence the MonadSTM constraint.

Connected peers

runConnectedPeers :: forall m failure bytes ps (pr :: PeerRole) (st :: ps) a b. (MonadAsync m, MonadCatch m, Exception failure) => m (Channel m bytes, Channel m bytes) -> Tracer m (Role, TraceSendRecv ps) -> Codec ps failure m bytes -> Peer ps pr 'NonPipelined st m a -> Peer ps (FlipAgency pr) 'NonPipelined st m b -> m (a, b) Source #

Run two Peers via a pair of connected Channels and a common Codec.

This is useful for tests and quick experiments.

The first argument is expected to create two channels that are connected, for example createConnectedChannels.

runConnectedPeersPipelined :: forall m failure bytes ps (pr :: PeerRole) (st :: ps) a b. (MonadAsync m, MonadCatch m, Exception failure) => m (Channel m bytes, Channel m bytes) -> Tracer m (PeerRole, TraceSendRecv ps) -> Codec ps failure m bytes -> PeerPipelined ps pr st m a -> Peer ps (FlipAgency pr) 'NonPipelined st m b -> m (a, b) Source #

runConnectedPeersAsymmetric :: forall m failure bytes ps (pr :: PeerRole) (st :: ps) a b. (MonadAsync m, MonadMask m, Exception failure) => m (Channel m bytes, Channel m bytes) -> Tracer m (Role, TraceSendRecv ps) -> Codec ps failure m bytes -> Codec ps failure m bytes -> PeerPipelined ps pr st m a -> Peer ps (FlipAgency pr) 'NonPipelined st m b -> m (a, b) Source #

Driver utilities

This may be useful if you want to write your own driver.

driverSimple :: forall ps (pr :: PeerRole) failure bytes (m :: Type -> Type). (MonadThrow m, Exception failure) => Tracer m (TraceSendRecv ps) -> Codec ps failure m bytes -> Channel m bytes -> Driver ps pr (Maybe bytes) m Source #

runDecoderWithChannel :: Monad m => Channel m bytes -> Maybe bytes -> DecodeStep bytes failure m a -> m (Either failure (a, Maybe bytes)) Source #

Run a codec incremental decoder DecodeStep against a channel. It also takes any extra input data and returns any unused trailing data.