websockets-0.13.0.0: A sensible and clean way to write WebSocket-capable servers in Haskell.

Safe Haskell | None
Language | Haskell2010

Network.WebSockets

Contents

- Incoming connections and handshaking
- Main connection type
- Options for connections
  - Compression options
  - Protection limits
- Sending and receiving messages
- HTTP Types
- WebSocket message types
- Exceptions
- Running a standalone server
- Utilities for writing your own server
- Running a client
- Utilities

Synopsis

- data PendingConnection
- pendingRequest :: PendingConnection -> RequestHead
- acceptRequest :: PendingConnection -> IO Connection
- data AcceptRequest = AcceptRequest {
  - acceptSubprotocol :: !(Maybe ByteString)
  - acceptHeaders :: !Headers
  }
- defaultAcceptRequest :: AcceptRequest
- acceptRequestWith :: PendingConnection -> AcceptRequest -> IO Connection
- rejectRequest :: PendingConnection -> ByteString -> IO ()
- data RejectRequest = RejectRequest {
  - rejectCode :: !Int
  - rejectMessage :: !ByteString
  - rejectHeaders :: Headers
  - rejectBody :: !ByteString
  }
- defaultRejectRequest :: RejectRequest
- rejectRequestWith :: PendingConnection -> RejectRequest -> IO ()
- data Connection
- data ConnectionOptions = ConnectionOptions {
  - connectionOnPong :: !(IO ())
  - connectionTimeout :: !Int
  - connectionCompressionOptions :: !CompressionOptions
  - connectionStrictUnicode :: !Bool
  - connectionFramePayloadSizeLimit :: !SizeLimit
  - connectionMessageDataSizeLimit :: !SizeLimit
  }
- defaultConnectionOptions :: ConnectionOptions
- data CompressionOptions
  - = NoCompression
  - | PermessageDeflateCompression PermessageDeflate
- data PermessageDeflate = PermessageDeflate {
  - serverNoContextTakeover :: Bool
  - clientNoContextTakeover :: Bool
  - serverMaxWindowBits :: Int
  - clientMaxWindowBits :: Int
  - pdCompressionLevel :: Int
  }
- defaultPermessageDeflate :: PermessageDeflate
- data SizeLimit
  - = NoSizeLimit
  - | SizeLimit !Int64
- receive :: Connection -> IO Message
- receiveDataMessage :: Connection -> IO DataMessage
- receiveData :: WebSocketsData a => Connection -> IO a
- send :: Connection -> Message -> IO ()
- sendDataMessage :: Connection -> DataMessage -> IO ()
- sendDataMessages :: Connection -> [DataMessage] -> IO ()
- sendTextData :: WebSocketsData a => Connection -> a -> IO ()
- sendTextDatas :: WebSocketsData a => Connection -> [a] -> IO ()
- sendBinaryData :: WebSocketsData a => Connection -> a -> IO ()
- sendBinaryDatas :: WebSocketsData a => Connection -> [a] -> IO ()
- sendClose :: WebSocketsData a => Connection -> a -> IO ()
- sendCloseCode :: WebSocketsData a => Connection -> Word16 -> a -> IO ()
- sendPing :: WebSocketsData a => Connection -> a -> IO ()
- type Headers = [(CI ByteString, ByteString)]
- data Request = Request RequestHead ByteString
- data RequestHead = RequestHead {
  - requestPath :: !ByteString
  - requestHeaders :: Headers
  - requestSecure :: Bool
  }
- getRequestSubprotocols :: RequestHead -> [ByteString]
- data Response = Response ResponseHead ByteString
- data ResponseHead = ResponseHead {
  - responseCode :: !Int
  - responseMessage :: !ByteString
  - responseHeaders :: Headers
  }
- data Message
  - = ControlMessage ControlMessage
  - | DataMessage Bool Bool Bool DataMessage
- data ControlMessage
  - = Close Word16 ByteString
  - | Ping ByteString
  - | Pong ByteString
- data DataMessage
  - = Text ByteString (Maybe Text)
  - | Binary ByteString
- class WebSocketsData a where
  - fromDataMessage :: DataMessage -> a
  - fromLazyByteString :: ByteString -> a
  - toLazyByteString :: a -> ByteString
