diff options
-rw-r--r-- | consolation.hs | 65 |
1 files changed, 45 insertions, 20 deletions
diff --git a/consolation.hs b/consolation.hs index bced2839..640b51c2 100644 --- a/consolation.hs +++ b/consolation.hs | |||
@@ -6,6 +6,7 @@ import Control.Applicative | |||
6 | import Control.Concurrent | 6 | import Control.Concurrent |
7 | import Control.Concurrent.STM | 7 | import Control.Concurrent.STM |
8 | import Data.Monoid | 8 | import Data.Monoid |
9 | import Data.Char | ||
9 | import System.INotify ( initINotify, EventVariety(Modify), addWatch ) | 10 | import System.INotify ( initINotify, EventVariety(Modify), addWatch ) |
10 | import Data.Word ( Word8 ) | 11 | import Data.Word ( Word8 ) |
11 | import Data.Text ( Text ) | 12 | import Data.Text ( Text ) |
@@ -43,14 +44,23 @@ onLogin cs start = \e -> do | |||
43 | Traversable.mapM (flip writeTVar Nothing) dead | 44 | Traversable.mapM (flip writeTVar Nothing) dead |
44 | writeTVar (csUtmp cs) $ (old `Map.union` newborn) Map.\\ dead | 45 | writeTVar (csUtmp cs) $ (old `Map.union` newborn) Map.\\ dead |
45 | return newborn | 46 | return newborn |
47 | let getActive = do | ||
48 | tty <- readTVar $ csActiveTTY cs | ||
49 | utmp <- readTVar $ csUtmp cs | ||
50 | flip (maybe $ return (tty,Nothing)) | ||
51 | (Map.lookup ("tty"<>tshow tty) utmp) | ||
52 | $ \tuvar -> do | ||
53 | tu <- readTVar tuvar | ||
54 | return (tty,tu) | ||
55 | |||
46 | forM_ (Map.elems newborn) $ | 56 | forM_ (Map.elems newborn) $ |
47 | forkIO . start (csActiveTTY cs) | 57 | forkIO . start getActive |
48 | -- forM_ (Map.elems dead ) $ putStrLn . ("gone: "++) . show | 58 | -- forM_ (Map.elems dead ) $ putStrLn . ("gone: "++) . show |
49 | 59 | ||
50 | onTTY cs vtnum = atomically $ writeTVar (csActiveTTY cs) vtnum | 60 | onTTY cs vtnum = atomically $ writeTVar (csActiveTTY cs) vtnum |
51 | 61 | ||
52 | retryWhen var pred = do | 62 | retryWhen var pred = do |
53 | value <- readTVar var | 63 | value <- var |
54 | if pred value then retry | 64 | if pred value then retry |
55 | else return value | 65 | else return value |
56 | 66 | ||
@@ -71,38 +81,53 @@ ujid u = do | |||
71 | h <- textHostName | 81 | h <- textHostName |
72 | return $ utmpUser u <> "@" <> h <> "/" <> resource u | 82 | return $ utmpUser u <> "@" <> h <> "/" <> resource u |
73 | 83 | ||
74 | newCon :: (Text -> IO ()) -> TVar Word8 -> TVar (Maybe UtmpRecord) -> IO () | 84 | newCon :: (Text -> IO ()) -> STM (Word8,Maybe UtmpRecord) -> TVar (Maybe UtmpRecord) -> IO () |
75 | newCon log activeTTY utmp = do | 85 | newCon log activeTTY utmp = do |
76 | (tty,u) <- atomically $ | 86 | ((tty,tu),u) <- atomically $ |
77 | liftM2 (,) (readTVar activeTTY) | 87 | liftM2 (,) activeTTY |
78 | (readTVar utmp) | 88 | (readTVar utmp) |
79 | flip (maybe $ return ()) u $ \u -> do | 89 | flip (maybe $ return ()) u $ \u -> do |
80 | jid <- ujid u | 90 | jid <- ujid u |
81 | log $ status (resource u) tty <> " " <> jid <> " pid=" <> tshow (utmpPid u) | 91 | log $ status (resource u) tty tu <> " " <> jid <> " pid=" <> tshow (utmpPid u) |
82 | loop tty (Just u) | 92 | <> if istty (resource u) |
93 | then " host=" <> tshow (utmpHost u) | ||
94 | else "" | ||
95 | loop tty tu (Just u) | ||
83 | where | 96 | where |
84 | bstatus r ttynum = r == "tty" <> tshow ttynum | 97 | bstatus r ttynum mtu |
85 | status r ttynum = | 98 | = r == ttystr |
86 | if bstatus r ttynum | 99 | || match mtu |
100 | where ttystr = "tty" <> tshow ttynum | ||
101 | searchstr mtu = maybe ttystr utmpHost $ do | ||
102 | tu <- mtu | ||
103 | guard (not $ Text.null $ utmpHost tu) | ||
104 | return tu | ||
105 | match mtu = searchstr mtu `Text.isInfixOf` Text.dropWhile (/=':') r | ||
106 | status r ttynum tu = | ||
107 | if bstatus r ttynum tu | ||
87 | then "Available" | 108 | then "Available" |
88 | else "Away " | 109 | else "Away " |
89 | 110 | ||
90 | loop tty u = do | 111 | istty r = fst3 == "tty" && Text.all isDigit rst |
112 | where | ||
113 | (fst3,rst) = Text.splitAt 3 r | ||
114 | |||
115 | loop tty tu u = do | ||
91 | what <- atomically $ foldr1 orElse | 116 | what <- atomically $ foldr1 orElse |
92 | [ do tty' <- retryWhen activeTTY | 117 | [ do (tty',tu') <- retryWhen activeTTY |
93 | (\tty' -> bstatus r tty == bstatus r tty') | 118 | (\ttyu -> bstatus r tty tu == uncurry (bstatus r) ttyu) |
94 | return $ ttyChanged tty' | 119 | return $ ttyChanged tty' tu' |
95 | , do u' <- retryWhen utmp (==u) | 120 | , do u' <- retryWhen (readTVar utmp) (==u) |
96 | return $ utmpChanged u' | 121 | return $ utmpChanged u' |
97 | ] | 122 | ] |
98 | what | 123 | what |
99 | where | 124 | where |
100 | r = maybe "" resource u | 125 | r = maybe "" resource u |
101 | 126 | ||
102 | ttyChanged tty' = do | 127 | ttyChanged tty' tu' = do |
103 | jid <- maybe (return "") ujid u | 128 | jid <- maybe (return "") ujid u |
104 | log $ status r tty' <> " " <> jid | 129 | log $ status r tty' tu' <> " " <> jid |
105 | loop tty' u | 130 | loop tty' tu' u |
106 | 131 | ||
107 | utmpChanged u' = maybe dead changed u' | 132 | utmpChanged u' = maybe dead changed u' |
108 | where | 133 | where |
@@ -110,7 +135,7 @@ newCon log activeTTY utmp = do | |||
110 | jid0 <- maybe (return "") ujid u | 135 | jid0 <- maybe (return "") ujid u |
111 | jid <- ujid u' | 136 | jid <- ujid u' |
112 | log $ "changed: " <> jid0 <> " --> " <> jid | 137 | log $ "changed: " <> jid0 <> " --> " <> jid |
113 | loop tty (Just u') | 138 | loop tty tu (Just u') |
114 | dead = do | 139 | dead = do |
115 | jid <- maybe (return "") ujid u | 140 | jid <- maybe (return "") ujid u |
116 | log $ "Offline " <> jid | 141 | log $ "Offline " <> jid |
@@ -129,7 +154,7 @@ main = do | |||
129 | 154 | ||
130 | -- get active tty | 155 | -- get active tty |
131 | mtty <- monitorTTY (onTTY cs) | 156 | mtty <- monitorTTY (onTTY cs) |
132 | atomically $ retryWhen (csActiveTTY cs) (==0) | 157 | atomically $ retryWhen (readTVar $ csActiveTTY cs) (==0) |
133 | 158 | ||
134 | -- read utmp | 159 | -- read utmp |
135 | onLogin cs (newCon $ logit outvar) Modify | 160 | onLogin cs (newCon $ logit outvar) Modify |