summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Presence/XMPP.hs3
-rw-r--r--Presence/XMPPTypes.hs4
-rw-r--r--Presence/main.hs85
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 #-}
5module XMPP 5module 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
164socketFamily (SockAddrInet6 _ _ _ _) = AF_INET6 164socketFamily (SockAddrInet6 _ _ _ _) = AF_INET6
165socketFamily (SockAddrUnix _) = AF_UNIX 165socketFamily (SockAddrUnix _) = AF_UNIX
166 166
167withPort (SockAddrInet _ a) port = SockAddrInet (toEnum port) a
168withPort (SockAddrInet6 _ a b c) port = SockAddrInet6 (toEnum port) a b c
169
170withoutPort = (`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
56import qualified Text.Show.ByteString as L 56import qualified Text.Show.ByteString as L
57import Network.Socket (Family(AF_INET,AF_INET6)) 57import Network.Socket (Family(AF_INET,AF_INET6))
58 58
59type RefCount = Int
60
61data 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
60data ClientSession = ClientSession { 72data ClientSession = ClientSession {
61 localhost :: Peer, -- ByteString, 73 localhost :: Peer, -- ByteString,
@@ -110,6 +122,7 @@ instance XMPPSession ClientSession where
110 122
111data PeerSession = PeerSession { 123data 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}
115instance XMPPSession PeerSession where 128instance 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
156subscribeToMap tvar jid = do 173getRefFromMap 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
187unrefFromMap 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
200subscribeToMap tvar jid =
201 getRefFromMap tvar jid newTChan dupTChan
169 202
170matchResource tty jid = maybe Away (avail . (==tty)) $ resource jid 203matchResource 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
191type RefCount = Int
192
193data 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
202newPresenceState hostname = atomically $ do 224newPresenceState 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
209track_login host state e = do 232track_login host state e = do
210#ifndef NOUTMP 233#ifndef NOUTMP