- data HandshakeException
  - = NotSupported
  - | MalformedRequest RequestHead String
  - | MalformedResponse ResponseHead String
  - | RequestRejected RequestHead ResponseHead
  - | ConnectionTimeout
  - | OtherHandshakeException String
- data ConnectionException
  - = CloseRequest Word16 ByteString
  - | ConnectionClosed
  - | ParseException String
  - | UnicodeException String
- type ServerApp = PendingConnection -> IO ()
- runServer :: String -> Int -> ServerApp -> IO ()
- runServerWith :: String -> Int -> ConnectionOptions -> ServerApp -> IO ()
- data ServerOptions = ServerOptions {
  - serverHost :: String
  - serverPort :: Int
  - serverConnectionOptions :: ConnectionOptions
  }
- defaultServerOptions :: ServerOptions
- runServerWithOptions :: ServerOptions -> ServerApp -> IO a
- makeListenSocket :: String -> Int -> IO Socket
- makePendingConnection :: Socket -> ConnectionOptions -> IO PendingConnection
- makePendingConnectionFromStream :: Stream -> ConnectionOptions -> IO PendingConnection
- type ClientApp a = Connection -> IO a
- runClient :: String -> Int -> String -> ClientApp a -> IO a
- runClientWith :: String -> Int -> String -> ConnectionOptions -> Headers -> ClientApp a -> IO a
- runClientWithSocket :: Socket -> String -> String -> ConnectionOptions -> Headers -> ClientApp a -> IO a
- runClientWithStream :: Stream -> String -> String -> ConnectionOptions -> Headers -> ClientApp a -> IO a
- newClientConnection :: Stream -> String -> String -> ConnectionOptions -> Headers -> IO Connection
- data PingPongOptions = PingPongOptions {
  - pingInterval :: Int
  - pongTimeout :: Int
  - pingAction :: IO ()
  }
- defaultPingPongOptions :: PingPongOptions
- withPingPong :: PingPongOptions -> Connection -> (Connection -> IO ()) -> IO ()
- withPingThread :: Connection -> Int -> IO () -> IO a -> IO a
- forkPingThread :: Connection -> Int -> IO ()

# Incoming connections and handshaking

data PendingConnection #

A new client connected to the server. We haven't accepted the connection yet, though.

pendingRequest :: PendingConnection -> RequestHead #

Useful for e.g. inspecting the request path.

acceptRequest :: PendingConnection -> IO Connection #

Accept a pending connection, turning it into a `Connection`.

data AcceptRequest #

This datatype allows you to set options for `acceptRequestWith`. It is strongly recommended to use `defaultAcceptRequest` and then modify the various fields, that way new fields introduced in the library do not break your code.

Constructors

AcceptRequest |

Fields

- acceptSubprotocol :: !(Maybe ByteString)

  The subprotocol to speak with the client. If `pendingSubprotcols` is non-empty, `acceptSubprotocol` must be one of the subprotocols from the list.

- acceptHeaders :: !Headers

  Extra headers to send with the response.

defaultAcceptRequest :: AcceptRequest #

acceptRequestWith :: PendingConnection -> AcceptRequest -> IO Connection #

This function is like `acceptRequest` but allows you to set custom options using the `AcceptRequest` datatype.

rejectRequest #

Arguments

:: PendingConnection | Connection to reject
-> ByteString | Rejection response body
-> IO () |

Requires calling `pendingStream` and `close`.

data RejectRequest #

Parameters that allow you to tweak how a request is rejected. Please use `defaultRejectRequest` and modify fields using record syntax so your code will not break when new fields are added.

Constructors

RejectRequest |

Fields

- rejectCode :: !Int

  The status code, 400 by default.

- rejectMessage :: !ByteString

  The message, "Bad Request" by default

- rejectHeaders :: Headers

  Extra headers to be sent with the response.

- rejectBody :: !ByteString

  Reponse body of the rejection.

defaultRejectRequest :: RejectRequest #

rejectRequestWith #

Arguments

:: PendingConnection | Connection to reject
-> RejectRequest | Params on how to reject the request
-> IO () |

