packages feed

hemokit-0.5.1: apps/WebsocketUtils.hs

{-# LANGUAGE ExistentialQuantification #-}

module WebsocketUtils
  ( jsonWSServerFromChan
  , makeJsonWSServer
  , makeJsonOrShowWSServer
  , JsonShowable (..)
  ) where

import           Control.Concurrent
import           Control.Monad
import           Data.Aeson (ToJSON(..), encode)
import           Network.WebSockets


-- | A websocket server that serves JSON from a Chan.
jsonWSServerFromChan :: (ToJSON a) => Chan a -> PendingConnection -> IO ()
jsonWSServerFromChan chan = \req -> do
  conn <- acceptRequest req
  c <- dupChan chan
  forever (readChan c >>= sendTextData conn . encode)


-- | Creates and starts (forking) a JSON-serving websocket server.
-- Returns a Chan from which the server will read.
makeJsonWSServer :: (ToJSON a) => String -> Int -> IO (Chan a)
makeJsonWSServer host port = do
  chan <- newChan
  _ <- forkIO $ runServer host port (jsonWSServerFromChan chan)
  return chan


-- | Creates a server that can serve things either as text or as JSON.
-- If `json` is true, inputs to the returned function will be sent as JSON,
-- otherwise they will be `show`n and then JSON-formatted as a String.
makeJsonOrShowWSServer :: (Show a, ToJSON a) => String -> Int -> Bool -> IO (a -> IO ())
makeJsonOrShowWSServer host port json =
  if json then do chan <- makeJsonWSServer host port
                  return (writeChan chan)
          else do chan <- makeJsonWSServer host port
                  return (writeChan chan . show)


-- | Something that can be shown and formatted as JSON.
data JsonShowable = forall a . (Show a, ToJSON a) => JsonShowable a

instance Show JsonShowable   where show (JsonShowable x) = show x
instance ToJSON JsonShowable where toJSON (JsonShowable x) = toJSON x