diff options
-rw-r--r-- | Presence/XMPP.hs | 3 | ||||
-rw-r--r-- | Presence/XMPPTypes.hs | 4 | ||||
-rw-r--r-- | Presence/main.hs | 85 |
3 files changed, 59 insertions, 33 deletions
diff --git a/Presence/XMPP.hs b/Presence/XMPP.hs index 9dfee14e..3d20a9b8 100644 --- a/Presence/XMPP.hs +++ b/Presence/XMPP.hs | |||
@@ -4,6 +4,7 @@ | |||
4 | {-# LANGUAGE ViewPatterns #-} | 4 | {-# LANGUAGE ViewPatterns #-} |
5 | module XMPP | 5 | module XMPP |
6 | ( module XMPPTypes | 6 | ( module XMPPTypes |
7 | , module SocketLike | ||
7 | , listenForXmppClients | 8 | , listenForXmppClients |
8 | , listenForRemotePeers | 9 | , listenForRemotePeers |
9 | , seekRemotePeers | 10 | , seekRemotePeers |
@@ -675,8 +676,6 @@ connect' addr port = do | |||
675 | -} | 676 | -} |
676 | let getport (SockAddrInet port _) = port | 677 | let getport (SockAddrInet port _) = port |
677 | getport (SockAddrInet6 port _ _ _) = port | 678 | getport (SockAddrInet6 port _ _ _) = port |
678 | let withPort (SockAddrInet _ a) port = SockAddrInet (toEnum port) a | ||
679 | withPort (SockAddrInet6 _ a b c) port = SockAddrInet6 (toEnum port) a b c | ||
680 | let doException (SomeException e) = do | 679 | let doException (SomeException e) = do |
681 | L.putStrLn $ "\nFailed to reach "<++> showPeer (RemotePeer addr) <++> " on port "<++>bshow port<++>": " <++> bshow e | 680 | L.putStrLn $ "\nFailed to reach "<++> showPeer (RemotePeer addr) <++> " on port "<++>bshow port<++>": " <++> bshow e |
682 | return Nothing | 681 | return Nothing |
diff --git a/Presence/XMPPTypes.hs b/Presence/XMPPTypes.hs index 8af1018c..b46b4294 100644 --- a/Presence/XMPPTypes.hs +++ b/Presence/XMPPTypes.hs | |||
@@ -164,4 +164,8 @@ socketFamily (SockAddrInet _ _) = AF_INET | |||
164 | socketFamily (SockAddrInet6 _ _ _ _) = AF_INET6 | 164 | socketFamily (SockAddrInet6 _ _ _ _) = AF_INET6 |
165 | socketFamily (SockAddrUnix _) = AF_UNIX | 165 | socketFamily (SockAddrUnix _) = AF_UNIX |
166 | 166 | ||
167 | withPort (SockAddrInet _ a) port = SockAddrInet (toEnum port) a | ||
168 | withPort (SockAddrInet6 _ a b c) port = SockAddrInet6 (toEnum port) a b c | ||
169 | |||
170 | withoutPort = (`withPort` 0) | ||
167 | 171 | ||
diff --git a/Presence/main.hs b/Presence/main.hs index f17b8340..3182431f 100644 --- a/Presence/main.hs +++ b/Presence/main.hs | |||
@@ -56,6 +56,18 @@ import System.Environment | |||
56 | import qualified Text.Show.ByteString as L | 56 | import qualified Text.Show.ByteString as L |
57 | import Network.Socket (Family(AF_INET,AF_INET6)) | 57 | import Network.Socket (Family(AF_INET,AF_INET6)) |
58 | 58 | ||
59 | type RefCount = Int | ||
60 | |||
61 | data PresenceState = PresenceState | ||
62 | { hostname :: Peer -- ByteString, TODO: remove this, its always LocalHost now | ||
63 | , currentTTY :: TVar ByteString | ||
64 | , activeUsers :: TVar (Set JID) | ||
65 | , subscriberMap :: TVar (Map JID (RefCount,TChan Presence)) -- UNUSED as yet | ||
66 | , localSubscriber :: TMVar (RefCount,TChan Presence) -- TODO: rename this, its not just locals | ||
67 | -- ... or make a seperate channel for remotes | ||
68 | , remoteUsers :: TVar (Map Peer (RefCount,TVar (Set JID))) | ||
69 | } | ||
70 | |||
59 | 71 | ||
60 | data ClientSession = ClientSession { | 72 | data ClientSession = ClientSession { |
61 | localhost :: Peer, -- ByteString, | 73 | localhost :: Peer, -- ByteString, |
@@ -110,6 +122,7 @@ instance XMPPSession ClientSession where | |||
110 | 122 | ||
111 | data PeerSession = PeerSession { | 123 | data PeerSession = PeerSession { |
112 | announced :: TVar (Set JID), | 124 | announced :: TVar (Set JID), |
125 | peer_name :: Peer, | ||
113 | peer_global :: PresenceState | 126 | peer_global :: PresenceState |
114 | } | 127 | } |
115 | instance XMPPSession PeerSession where | 128 | instance XMPPSession PeerSession where |
@@ -120,15 +133,19 @@ instance XMPPSession PeerSession where | |||
120 | subscribe _ _ = error "subscribe on peer session?" | 133 | subscribe _ _ = error "subscribe on peer session?" |
121 | 134 | ||
122 | newSession (PeerSessions state) sock = do | 135 | newSession (PeerSessions state) sock = do |
123 | L.putStrLn $ "PEER SESSION: open" | 136 | me <- fmap (RemotePeer . withoutPort) (getPeerName sock) |
124 | jids <- newTVarIO Set.empty | 137 | L.putStrLn $ "PEER SESSION: open "<++>showPeer me |
125 | return $ PeerSession jids state | 138 | let remotes = remoteUsers state |
139 | jids <- atomically $ getRefFromMap remotes me (newTVar Set.empty) return | ||
140 | return $ PeerSession jids me state | ||
126 | 141 | ||
127 | closeSession session = do | 142 | closeSession session = do |
128 | L.putStrLn "PEER SESSION: close" | 143 | L.putStrLn $ "PEER SESSION: close "<++>showPeer (peer_name session) |
129 | js <- fmap Set.toList (readTVarIO . announced $ session) | ||
130 | let offline jid = Presence jid Offline | 144 | let offline jid = Presence jid Offline |
131 | forM_ js $ announcePresence session . offline | 145 | unrefFromMap (remoteUsers . peer_global $ session) (peer_name session) |
146 | $ do | ||
147 | js <- fmap Set.toList (readTVarIO . announced $ session) | ||
148 | forM_ js $ announcePresence session . offline | ||
132 | 149 | ||
133 | announcePresence session (Presence jid status) = do | 150 | announcePresence session (Presence jid status) = do |
134 | (greedy,subs) <- atomically $ do | 151 | (greedy,subs) <- atomically $ do |
@@ -153,19 +170,35 @@ subscribeToChan tmvar = | |||
153 | putTMVar tmvar (1,chan) | 170 | putTMVar tmvar (1,chan) |
154 | return chan ) | 171 | return chan ) |
155 | 172 | ||
156 | subscribeToMap tvar jid = do | 173 | getRefFromMap tvar key newObject copyObject = do |
157 | subs <- readTVar tvar | 174 | subs <- readTVar tvar |
158 | let mbchan = Map.lookup jid subs | 175 | let mbobject = Map.lookup key subs |
159 | (chan,subs') <- | 176 | (object,subs') <- |
160 | do case mbchan of | 177 | do case mbobject of |
161 | Nothing -> do | 178 | Nothing -> do |
162 | newchan <- newTChan | 179 | newobject <- newObject |
163 | return (newchan, Map.insert jid (1,newchan) subs) | 180 | return (newobject, Map.insert key (1,newobject) subs) |
164 | Just (cnt,chan) -> do | 181 | Just (cnt,object) -> do |
165 | chan' <- dupTChan chan | 182 | object' <- copyObject object |
166 | return (chan', Map.insert jid (cnt+1,chan) subs) | 183 | return (object', Map.insert key (cnt+1,object) subs) |
167 | writeTVar tvar subs' | 184 | writeTVar tvar subs' |
168 | return chan | 185 | return object |
186 | |||
187 | unrefFromMap tvar key finalizer = do | ||
188 | vanished <- atomically $ do | ||
189 | omap <- readTVar tvar | ||
190 | let (r,omap') = Map.updateLookupWithKey unref key omap | ||
191 | writeTVar tvar omap' | ||
192 | return (isNothing r) | ||
193 | when vanished finalizer | ||
194 | where | ||
195 | unref key (cnt,object) = | ||
196 | if cnt==1 then Nothing | ||
197 | else Just (cnt-1,object) | ||
198 | |||
199 | |||
200 | subscribeToMap tvar jid = | ||
201 | getRefFromMap tvar jid newTChan dupTChan | ||
169 | 202 | ||
170 | matchResource tty jid = maybe Away (avail . (==tty)) $ resource jid | 203 | matchResource tty jid = maybe Away (avail . (==tty)) $ resource jid |
171 | where | 204 | where |
@@ -188,23 +221,13 @@ update_presence locals_greedy subscribers state getStatus = | |||
188 | sendPresence chan jid status | 221 | sendPresence chan jid status |
189 | putStrLn $ bshow jid <++> " " <++> bshow status | 222 | putStrLn $ bshow jid <++> " " <++> bshow status |
190 | 223 | ||
191 | type RefCount = Int | ||
192 | |||
193 | data PresenceState = PresenceState | ||
194 | { hostname :: Peer -- ByteString, TODO: remove this, its always LocalHost now | ||
195 | , currentTTY :: TVar ByteString | ||
196 | , activeUsers :: TVar (Set JID) | ||
197 | , subscriberMap :: TVar (Map JID (RefCount,TChan Presence)) -- UNUSED as yet | ||
198 | , localSubscriber :: TMVar (RefCount,TChan Presence) -- TODO: rename this, its not just locals | ||
199 | -- ... or make a separte channel for remotes | ||
200 | } | ||
201 | |||
202 | newPresenceState hostname = atomically $ do | 224 | newPresenceState hostname = atomically $ do |
203 | tty <- newTVar "" | 225 | tty <- newTVar "" |
204 | us <- newTVar (Set.empty) | 226 | us <- newTVar (Set.empty) |
205 | subs <- newTVar (Map.empty) | 227 | subs <- newTVar (Map.empty) |
206 | locals_greedy <- newEmptyTMVar | 228 | locals_greedy <- newEmptyTMVar |
207 | return $ PresenceState hostname tty us subs locals_greedy | 229 | remotes <- newTVar (Map.empty) |
230 | return $ PresenceState hostname tty us subs locals_greedy remotes | ||
208 | 231 | ||
209 | track_login host state e = do | 232 | track_login host state e = do |
210 | #ifndef NOUTMP | 233 | #ifndef NOUTMP |