# Main connection type

data Connection #

# Options for connections

data ConnectionOptions #

Set options for a `Connection`. Please do not use this constructor directly, but rather use `defaultConnectionOptions` and then set the fields you want, e.g.:

    myOptions = defaultConnectionOptions {connectionStrictUnicode = True}

This way your code does not break if the library introduces new fields.

Constructors

ConnectionOptions |

Fields

- connectionOnPong :: !(IO ())

  Whenever a `pong` is received, this IO action is executed. It can be used to tickle connections or fire missiles.

- connectionTimeout :: !Int

  Timeout for connection establishment in seconds. Only used in the client.

- connectionCompressionOptions :: !CompressionOptions

  Enable `PermessageDeflate`.

- connectionStrictUnicode :: !Bool

  Enable strict unicode on the connection. This means that if a client (or server) sends invalid UTF-8, we will throw a `UnicodeException` rather than replacing it by the unicode replacement character U+FFFD.

- connectionFramePayloadSizeLimit :: !SizeLimit

  The maximum size for incoming frame payload size in bytes. If a frame exceeds this limit, a `ParseException` is thrown.

- connectionMessageDataSizeLimit :: !SizeLimit

  `connectionFrameSizeLimit` is often not enough since a malicious client can send many small frames to create a huge message. This limit allows you to protect from that. If a message exceeds this limit, a `ParseException` is thrown.

  Note that, if compression is enabled, we check the size of the compressed messages, as well as the size of the uncompressed messages as we are deflating them to ensure we don't use too much memory in any case.

defaultConnectionOptions :: ConnectionOptions #

The default connection options:

- Nothing happens when a pong is received.
- Compression is disabled.
- Lenient unicode decoding.
- 30 second timeout for connection establishment.

## Compression options

data CompressionOptions #

Constructors

NoCompression |
PermessageDeflateCompression PermessageDeflate |

#### Instances

Instances details

Show CompressionOptions # |
Instance details Defined in Network.WebSockets.Connection.Options Methods showsPrec :: Int -> CompressionOptions -> ShowS # show :: CompressionOptions -> String # showList :: [CompressionOptions] -> ShowS #
Eq CompressionOptions # |
Instance details Defined in Network.WebSockets.Connection.Options Methods (==) :: CompressionOptions -> CompressionOptions -> Bool # (/=) :: CompressionOptions -> CompressionOptions -> Bool #

data PermessageDeflate #

Four extension parameters are defined for "permessage-deflate" to help endpoints manage per-connection resource usage.

- "server_no_context_takeover"
- "client_no_context_takeover"
- "server_max_window_bits"
- "client_max_window_bits"

Constructors

PermessageDeflate |

Fields

- serverNoContextTakeover :: Bool
- clientNoContextTakeover :: Bool
- serverMaxWindowBits :: Int
- clientMaxWindowBits :: Int
- pdCompressionLevel :: Int

#### Instances

Instances details

Show PermessageDeflate # |
Instance details Defined in Network.WebSockets.Connection.Options Methods showsPrec :: Int -> PermessageDeflate -> ShowS # show :: PermessageDeflate -> String # showList :: [PermessageDeflate] -> ShowS #
Eq PermessageDeflate # |
Instance details Defined in Network.WebSockets.Connection.Options Methods (==) :: PermessageDeflate -> PermessageDeflate -> Bool # (/=) :: PermessageDeflate -> PermessageDeflate -> Bool #

defaultPermessageDeflate :: PermessageDeflate #

## Protection limits

data SizeLimit #

A size limit, in bytes. The `Monoid` instance takes the minimum limit.

Constructors

NoSizeLimit |
SizeLimit !Int64 |

#### Instances

Instances details

