-- 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: -- --
-- {-# 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: -- --