{-# OPTIONS_GHC -XScopedTypeVariables #-} {-# OPTIONS_HADDOCK hide #-} module Control.Distributed.STM.NameService (nameService, gDefaultNameServer, registerTVar, deregisterTVar, lookupTVar) where import qualified Control.Exception as CE import Control.Distributed.STM.DebugBase import Control.Distributed.STM.Dist import Control.Distributed.STM.EnvAddr import Control.Distributed.STM.TVar import Network import Prelude as P hiding (catch, putStr, putStrLn) import System.IO --------------- -- Messaging -- --------------- data NameServerMsg = NameServerPing | NameServerReg String VarLink | NameServerUnReg String | NameServerLookup String deriving (Show, Read) type TVarDict = [(String, VarLink)] ----------------- -- Post Office -- ----------------- putNameServerLn :: Show a => String -> a -> IO () putNameServerLn nameServer msg = do debugStrLn0 ("--> putNameServerLn: "++nameServer++" msg: "++(show msg)) h <- connectTo nameServer (PortNumber gNameServerPort) sendTCP msg h hClose h getNameServerLn :: Show a => String -> a -> IO String getNameServerLn nameServer msg = do debugStrLn0 ("<-- getNameServerLn: "++nameServer++" msg: "++(show msg)) h <- connectTo nameServer (PortNumber gNameServerPort) answer <- recvTCP msg h hClose h return answer ------------------ -- Name Service -- ------------------ -- |The default name server for the process running the main function. -- Usually it is @localhost@. gDefaultNameServer :: String gDefaultNameServer = "localhost" nameService :: String -> IO () nameService server = CE.catch (putNameServerLn server NameServerPing) (\(e::CE.SomeException) -> do -- no name server yet -> start one per node debugStrLn0 ("nameService: start name server: "++ show e) listenOn (PortNumber gNameServerPort) >>= readNameServerMsg []) readNameServerMsg :: TVarDict -> Socket -> IO () readNameServerMsg tVarDict s = do debugStrLn0 ("nameService: readNameServerMsg: "++ show s) (h, _, _) <- accept s str <- hGetLine h newTable <- case reads str of ((msg,_):_) -> handleNameServerMsg h msg tVarDict _ -> return tVarDict -- internal error hClose h readNameServerMsg newTable s handleNameServerMsg :: Handle -> NameServerMsg -> TVarDict -> IO TVarDict handleNameServerMsg h msg tVarDict = case msg of NameServerPing -> return tVarDict NameServerReg name tVar -> do debugStrLn0 ("Registered: "++(show name)) return $ (name, tVar):filter ((name/=).fst) tVarDict NameServerUnReg name -> do debugStrLn0 ("Unregistered: "++(show name)) return $ filter ((name/=) . fst) tVarDict NameServerLookup name -> do debugStrLn0 ("Lookup: "++(show name)) hPutStrLn h (show (lookup name tVarDict)) return tVarDict -- |'registerTVar' @server tVar name@ registers @tVar@ with @name@ onto @server@ registerTVar :: Dist a => String -> TVar a -> String -> IO () registerTVar server tVar name = CE.catch (do debugStrLn0 ("registerTVar: " ++ show tVar ++ " " ++ name) putNameServerLn server (NameServerReg name (tVarToLink tVar)) regTVars gMyEnv tVar -- generate actions for exported tVar )(propagateEx "registerTVar") -- |'deregisterTVar' @server name@ removes @name@ from @server@ deregisterTVar :: String -> String -> IO () deregisterTVar server name = CE.catch (do debugStrLn0 ("deregisterTVar: " ++ show name) putNameServerLn server (NameServerUnReg name) )(propagateEx "deregisterTVar") -- |'lookupTVar' @server name@ returns ('Just' @tVar@) if a @tVar@ registration -- of @name@ exists on @server@, 'Nothing' otherwise. lookupTVar :: forall a . Dist a => String -> String -> IO (Maybe (TVar a)) lookupTVar server name = CE.catch (do debugStrLn0 ("lookupTVar: " ++ server ++ " , " ++ name) answer <- getNameServerLn server (NameServerLookup name) debugStrLn0 ("lookupTVar: " ++ show answer) case reads answer of ((Just link,_):_) -> do let tVar::TVar a = LinkTVar link finTVars tVar return $ Just tVar _ -> return Nothing )(propagateEx "lookupTVar")