socketio-0.1.0.0: Web/SocketIO/Types/SocketIO.hs
--------------------------------------------------------------------------------
-- | Datatypes to be exposed to end user
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Web.SocketIO.Types.SocketIO where
--------------------------------------------------------------------------------
import Control.Applicative (Applicative, (<$>))
import Control.Concurrent.Chan.Lifted (Chan, writeChan)
import Control.Monad.Base
import Control.Monad.Reader
import Control.Monad.Writer
import qualified Data.Aeson as Aeson
--------------------------------------------------------------------------------
import Web.SocketIO.Types.String
--------------------------------------------------------------------------------
-- | Now only xhr-polling is supported.
data Transport = WebSocket | XHRPolling | NoTransport deriving (Eq, Show)
--------------------------------------------------------------------------------
data Configuration = Configuration
{ transports :: [Transport]
, logLevel :: Int
, heartbeats :: Bool
, closeTimeout :: Int
, heartbeatTimeout :: Int
, heartbeatInterval :: Int
, pollingDuration :: Int
} deriving Show
--------------------------------------------------------------------------------
type Port = Int
--------------------------------------------------------------------------------
type Event = Text
type Buffer = Chan Emitter
type Listener = (Event, CallbackM ())
data Emitter = Emitter Event [Text] | NoEmitter deriving (Show, Eq)
instance Aeson.ToJSON Emitter where
toJSON (Emitter name args) = Aeson.object ["name" Aeson..= name, "args" Aeson..= args]
toJSON NoEmitter = Aeson.object []
data BufferHub = BufferHub
{ selectLocalBuffer :: Buffer
, selectGlobalBuffer :: Buffer
}
--------------------------------------------------------------------------------
-- | Capable of both sending and receiving events.
--
-- Use 'liftIO' if you wanna do some IO here.
newtype HandlerM a = HandlerM { runHandlerM :: (ReaderT BufferHub (WriterT [Listener] IO)) a }
deriving (Monad, Functor, Applicative, MonadIO, MonadWriter [Listener], MonadReader BufferHub, MonadBase IO)
--------------------------------------------------------------------------------
-- | Capable of only sending events.
--
-- Use 'liftIO' if you wanna do some IO here.
newtype CallbackM a = CallbackM { runCallbackM :: (WriterT [Emitter] (ReaderT [Text] (ReaderT BufferHub IO))) a }
deriving (Monad, Functor, Applicative, MonadIO, MonadWriter [Emitter], MonadReader [Text], MonadBase IO)
--------------------------------------------------------------------------------
-- | Sending events
class Publisher m where
-- | Sends a message to the socket that starts it.
--
-- @
-- `emit` \"launch\" [\"missile\", \"nuke\"]
-- @
emit :: Event -- ^ event to trigger
-> [Text] -- ^ message to carry with
-> m ()
-- | Sends a message to everyone else except for the socket that starts it.
--
-- @
-- `broadcast` \"hide\" [\"nukes coming!\"]
-- @
broadcast :: Event -- ^ event to trigger
-> [Text] -- ^ message to carry with
-> m ()
-- |
instance Publisher HandlerM where
emit event reply = do
channel <- selectLocalBuffer <$> ask
writeChan channel (Emitter event reply)
broadcast event reply = do
channel <- selectGlobalBuffer <$> ask
writeChan channel (Emitter event reply)
instance Publisher CallbackM where
emit event reply = do
channel <- CallbackM . lift . lift $ selectLocalBuffer <$> ask
writeChan channel (Emitter event reply)
broadcast event reply = do
channel <- CallbackM . lift . lift $ selectGlobalBuffer <$> ask
writeChan channel (Emitter event reply)
--------------------------------------------------------------------------------
-- | Receiving events.
class Subscriber m where
-- @
-- 'on' \"ping\" $ do
-- 'emit' \"pong\" []
-- @
on :: Event -- ^ event to listen to
-> CallbackM () -- ^ callback
-> m ()
instance Subscriber HandlerM where
on event callback = do
HandlerM . lift . tell $ [(event, callback)]