-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | A sensible and clean way to write WebSocket-capable servers in Haskell. -- @package websockets @version 0.9.3.0 -- | Lightweight abstraction over an input/output stream. module Network.WebSockets.Stream -- | Lightweight abstraction over an input/output stream. data Stream makeStream :: IO (Maybe ByteString) -> (Maybe ByteString -> IO ()) -> IO Stream makeSocketStream :: Socket -> IO Stream makeEchoStream :: IO Stream parse :: Stream -> Parser a -> IO (Maybe a) write :: Stream -> ByteString -> IO () close :: Stream -> IO () -- | This module exposes connection internals and should only be used if -- you really know what you are doing. module Network.WebSockets.Connection -- | A new client connected to the server. We haven't accepted the -- connection yet, though. data PendingConnection PendingConnection :: !ConnectionOptions -> !RequestHead -> !(Connection -> IO ()) -> !Stream -> PendingConnection -- | Options, passed as-is to the Connection pendingOptions :: PendingConnection -> !ConnectionOptions -- | Useful for e.g. inspecting the request path. pendingRequest :: PendingConnection -> !RequestHead -- | One-shot callback fired when a connection is accepted, i.e., *after* -- the accepting response is sent to the client. pendingOnAccept :: PendingConnection -> !(Connection -> IO ()) -- | Input/output stream pendingStream :: PendingConnection -> !Stream data AcceptRequest AcceptRequest :: !(Maybe ByteString) -> AcceptRequest -- | The subprotocol to speak with the client. If -- pendingSubprotcols is non-empty, acceptSubprotocol -- must be one of the subprotocols from the list. acceptSubprotocol :: AcceptRequest -> !(Maybe ByteString) acceptRequest :: PendingConnection -> IO Connection acceptRequestWith :: PendingConnection -> AcceptRequest -> IO Connection rejectRequest :: PendingConnection -> ByteString -> IO () -- | Type representing an available or unavailable stream. data DecoderEncoder a DecoderEncoder :: !(IO (Maybe a)) -> !(a -> IO ()) -> DecoderEncoder a Closed :: DecoderEncoder a data Connection Connection :: !ConnectionOptions -> !ConnectionType -> !Protocol -> !(MVar ()) -> !(MVar ()) -> !(IORef (DecoderEncoder Message)) -> !(IORef Bool) -> Connection connectionOptions :: Connection -> !ConnectionOptions connectionType :: Connection -> !ConnectionType connectionProtocol :: Connection -> !Protocol connectionParseLock :: Connection -> !(MVar ()) connectionWriteLock :: Connection -> !(MVar ()) connectionStream :: Connection -> !(IORef (DecoderEncoder Message)) -- | According to the RFC, both the client and the server MUST send a close -- control message to each other. Either party can initiate the first -- close message but then the other party must respond. Finally, the -- server is in charge of closing the TCP connection. This IORef tracks -- if we have sent a close message and are waiting for the peer to -- respond. connectionSentClose :: Connection -> !(IORef Bool) -- | Set options for a Connection. data ConnectionOptions ConnectionOptions :: !(IO ()) -> ConnectionOptions -- | Whenever a pong is received, this IO action is executed. It -- can be used to tickle connections or fire missiles. connectionOnPong :: ConnectionOptions -> !(IO ()) defaultConnectionOptions :: ConnectionOptions receive :: Connection -> IO Message -- | 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. receiveDataMessage :: Connection -> IO DataMessage -- | Receive a message, converting it to whatever format is needed. receiveData :: WebSocketsData a => Connection -> IO a send :: Connection -> Message -> IO () -- | Send a DataMessage sendDataMessage :: Connection -> DataMessage -> IO () -- | Send a message as text sendTextData :: WebSocketsData a => Connection -> a -> IO () -- | Send a message as binary data sendBinaryData :: 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. sendClose :: WebSocketsData a => Connection -> 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. sendCloseCode :: WebSocketsData a => Connection -> Word16 -> a -> IO () -- | Send a ping sendPing :: WebSocketsData a => Connection -> a -> IO () -- | 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. forkPingThread :: Connection -> Int -> IO () module Network.WebSockets -- | A new client connected to the server. We haven't accepted the -- connection yet, though. data PendingConnection -- | Useful for e.g. inspecting the request path. pendingRequest :: PendingConnection -> RequestHead data AcceptRequest AcceptRequest :: !(Maybe ByteString) -> AcceptRequest -- | The subprotocol to speak with the client. If -- pendingSubprotcols is non-empty, acceptSubprotocol -- must be one of the subprotocols from the list. acceptSubprotocol :: AcceptRequest -> !(Maybe ByteString) acceptRequest :: PendingConnection -> IO Connection acceptRequestWith :: PendingConnection -> AcceptRequest -> IO Connection rejectRequest :: PendingConnection -> ByteString -> IO () data Connection -- | Set options for a Connection. data ConnectionOptions ConnectionOptions :: !(IO ()) -> ConnectionOptions -- | Whenever a pong is received, this IO action is executed. It -- can be used to tickle connections or fire missiles. connectionOnPong :: ConnectionOptions -> !(IO ()) defaultConnectionOptions :: ConnectionOptions receive :: Connection -> IO Message -- | 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. receiveDataMessage :: Connection -> IO DataMessage -- | Receive a message, converting it to whatever format is needed. receiveData :: WebSocketsData a => Connection -> IO a send :: Connection -> Message -> IO () -- | Send a DataMessage sendDataMessage :: Connection -> DataMessage -> IO () -- | Send a message as text sendTextData :: WebSocketsData a => Connection -> a -> IO () -- | Send a message as binary data sendBinaryData :: 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. sendClose :: WebSocketsData a => Connection -> a -> IO () -- | Send a ping sendPing :: WebSocketsData a => Connection -> a -> IO () -- | Request headers type Headers = [(CI ByteString, ByteString)] -- | A request with a body data Request Request :: RequestHead -> ByteString -> Request -- | An HTTP request. The request body is not yet read. data RequestHead RequestHead :: !ByteString -> Headers -> Bool -> RequestHead requestPath :: RequestHead -> !ByteString requestHeaders :: RequestHead -> Headers requestSecure :: RequestHead -> Bool -- | 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. getRequestSubprotocols :: RequestHead -> [ByteString] -- | A response including a body data Response Response :: ResponseHead -> ByteString -> Response -- | HTTP response, without body. data ResponseHead ResponseHead :: !Int -> !ByteString -> Headers -> ResponseHead responseCode :: ResponseHead -> !Int responseMessage :: ResponseHead -> !ByteString responseHeaders :: ResponseHead -> Headers -- | The kind of message a server application typically deals with data Message ControlMessage :: ControlMessage -> Message DataMessage :: DataMessage -> Message -- | Different control messages data ControlMessage Close :: Word16 -> ByteString -> ControlMessage Ping :: ByteString -> ControlMessage Pong :: ByteString -> ControlMessage -- | For an end-user of this library, dealing with Frames would be -- a bit low-level. This is why define another type on top of it, which -- represents data for the application layer. data DataMessage Text :: ByteString -> DataMessage Binary :: ByteString -> DataMessage -- | 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: -- -- class WebSocketsData a fromLazyByteString :: WebSocketsData a => ByteString -> a toLazyByteString :: WebSocketsData a => a -> ByteString -- | 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. data HandshakeException -- | We don't have a match for the protocol requested by the client. todo: -- version parameter NotSupported :: HandshakeException -- | The request was somehow invalid (missing headers or wrong security -- token) MalformedRequest :: RequestHead -> String -> HandshakeException -- | The servers response was somehow invalid (missing headers or wrong -- security token) MalformedResponse :: ResponseHead -> String -> HandshakeException -- | The request was well-formed, but the library user rejected it. (e.g. -- "unknown path") RequestRejected :: Request -> String -> HandshakeException -- | for example "EOF came too early" (which is actually a parse error) or -- for your own errors. (like "unknown path"?) OtherHandshakeException :: String -> HandshakeException -- | Various exceptions that can occur while receiving or transmitting -- messages data ConnectionException -- | 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. CloseRequest :: Word16 -> ByteString -> ConnectionException -- | 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. ConnectionClosed :: ConnectionException -- | The client sent garbage, i.e. we could not parse the WebSockets -- stream. ParseException :: String -> ConnectionException -- | WebSockets application that can be ran by a server. Once this -- IO action finishes, the underlying socket is closed -- automatically. type ServerApp = PendingConnection -> IO () -- | Provides a simple server. This function blocks forever. Note that this -- is merely provided for quick-and-dirty standalone applications, for -- real applications, you should use a real server. runServer :: String -> Int -> ServerApp -> IO () -- | A version of runServer which allows you to customize some -- options. runServerWith :: String -> Int -> ConnectionOptions -> ServerApp -> IO () -- | 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. makeListenSocket :: String -> Int -> IO Socket -- | Turns a socket, connected to some client, into a -- PendingConnection. makePendingConnection :: Socket -> ConnectionOptions -> IO PendingConnection -- | A client application interacting with a single server. Once this -- IO action finished, the underlying socket is closed -- automatically. 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 -- | 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. forkPingThread :: Connection -> Int -> IO ()