packages feed

tianbar-0.4.0.0: src/System/Tianbar/Plugin/Socket.hs

module System.Tianbar.Plugin.Socket where

-- Socket connectivity

import Control.Concurrent
import Control.Monad
import Control.Monad.IO.Class

import qualified Data.Map as M

import Happstack.Server

import Network.Socket

import System.Tianbar.Callbacks
import System.Tianbar.Plugin

data SocketPlugin = SocketPlugin { spHost :: Callbacks
                                 , spSock :: MVar (M.Map String Socket)
                                 }

instance Plugin SocketPlugin where
    initialize c = do
        socks <- newMVar M.empty
        return $ SocketPlugin c socks

    destroy sp = withMVar (spSock sp) $ mapM_ close . M.elems

    handler plugin = dir "socket" $ msum $ map (\act -> act plugin) acts
        where acts = [connectHandler, sendHandler, closeHandler]

connectHandler :: SocketPlugin -> ServerPartT IO Response
connectHandler sp = dir "connect" $ do
    nullDir
    callbackIndex <- look "callbackIndex"
    socketPath <- look "path"
    sock <- liftIO $ do
        s <- socket AF_UNIX Stream defaultProtocol
        connect s $ SockAddrUnix socketPath
        return s
    _ <- liftIO $ forkIO $ void $ forever $ do
        response <- recv sock 4096
        callback (spHost sp) callbackIndex [response]
    liftIO $ modifyMVar_ (spSock sp) $ return . M.insert callbackIndex sock
    return $ toResponse "ok"

sendHandler :: SocketPlugin -> ServerPartT IO Response
sendHandler sp = dir "send" $ do
    nullDir
    callbackIndex <- look "callbackIndex"
    -- TODO: Maybe
    Just sock <- withSocket sp callbackIndex
    dataToSend <- look "data"
    -- TODO: resend until done
    _ <- liftIO $ send sock dataToSend
    return $ toResponse "ok"

closeHandler :: SocketPlugin -> ServerPartT IO Response
closeHandler sp = dir "close" $ do
    nullDir
    callbackIndex <- look "callbackIndex"
    sock <- withSocket sp callbackIndex
    case sock of
        Nothing -> return ()
        Just sock' -> liftIO $ do
            close sock'
            modifyMVar_ (spSock sp) $ return . M.delete callbackIndex
    return $ toResponse "ok"

withSocket :: MonadIO m => SocketPlugin -> String -> m (Maybe Socket)
withSocket sp callbackIndex = liftIO $ withMVar (spSock sp) $ return . M.lookup callbackIndex