websockets- Create WebSocket servers



How do you use this library? Here's how:

And here's a short example of a server that accepts clients, greets them with a welcome message, checks for disconnects and replies to all messages by echoing them back with an appended meow:

 import Network.WebSockets (shakeHands, getFrame, putFrame)
 import Network (listenOn, PortID(PortNumber), accept, withSocketsDo)
 import System.IO (Handle, hClose)
 import qualified Data.ByteString as B (append, null)
 import Data.ByteString.UTF8 (fromString) -- this is from utf8-string
 import Control.Monad (forever)
 import Control.Concurrent (forkIO)

 -- Accepts clients, spawns a single handler for each one.
 main :: IO ()
 main = withSocketsDo $ do
   socket <- listenOn (PortNumber 12345)
   putStrLn "Listening on port 12345."
   forever $ do
     (h, _, _) <- accept socket
     forkIO (talkTo h)
 -- Shakes hands with client. If no error, starts talking.
 talkTo :: Handle -> IO ()
 talkTo h = do
   request <- shakeHands h
   case request of
     Left err -> print err
     Right  _ -> do
       putFrame h (fromString "Do you read me, Lieutenant Bowie?")
       putStrLn "Shook hands, sent welcome message."
       talkLoop h
 -- Talks to the client (by echoing messages back) until EOF.
 talkLoop :: Handle -> IO ()
 talkLoop h = do
   msg <- getFrame h
   if B.null msg
      then do
        putStrLn "EOF encountered. Closing handle."
        hClose h
      else do
        putFrame h $ B.append msg (fromString ", meow.")
        talkLoop h

The example above will suffice if you wish to accept any WebSocket-capable client, regardless of its origin or target. It won't suffice if you have to filter the incoming clients by the contents of their requests. For that, you can use getRequest and putResponse, which allow you to inspect the request details before you send back a response, if any.

If you have any suggestions, bug reports and/or fixes, feel free to send them to mailto:sinisa@bidin.cc.



shakeHands :: Handle -> IO (Either HandshakeError Request)Source

Accept and perform a handshake, no matter the request contents.

As long as the request is well-formed, the client will receive a response saying, essentially, "proceed". Use this function if you don't care who you're connected to, as long as that someone speaks the WebSocket protocol.

The function returns either a HandshakeError in case of error, or a Request on success. The Request is returned purely for logging purposes, since the handshake has already been executed. Use this function immediately after establishing the connection.

If you wish not to blindly accept requests but to filter them according to their contents, use the getRequest and putResponse functions.

getRequest :: Handle -> IO (Either HandshakeError Request)Source

Reads the client's opening handshake and returns either a Request based on its contents, or a HandshakeError in case of an error.

putResponse :: Handle -> Request -> IO ()Source

Sends an accepting response based on the given Request, thus accepting and ending the handshake.

createResponse :: Request -> ByteStringSource

Returns an accepting response based on the given Request. putResponse uses this function internally.

getFrame :: Handle -> IO ByteStringSource

Receive a strict ByteString. Call this function only after having performed the handshake. This function will block until an entire frame is read. If the writing end of the handle is closed, the function returns an empty ByteString.

putFrame :: Handle -> ByteString -> IO ()Source

Send a strict ByteString. Call this function only after having performed the handshake.

createToken :: Request -> ByteStringSource

Constructs the response token by using the two security keys the and eight-byte token given in the request, as defined by the protocol.

data Request Source

Contains the request details.




reqHost :: String

The requested host.

reqPath :: String

The requested path.

reqOrigin :: String

The origin of the request.

reqKey1 :: String

The first security key.

reqKey2 :: String

The second security key.

reqToken :: String

The given eight-byte token.