packages feed

tianbar-0.4.2.0: src/System/Tianbar/Server.hs

module System.Tianbar.Server (
    Server (..),
    startServer
) where

-- Server to handle JS callbacks

import Control.Concurrent
import Control.Monad

import Happstack.Server

import Network.Socket
import Network.URI

import System.Random

import System.Tianbar.Callbacks
import System.Tianbar.Plugin
import System.Tianbar.Plugin.Combined
import System.Tianbar.Plugin.DataDirectory
import System.Tianbar.Plugin.DBus
import System.Tianbar.Plugin.GSettings
import System.Tianbar.Plugin.Socket

data Server = Server { serverOverrideURI :: URI -> URI
                     , stopServer :: IO ()
                     }

startServer :: Callbacks -> IO Server
startServer c = do
    sock <- bindIPv4 "127.0.0.1" $ fromIntegral aNY_PORT
    prefix <- replicateM 20 $ randomRIO ('a', 'z')
    plugins <- initialize c :: IO AllPlugins
    thread <- forkIO $ runServer sock prefix plugins
    portNum <- socketPort sock
    return $ Server (handleURI portNum prefix) (killServer thread plugins)

type AllPlugins =
    Combined DataDirectory (
        Combined DBusPlugin (
            Combined GSettings (
                Combined SocketPlugin (
                    Combined Empty Empty))))

runServer :: Plugin p => Socket -> String -> p -> IO ()
runServer sock prefix plugin = do
    portNum <- socketPort sock
    let conf = nullConf { port = fromIntegral portNum }
    simpleHTTPWithSocket sock conf $ dir prefix $ handler plugin

killServer :: Plugin p => ThreadId -> p -> IO ()
killServer thread p = do
    destroy p
    killThread thread

handleURI :: PortNumber -> String -> URI -> URI
handleURI portNum prefix uri | uriScheme uri == "tianbar:" = uri'
                             | otherwise = uri
    where uri' = uri { uriScheme = "http:"
                     , uriAuthority = Just URIAuth { uriUserInfo = ""
                                                   , uriRegName = "localhost"
                                                   , uriPort = ':' : show portNum
                                                   }
                     , uriPath = "/" ++ prefix ++ uriPath uri
                     }