Monoid SizeLimit # |
Instance details Defined in Network.WebSockets.Connection.Options Methods mempty :: SizeLimit # mappend :: SizeLimit -> SizeLimit -> SizeLimit # mconcat :: [SizeLimit] -> SizeLimit #
Semigroup SizeLimit # |
Instance details Defined in Network.WebSockets.Connection.Options Methods (<>) :: SizeLimit -> SizeLimit -> SizeLimit # sconcat :: NonEmpty SizeLimit -> SizeLimit # stimes :: Integral b => b -> SizeLimit -> SizeLimit #
Show SizeLimit # |
Instance details Defined in Network.WebSockets.Connection.Options Methods showsPrec :: Int -> SizeLimit -> ShowS # show :: SizeLimit -> String # showList :: [SizeLimit] -> ShowS #
Eq SizeLimit # |
Instance details Defined in Network.WebSockets.Connection.Options Methods (==) :: SizeLimit -> SizeLimit -> Bool # (/=) :: SizeLimit -> SizeLimit -> Bool #

# Sending and receiving messages

receive :: Connection -> IO Message #

receiveDataMessage :: Connection -> IO DataMessage #

Receive an application message. Automatically respond to control messages.

When the peer sends a close control message, an exception of type `CloseRequest` is thrown. The peer can send a close control message either to initiate a close or in response to a close message we have sent to the peer. In either case the `CloseRequest` exception will be thrown. The RFC specifies that the server is responsible for closing the TCP connection, which should happen after receiving the `CloseRequest` exception from this function.

This will throw `ConnectionClosed` if the TCP connection dies unexpectedly.

receiveData :: WebSocketsData a => Connection -> IO a #

Receive a message, converting it to whatever format is needed.

send :: Connection -> Message -> IO () #

sendDataMessage :: Connection -> DataMessage -> IO () #

Send a `DataMessage`. This allows you send both human-readable text and binary data. This is a slightly more low-level interface than `sendTextData` or `sendBinaryData`.

sendDataMessages :: Connection -> [DataMessage] -> IO () #

Send a collection of `DataMessage`s. This is more efficient than calling `sendDataMessage` many times.

sendTextData :: WebSocketsData a => Connection -> a -> IO () #

Send a textual message. The message will be encoded as UTF-8. This should be the default choice for human-readable text-based protocols such as JSON.

sendTextDatas :: WebSocketsData a => Connection -> [a] -> IO () #

Send a number of textual messages. This is more efficient than calling `sendTextData` many times.

sendBinaryData :: WebSocketsData a => Connection -> a -> IO () #

Send a binary message. This is useful for sending binary blobs, e.g. images, data encoded with MessagePack, images...

sendBinaryDatas :: WebSocketsData a => Connection -> [a] -> IO () #

Send a number of binary messages. This is more efficient than calling `sendBinaryData` many times.

sendClose :: WebSocketsData a => Connection -> a -> IO () #

Send a friendly close message. Note that after sending this message, you should still continue calling `receiveDataMessage` to process any in-flight messages. The peer will eventually respond with a close control message of its own which will cause `receiveDataMessage` to throw the `CloseRequest` exception. This exception is when you can finally consider the connection closed.

sendCloseCode :: WebSocketsData a => Connection -> Word16 -> a -> IO () #

Send a friendly close message and close code. Similar to `sendClose`, you should continue calling `receiveDataMessage` until you receive a `CloseRequest` exception.

See http://tools.ietf.org/html/rfc6455#section-7.4 for a list of close codes.

sendPing :: WebSocketsData a => Connection -> a -> IO () #

Send a ping

# HTTP Types

type Headers = [(CI ByteString, ByteString)] #

Request headers

data Request #

A request with a body

Constructors

Request RequestHead ByteString |

#### Instances

Instances details

Show Request # |
Instance details Defined in Network.WebSockets.Http Methods showsPrec :: Int -> Request -> ShowS # show :: Request -> String # showList :: [Request] -> ShowS #

data RequestHead #

An HTTP request. The request body is not yet read.

Constructors

RequestHead |

Fields

- requestPath :: !ByteString
- requestHeaders :: Headers
- requestSecure :: Bool

#### Instances

Instances details

Show RequestHead # |
Instance details Defined in Network.WebSockets.Http Methods showsPrec :: Int -> RequestHead -> ShowS # show :: RequestHead -> String # showList :: [RequestHead] -> ShowS #

getRequestSubprotocols :: RequestHead -> [ByteString] #

List of subprotocols specified by the client, in order of preference. If the client did not specify a list of subprotocols, this will be the empty list.

data Response #

