-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | A sensible and clean way to write WebSocket-capable servers in Haskell. -- -- This library allows you to write WebSocket-capable servers. -- -- See an example: http://jaspervdj.be/websockets/example.html. -- -- The API of the Network.WebSockets module should also contain -- enough information to get you started. -- -- See also: -- -- @package websockets @version 0.7.2.0 -- | This module exports some extra functions. However, note that these -- utilities are primarily meant for internal use, and can change between -- minor releases. module Network.WebSockets.Internal -- | Create an iterator which writes to a socket. Throws a -- ConnectionClosed exception if the user attempts to write to a -- closed socket. iterSocket :: Socket -> Iteratee ByteString IO () -- | How do you use this library? Here's how: -- -- Get an enumerator/iteratee pair from your favorite web server (or use -- a library which provides integration). Alternatively, use -- runServer to set up a simple standalone server. -- -- An application typically has the form of I.Request -> -- I.WebSockets p (). The first thing to do is accept or reject the -- request, usually based upon the path in the Request. An -- example: -- --
--   {-# LANGUAGE OverloadedStrings #-}
--   import Network.WebSockets
--   
--   app :: Protocol p => Request -> WebSockets p ()
--   app rq = case requestPath rq of
--      "/forbidden" -> rejectRequest rq "Forbidden!"
--      _            -> do
--          acceptRequest rq
--          ... actual application ...
--   
-- -- You can now start using the socket for sending and receiving data. But -- what's with the p in WebSockets p ()? -- -- Well, the answer is that this library aims to support many versions of -- the WebSockets protocol. Unfortunately, not all versions of the -- protocol have the same capabilities: for example, older versions are -- not able to send binary data. -- -- The library user (you!) choose which capabilities you need. Then, the -- browser and library will negotiate at runtime which version will be -- actually used. -- -- As an example, here are two applications which need different -- capabilities: -- --
--   import Network.WebSockets
--   import qualified Data.ByteString as B
--   import qualified Data.Text as T
--   
--   app1 :: TextProtocol p => WebSockets p ()
--   app1 = sendTextData (T.pack "Hello world!")
--   
--   app2 :: BinaryProtocol p => WebSockets p ()
--   app2 = sendBinaryData (B.pack [0 .. 100])
--   
-- -- When you tie the knot, you will need to decide what protocol to -- use, to prevent ambiguousness. A good rule of thumb is to select the -- lowest protocol possible, since higher versions are generally -- backwards compatible in terms of features. . For example, the -- following application uses only features from Hybi00, and is -- therefore compatible with Hybi10 and later protocols. -- --
--   app :: Request -> WebSockets Hybi00 ()
--   app _ = app1
--   
--   main :: IO ()
--   main = runServer "0.0.0.0" 8000 app
--   
-- -- In some cases, you want to escape from the WebSockets monad and -- send data to the websocket from different threads. To this end, the -- getSink method is provided. The next example spawns a thread -- which continuously spams the client in another thread: -- --
--   import Control.Concurrent (forkIO)
--   import Control.Monad (forever)
--   import Control.Monad.Trans (liftIO)
--   import Network.WebSockets
--   import qualified Data.Text as T
--   
--   spam :: TextProtocol p => WebSockets p ()
--   spam = do
--       sink <- getSink
--       _ <- liftIO $ forkIO $ forever $
--           sendSink sink $ textData (T.pack "SPAM SPAM SPAM!")
--       sendTextData (T.pack "Hello world!")
--   
-- -- For safety reasons, you can only read from the socket in the -- WebSockets monad. -- -- For a full example, see: -- -- http://jaspervdj.be/websockets/example.html module Network.WebSockets -- | Options for the WebSocket program data WebSocketsOptions WebSocketsOptions :: IO () -> WebSocketsOptions onPong :: WebSocketsOptions -> IO () -- | Default options defaultWebSocketsOptions :: WebSocketsOptions -- | The monad in which you can write WebSocket-capable applications data WebSockets p a -- | Run a WebSockets application on an 'Enumerator'/'Iteratee' -- pair, given that you (read: your web server) has already received the -- HTTP part of the initial request. If not, you might want to use -- runWebSocketsWithHandshake instead. -- -- If the handshake failed, throws a HandshakeError. Otherwise, -- executes the supplied continuation. You should still send a response -- to the client yourself. runWebSockets :: Protocol p => RequestHttpPart -> (Request -> WebSockets p a) -> Iteratee ByteString IO () -> Iteratee ByteString IO a -- | Version of runWebSockets which allows you to specify custom -- options runWebSocketsWith :: Protocol p => WebSocketsOptions -> RequestHttpPart -> (Request -> WebSockets p a) -> Iteratee ByteString IO () -> Iteratee ByteString IO a -- | Receives the initial client handshake, then behaves like -- runWebSockets. runWebSocketsHandshake :: Protocol p => Bool -> (Request -> WebSockets p a) -> Iteratee ByteString IO () -> Iteratee ByteString IO a -- | Receives the initial client handshake, then behaves like -- runWebSocketsWith. runWebSocketsWithHandshake :: Protocol p => WebSocketsOptions -> Bool -> (Request -> WebSockets p a) -> Iteratee ByteString IO () -> Iteratee ByteString IO a class Protocol p where supported p h = case getSecWebSocketVersion h of { Just v -> v `elem` headerVersions p _ -> False } class Protocol p => TextProtocol p class TextProtocol p => BinaryProtocol p data Hybi00 data Hybi10 -- | 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 :: Protocol p => String -> Int -> (Request -> WebSockets p ()) -> IO () -- | This function wraps runWebSockets in order to provide a simple -- API for stand-alone servers. runWithSocket :: Protocol p => Socket -> (Request -> WebSockets p a) -> IO a -- | Request headers type Headers = [(CI ByteString, ByteString)] -- | Full request type, including the response to it data Request Request :: !ByteString -> Headers -> ResponseBody -> Request requestPath :: Request -> !ByteString requestHeaders :: Request -> Headers requestResponse :: Request -> ResponseBody -- | (Internally used) HTTP headers and requested path. data RequestHttpPart RequestHttpPart :: !ByteString -> Headers -> Bool -> RequestHttpPart requestHttpPath :: RequestHttpPart -> !ByteString requestHttpHeaders :: RequestHttpPart -> Headers requestHttpSecure :: RequestHttpPart -> Bool -- | A request with a body data RequestBody RequestBody :: RequestHttpPart -> ByteString -> RequestBody -- | Response to a Request data ResponseHttpPart ResponseHttpPart :: !Int -> !ByteString -> Headers -> ResponseHttpPart responseHttpCode :: ResponseHttpPart -> !Int responseHttpMessage :: ResponseHttpPart -> !ByteString responseHttpHeaders :: ResponseHttpPart -> Headers -- | A response including a body data ResponseBody ResponseBody :: ResponseHttpPart -> ByteString -> ResponseBody -- | The kind of message a server application typically deals with data Message p ControlMessage :: (ControlMessage p) -> Message p DataMessage :: (DataMessage p) -> Message p -- | Different control messages data ControlMessage p Close :: ByteString -> ControlMessage p Ping :: ByteString -> ControlMessage p Pong :: ByteString -> ControlMessage p -- | 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 p Text :: ByteString -> DataMessage p Binary :: ByteString -> DataMessage p -- | 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 -- | Accept a request. After this, you can start sending and receiving -- data. acceptRequest :: Protocol p => Request -> WebSockets p () -- | Reject a request, sending a 400 (Bad Request) to the client and -- throwing a RequestRejected (HandshakeError) rejectRequest :: Protocol p => Request -> String -> WebSockets p a -- | Find out the WebSockets version used at runtime getVersion :: Protocol p => WebSockets p String -- | Receive a message receive :: Protocol p => WebSockets p (Message p) -- | Receive an application message. Automatically respond to control -- messages. receiveDataMessage :: Protocol p => WebSockets p (DataMessage p) -- | Receive a message, treating it as data transparently receiveData :: (Protocol p, WebSocketsData a) => WebSockets p a -- | Low-level sending with an arbitrary Message send :: Protocol p => Message p -> WebSockets p () -- | Send a text message sendTextData :: (TextProtocol p, WebSocketsData a) => a -> WebSockets p () -- | Send some binary data sendBinaryData :: (BinaryProtocol p, WebSocketsData a) => a -> WebSockets p () -- | Used for asynchronous sending. data Sink p -- | Send a message to a sink. Might generate an exception if the -- underlying connection is closed. sendSink :: Sink p -> Message p -> IO () -- | In case the user of the library wants to do asynchronous sending to -- the socket, he can extract a Sink and pass this value around, -- for example, to other threads. getSink :: Protocol p => WebSockets p (Sink p) -- | Construct a close message close :: (TextProtocol p, WebSocketsData a) => a -> Message p -- | Construct a ping message ping :: (BinaryProtocol p, WebSocketsData a) => a -> Message p -- | Construct a pong message pong :: (BinaryProtocol p, WebSocketsData a) => a -> Message p -- | Construct a text message textData :: (TextProtocol p, WebSocketsData a) => a -> Message p -- | Construct a binary message binaryData :: (BinaryProtocol p, WebSocketsData a) => a -> Message p -- | spawnPingThread n spawns a thread which sends a ping every -- n seconds (if the protocol supports it). To be called after -- having sent the response. spawnPingThread :: BinaryProtocol p => Int -> WebSockets p () -- | Throw an iteratee error in the WebSockets monad throwWsError :: Exception e => e -> WebSockets p a -- | Catch an iteratee error in the WebSockets monad catchWsError :: WebSockets p a -> (SomeException -> WebSockets p a) -> WebSockets p a -- | Error in case of failed handshake. Will be thrown as an iteratee -- exception. (Error condition). -- -- TODO: This should probably be in the Handshake module, and is solely -- here to prevent a cyclic dependency. data HandshakeError -- | We don't have a match for the protocol requested by the client. todo: -- version parameter NotSupported :: HandshakeError -- | The request was somehow invalid (missing headers or wrong security -- token) MalformedRequest :: RequestHttpPart -> String -> HandshakeError -- | The servers response was somehow invalid (missing headers or wrong -- security token) MalformedResponse :: ResponseHttpPart -> String -> HandshakeError -- | The request was well-formed, but the library user rejected it. (e.g. -- unknown path) RequestRejected :: Request -> String -> HandshakeError -- | for example EOF came too early (which is actually a parse -- error) or for your own errors. (like unknown path?) OtherHandshakeError :: String -> HandshakeError -- | The connection couldn't be established or broke down unexpectedly. -- thrown as an iteratee exception. data ConnectionError -- | The client sent malformed data. ParseError :: ParseError -> ConnectionError -- | the client closed the connection while we were trying to receive some -- data. -- -- todo: Also want this for sending. ConnectionClosed :: ConnectionError connect :: Protocol p => String -> Int -> String -> WebSockets p a -> IO a connectWith :: Protocol p => String -> Int -> String -> Maybe String -> Maybe [String] -> WebSockets p a -> IO a -- | This is a simple utility module to implement a publish-subscribe -- pattern. Note that this only allows communication in a single -- direction: pusing data from the server to connected clients -- (browsers). -- -- Usage: -- -- module Network.WebSockets.Util.PubSub -- | A handle which keeps track of subscribed clients data PubSub p -- | Create a new PubSub handle, with no clients initally connected newPubSub :: IO (PubSub p) -- | Broadcast a message to all connected clients publish :: PubSub p -> Message p -> IO () -- | Blocks forever subscribe :: Protocol p => PubSub p -> WebSockets p ()