tianbar-0.4.5.0: src/System/Tianbar/Plugin/DBus.hs
module System.Tianbar.Plugin.DBus (DBusPlugin) where
-- DBus connectivity
import Control.Applicative
import Control.Concurrent
import Control.Monad
import Control.Monad.IO.Class
import Data.Aeson (encode)
import qualified Data.Map as M
import Happstack.Server
import DBus.Client
import System.Tianbar.Callbacks
import System.Tianbar.Plugin
import System.Tianbar.Plugin.DBus.JSON ()
import System.Tianbar.Plugin.DBus.FromData ()
data Bus = Bus { busClient :: Client
, busSignals :: MVar (M.Map String SignalHandler)
}
busNew :: IO Client -> IO Bus
busNew conn = Bus <$> conn <*> newMVar M.empty
busDestroy :: Bus -> IO ()
-- TODO: remove signals?
busDestroy = disconnect . busClient
busAddListener :: (MonadIO m) => Bus -> String -> SignalHandler -> m ()
busAddListener bus index listener = liftIO $ modifyMVar_ (busSignals bus) $ \listeners ->
return $ M.insert index listener listeners
busPopListener :: (MonadIO m) => Bus -> String -> m (Maybe SignalHandler)
busPopListener bus index = liftIO $ modifyMVar (busSignals bus) $ \listeners -> do
let listener = M.lookup index listeners
let listeners' = M.delete index listeners
return (listeners', listener)
data DBusPlugin = DBusPlugin { dbusHost :: Callbacks
, dbusSession :: Bus
, dbusSystem :: Bus
}
busNameMap :: [(String, DBusPlugin -> Bus)]
busNameMap = [ ("session", dbusSession)
, ("system", dbusSystem)
]
instance Plugin DBusPlugin where
initialize c = do
session <- busNew connectSession
system <- busNew connectSystem
return $ DBusPlugin c session system
destroy plugin = mapM_ busDestroy [dbusSession plugin, dbusSystem plugin]
handler plugin = dir "dbus" $ msum [ busHandler plugin busName (bus plugin)
| (busName, bus) <- busNameMap
]
busHandler :: DBusPlugin -> String -> Bus -> ServerPartT IO Response
busHandler plugin busName bus = dir busName $ msum [ mzero
, listenHandler plugin bus
, stopHandler plugin bus
, callHandler plugin bus
]
listenHandler :: DBusPlugin -> Bus -> ServerPartT IO Response
listenHandler plugin bus = dir "listen" $ withData $ \matcher -> do
nullDir
index <- look "index"
listener <- liftIO $ addMatch (busClient bus) matcher $ \sig -> callback (dbusHost plugin) index [sig]
busAddListener bus index listener
return $ toResponse ("ok" :: String)
stopHandler :: DBusPlugin -> Bus -> ServerPartT IO Response
stopHandler _ bus = dir "stop" $ do
nullDir
index <- look "index"
listener <- busPopListener bus index
case listener of
Just l -> do
liftIO $ removeMatch (busClient bus) l
return $ toResponse ("ok" :: String)
Nothing -> mzero
callHandler :: DBusPlugin -> Bus -> ServerPartT IO Response
callHandler _ bus = dir "call" $ withData $ \mcall -> do
nullDir
res <- liftIO $ call (busClient bus) mcall
return $ toResponse $ encode res