A response including a body

Constructors

Response ResponseHead ByteString |

#### Instances

Instances details

Show Response # |
Instance details Defined in Network.WebSockets.Http Methods showsPrec :: Int -> Response -> ShowS # show :: Response -> String # showList :: [Response] -> ShowS #

data ResponseHead #

HTTP response, without body.

Constructors

ResponseHead |

Fields

- responseCode :: !Int
- responseMessage :: !ByteString
- responseHeaders :: Headers

#### Instances

Instances details

Show ResponseHead # |
Instance details Defined in Network.WebSockets.Http Methods showsPrec :: Int -> ResponseHead -> ShowS # show :: ResponseHead -> String # showList :: [ResponseHead] -> ShowS #

# WebSocket message types

data Message #

The kind of message a server application typically deals with

Constructors

ControlMessage ControlMessage |
DataMessage Bool Bool Bool DataMessage | Reserved bits, actual message

#### Instances

Instances details

Show Message # |
Instance details Defined in Network.WebSockets.Types Methods showsPrec :: Int -> Message -> ShowS # show :: Message -> String # showList :: [Message] -> ShowS #
Eq Message # |
Instance details Defined in Network.WebSockets.Types Methods (==) :: Message -> Message -> Bool # (/=) :: Message -> Message -> Bool #

data ControlMessage #

Different control messages

Constructors

Close Word16 ByteString |
Ping ByteString |
Pong ByteString |

#### Instances

Instances details

Show ControlMessage # |
Instance details Defined in Network.WebSockets.Types Methods showsPrec :: Int -> ControlMessage -> ShowS # show :: ControlMessage -> String # showList :: [ControlMessage] -> ShowS #
Eq ControlMessage # |
Instance details Defined in Network.WebSockets.Types Methods (==) :: ControlMessage -> ControlMessage -> Bool # (/=) :: ControlMessage -> ControlMessage -> Bool #

data DataMessage #

For an end-user of this library, dealing with `Frame`s would be a bit low-level. This is why define another type on top of it, which represents data for the application layer.

There are currently two kinds of data messages supported by the WebSockets protocol:

- Textual UTF-8 encoded data. This corresponds roughly to sending a String in JavaScript.
- Binary data. This corresponds roughly to send an ArrayBuffer in JavaScript.

Constructors

Text ByteString (Maybe Text) | A textual message. The second field might contain the decoded UTF-8 text for caching reasons. This field is computed lazily so if it's not accessed, it should have no performance impact.
Binary ByteString | A binary message.

#### Instances

Instances details

Show DataMessage # |
Instance details Defined in Network.WebSockets.Types Methods showsPrec :: Int -> DataMessage -> ShowS # show :: DataMessage -> String # showList :: [DataMessage] -> ShowS #
Eq DataMessage # |
Instance details Defined in Network.WebSockets.Types Methods (==) :: DataMessage -> DataMessage -> Bool # (/=) :: DataMessage -> DataMessage -> Bool #

class WebSocketsData a where #

In order to have an even more high-level API, we define a typeclass for values the user can receive from and send to the socket. A few warnings apply:

- Natively, everything is represented as a `ByteString`, so this is the fastest instance
- You should only use the `Text` or the `Text` instance when you are sure that the data is UTF-8 encoded (which is the case for `Text` messages).
- Messages can be very large. If this is the case, it might be inefficient to use the strict `ByteString` and `Text` instances.

Methods

fromDataMessage :: DataMessage -> a #

fromLazyByteString :: ByteString -> a #

toLazyByteString :: a -> ByteString #

#### Instances

Instances details

WebSocketsData ByteString # |
Instance details Defined in Network.WebSockets.Types Methods fromDataMessage :: DataMessage -> ByteString # fromLazyByteString :: ByteString -> ByteString # toLazyByteString :: ByteString -> ByteString #
WebSocketsData ByteString # |
Instance details Defined in Network.WebSockets.Types Methods fromDataMessage :: DataMessage -> ByteString # fromLazyByteString :: ByteString -> ByteString # toLazyByteString :: ByteString -> ByteString #
WebSocketsData Text # |
Instance details Defined in Network.WebSockets.Types Methods fromDataMessage :: DataMessage -> Text # fromLazyByteString :: ByteString -> Text # toLazyByteString :: Text -> ByteString #
WebSocketsData Text # |
Instance details Defined in Network.WebSockets.Types Methods fromDataMessage :: DataMessage -> Text # fromLazyByteString :: ByteString -> Text # toLazyByteString :: Text -> ByteString #

# Exceptions

data HandshakeException #

Error in case of failed handshake. Will be thrown as an `Exception`.

TODO: This should probably be in the Handshake module, and is solely here to prevent a cyclic dependency.

Constructors

NotSupported | We don't have a match for the protocol requested by the client. todo: version parameter
MalformedRequest RequestHead String | The request was somehow invalid (missing headers or wrong security token)
MalformedResponse ResponseHead String | The servers response was somehow invalid (missing headers or wrong security token)
RequestRejected RequestHead ResponseHead | The request was well-formed, but the library user rejected it. (e.g. "unknown path")
ConnectionTimeout | The connection timed out
OtherHandshakeException String | for example "EOF came too early" (which is actually a parse error) or for your own errors. (like "unknown path"?)

#### Instances

Instances details

Exception HandshakeException # |
Instance details Defined in Network.WebSockets.Http Methods toException :: HandshakeException -> SomeException # fromException :: SomeException -> Maybe HandshakeException # displayException :: HandshakeException -> String # backtraceDesired :: HandshakeException -> Bool #
Show HandshakeException # |
Instance details Defined in Network.WebSockets.Http Methods showsPrec :: Int -> HandshakeException -> ShowS # show :: HandshakeException -> String # showList :: [HandshakeException] -> ShowS #

data ConnectionException #

Various exceptions that can occur while receiving or transmitting messages

Constructors

CloseRequest Word16 ByteString | The peer has requested that the connection be closed, and included a close code and a reason for closing. When receiving this exception, no more messages can be sent. Also, the server is responsible for closing the TCP connection once this exception is received. See http://tools.ietf.org/html/rfc6455#section-7.4 for a list of close codes.
ConnectionClosed | The peer unexpectedly closed the connection while we were trying to receive some data. This is a violation of the websocket RFC since the TCP connection should only be closed after sending and receiving close control messages.
ParseException String | The client sent garbage, i.e. we could not parse the WebSockets stream.
UnicodeException String | The client sent invalid UTF-8. Note that this exception will only be thrown if strict decoding is set in the connection options.

#### Instances

Instances details

Exception ConnectionException # |
Instance details Defined in Network.WebSockets.Types Methods toException :: ConnectionException -> SomeException # fromException :: SomeException -> Maybe ConnectionException # displayException :: ConnectionException -> String # backtraceDesired :: ConnectionException -> Bool #
Show ConnectionException # |
Instance details Defined in Network.WebSockets.Types Methods showsPrec :: Int -> ConnectionException -> ShowS # show :: ConnectionException -> String # showList :: [ConnectionException] -> ShowS #
Eq ConnectionException # |
Instance details Defined in Network.WebSockets.Types Methods (==) :: ConnectionException -> ConnectionException -> Bool # (/=) :: ConnectionException -> ConnectionException -> Bool #

# Running a standalone server

type ServerApp = PendingConnection -> IO () #

WebSockets application that can be ran by a server. Once this `IO` action finishes, the underlying socket is closed automatically.

runServer #

Arguments

:: String | Address to bind
-> Int | Port to listen on
-> ServerApp | Application
-> IO () | Never returns

Provides a simple server. This function blocks forever. Note that this is merely provided for quick-and-dirty or internal applications, but for real applications, you should use a real server.

For example:

- Performance is reasonable under load, but:
- No protection against DoS attacks is provided.
- No logging is performed.
- ...

Glue for using this package with real servers is provided by:

- https://hackage.haskell.org/package/wai-websockets
- https://hackage.haskell.org/package/websockets-snap

runServerWith :: String -> Int -> ConnectionOptions -> ServerApp -> IO () #

Deprecated: Use `runServerWithOptions` instead

A version of `runServer` which allows you to customize some options.

data ServerOptions #

Constructors

ServerOptions |

Fields

- serverHost :: String
- serverPort :: Int
- serverConnectionOptions :: ConnectionOptions

defaultServerOptions :: ServerOptions #

runServerWithOptions :: ServerOptions -> ServerApp -> IO a #

Customizable version of `runServer`. Never returns until killed.

Please use the `defaultServerOptions` combined with record updates to set the fields you want. This way your code is unlikely to break on future changes.

# Utilities for writing your own server

makeListenSocket :: String -> Int -> IO Socket #

Create a standardized socket on which you can listen for incomming connections. Should only be used for a quick and dirty solution! Should be preceded by the call `withSocketsDo`.

makePendingConnection :: Socket -> ConnectionOptions -> IO PendingConnection #

Turns a socket, connected to some client, into a `PendingConnection`. The `PendingConnection` should be closed using `pendingStream` and `close` later.

makePendingConnectionFromStream :: Stream -> ConnectionOptions -> IO PendingConnection #

More general version of `makePendingConnection` for `Stream` instead of a `Socket`.

# Running a client

type ClientApp a = Connection -> IO a #

A client application interacting with a single server. Once this `IO` action finished, the underlying socket is closed automatically.

runClient #

Arguments

:: String | Host
-> Int | Port
-> String | Path
-> ClientApp a | Client application
-> IO a |

runClientWith #

Arguments

:: String | Host
-> Int | Port
-> String | Path
-> ConnectionOptions | Options
-> Headers | Custom headers to send
-> ClientApp a | Client application
-> IO a |

runClientWithSocket #

Arguments

:: Socket | Socket
-> String | Host
-> String | Path
-> ConnectionOptions | Options
-> Headers | Custom headers to send
-> ClientApp a | Client application
-> IO a |

runClientWithStream #

Arguments

:: Stream | Stream
-> String | Host
-> String | Path
-> ConnectionOptions | Connection options
-> Headers | Custom headers to send
-> ClientApp a | Client application
-> IO a |

newClientConnection #

Arguments

:: Stream | Stream that will be used by the new `Connection`.
-> String | Host
-> String | Path
-> ConnectionOptions | Connection options
-> Headers | Custom headers to send
-> IO Connection |

Build a new `Connection` from the client's point of view.

WARNING: Be sure to call `close` on the given `Stream` after you are done using the `Connection` in order to properly close the communication channel. `runClientWithStream` handles this for you, prefer to use it when possible.

# Utilities

data PingPongOptions #

Options for ping-pong

Make sure that the ping interval is less than the pong timeout, for example N/2.

Constructors

PingPongOptions |

Fields

- pingInterval :: Int

  Interval in seconds

- pongTimeout :: Int

  Timeout in seconds

- pingAction :: IO ()

  Action to perform after sending a ping

defaultPingPongOptions :: PingPongOptions #

Default options for ping-pong

Ping every 15 seconds, timeout after 30 seconds

withPingPong :: PingPongOptions -> Connection -> (Connection -> IO ()) -> IO () #

Run an application with ping-pong enabled. Raises PongTimeout if a pong is not received.

Can used with Client and Server connections.

withPingThread #

Arguments

:: Connection |
-> Int | Second interval in which pings should be sent.
-> IO () | Repeat this after sending a ping.
-> IO a | Application to wrap with a ping thread.
-> IO a | Executes application and kills ping thread when done.

Forks a ping thread, sending a ping message every `n` seconds over the connection. The thread is killed when the inner IO action is finished.

This is useful to keep idle connections open through proxies and whatnot. Many (but not all) proxies have a 60 second default timeout, so based on that sending a ping every 30 seconds is a good idea.

Note that usually you want to use `withPingPong` to timeout the connection if a pong is not received.

forkPingThread :: Connection -> Int -> IO () #

Deprecated: Use `withPingThread` instead

DEPRECATED: Use `withPingThread` instead.

Forks a ping thread, sending a ping message every `n` seconds over the connection. The thread dies silently if the connection crashes or is closed.

This is useful to keep idle connections open through proxies and whatnot. Many (but not all) proxies have a 60 second default timeout, so based on that sending a ping every 30 seconds is a good idea.