diff options
Diffstat (limited to 'Presence')
-rw-r--r-- | Presence/XMPPServer.hs | 117 |
1 files changed, 79 insertions, 38 deletions
diff --git a/Presence/XMPPServer.hs b/Presence/XMPPServer.hs index a9e7e336..45b89b3d 100644 --- a/Presence/XMPPServer.hs +++ b/Presence/XMPPServer.hs | |||
@@ -26,10 +26,11 @@ import Data.Conduit.Blaze (builderToByteStringFlush) | |||
26 | import qualified Text.XML.Stream.Render as XML | 26 | import qualified Text.XML.Stream.Render as XML |
27 | import qualified Text.XML.Stream.Parse as XML | 27 | import qualified Text.XML.Stream.Parse as XML |
28 | import Data.XML.Types as XML | 28 | import Data.XML.Types as XML |
29 | import Data.Maybe (catMaybes,fromJust) | 29 | import Data.Maybe (catMaybes,fromJust,isNothing) |
30 | import Data.Monoid ( (<>) ) | 30 | import Data.Monoid ( (<>) ) |
31 | import Data.Text (Text) | 31 | import Data.Text (Text) |
32 | import qualified Data.Text as Text (pack) | 32 | import qualified Data.Text as Text (pack) |
33 | import Data.Char (toUpper) | ||
33 | 34 | ||
34 | import qualified Control.Concurrent.STM.UpdateStream as Slotted | 35 | import qualified Control.Concurrent.STM.UpdateStream as Slotted |
35 | import ControlMaybe | 36 | import ControlMaybe |
@@ -40,6 +41,8 @@ import Server | |||
40 | peerport = 5269 | 41 | peerport = 5269 |
41 | clientport = 5222 | 42 | clientport = 5222 |
42 | 43 | ||
44 | my_uuid = "154ae29f-98f2-4af4-826d-a40c8a188574" | ||
45 | |||
43 | 46 | ||
44 | -- TODO: http://xmpp.org/rfcs/rfc6120.html#rules-remote-error | 47 | -- TODO: http://xmpp.org/rfcs/rfc6120.html#rules-remote-error |
45 | -- client connection | 48 | -- client connection |
@@ -89,12 +92,27 @@ type FlagCommand = STM Bool | |||
89 | type ReadCommand = IO (Maybe ByteString) | 92 | type ReadCommand = IO (Maybe ByteString) |
90 | type WriteCommand = ByteString -> IO Bool | 93 | type WriteCommand = ByteString -> IO Bool |
91 | 94 | ||
95 | {- | ||
92 | data Stanza | 96 | data Stanza |
93 | = UnrecognizedStanza { stanzaChan :: TChan (Maybe XML.Event) } | 97 | = UnrecognizedStanza { stanzaChan :: TChan (Maybe XML.Event) } |
94 | | PingStanza { stanzaId :: Maybe Text | 98 | | PingStanza { stanzaId :: Maybe Text |
95 | , stanzaChan :: TChan (Maybe XML.Event) } | 99 | , stanzaChan :: TChan (Maybe XML.Event) } |
96 | | PongStanza { -- stanzaId :: Maybe Text | 100 | | PongStanza { -- stanzaId :: Maybe Text |
97 | stanzaChan :: TChan (Maybe XML.Event) } | 101 | stanzaChan :: TChan (Maybe XML.Event) } |
102 | -} | ||
103 | |||
104 | data StanzaType = Unrecognized | Ping | Pong | ||
105 | deriving Show | ||
106 | |||
107 | data Stanza = Stanza | ||
108 | { stanzaType :: StanzaType | ||
109 | , stanzaId :: Maybe Text | ||
110 | , stanzaTo :: Maybe Text | ||
111 | , stanzaFrom :: Maybe Text | ||
112 | , stanzaChan :: TChan XML.Event | ||
113 | , stanzaClosers :: TVar (Maybe [XML.Event]) | ||
114 | , stanzaInterrupt :: TMVar () | ||
115 | } | ||
98 | 116 | ||
99 | copyToChannel f chan closer_stack = awaitForever copy | 117 | copyToChannel f chan closer_stack = awaitForever copy |
100 | where | 118 | where |
@@ -104,10 +122,10 @@ copyToChannel f chan closer_stack = awaitForever copy | |||
104 | EventBeginDocument {} -> do | 122 | EventBeginDocument {} -> do |
105 | let clsr = closerFor x | 123 | let clsr = closerFor x |
106 | liftIO . atomically $ | 124 | liftIO . atomically $ |
107 | modifyTVar' closer_stack (clsr:) | 125 | modifyTVar' closer_stack (fmap (clsr:)) |
108 | EventEndDocument {} -> do | 126 | EventEndDocument {} -> do |
109 | liftIO . atomically $ | 127 | liftIO . atomically $ |
110 | modifyTVar' closer_stack (drop 1) | 128 | modifyTVar' closer_stack (fmap (drop 1)) |
111 | _ -> return () | 129 | _ -> return () |
112 | yield x | 130 | yield x |
113 | 131 | ||
@@ -119,15 +137,12 @@ prettyPrint prefix xs = | |||
119 | =$= CB.lines | 137 | =$= CB.lines |
120 | $$ CL.mapM_ (wlogb . (prefix <>)) | 138 | $$ CL.mapM_ (wlogb . (prefix <>)) |
121 | 139 | ||
122 | grockStanzaIQGet :: Monad m => XML.Event -> NestingXML o m (Maybe (TChan (Maybe Event) -> Stanza)) | 140 | grockStanzaIQGet :: Monad m => XML.Event -> NestingXML o m (Maybe StanzaType) |
123 | grockStanzaIQGet stanza = do | 141 | grockStanzaIQGet stanza = do |
124 | let mid = lookupAttrib "id" (tagAttrs stanza) | ||
125 | -- mfrom = lookupAttrib "from" (tagAttrs stanza) | ||
126 | mtag <- nextElement | 142 | mtag <- nextElement |
127 | flip (maybe $ return Nothing) mtag $ \tag -> do | 143 | flip (maybe $ return Nothing) mtag $ \tag -> do |
128 | case tagName tag of | 144 | case tagName tag of |
129 | "{urn:xmpp:ping}ping" -> do | 145 | "{urn:xmpp:ping}ping" -> return $ Just Ping |
130 | return $ Just (PingStanza mid) | ||
131 | _ -> return Nothing | 146 | _ -> return Nothing |
132 | 147 | ||
133 | ioWriteChan c v = liftIO . atomically $ writeTChan c v | 148 | ioWriteChan c v = liftIO . atomically $ writeTChan c v |
@@ -146,33 +161,52 @@ xmppInbound k pingflag src stanzas output donevar = doNestingXML $ do | |||
146 | fix $ \loop -> do | 161 | fix $ \loop -> do |
147 | -- liftIO . wlog $ "waiting for stanza." | 162 | -- liftIO . wlog $ "waiting for stanza." |
148 | (chan,clsrs) <- liftIO . atomically $ | 163 | (chan,clsrs) <- liftIO . atomically $ |
149 | liftM2 (,) newTChan (newTVar []) | 164 | liftM2 (,) newTChan (newTVar (Just [])) |
150 | whenJust nextElement $ \stanza -> do | 165 | whenJust nextElement $ \stanzaTag -> do |
151 | stanza_lvl <- nesting | 166 | stanza_lvl <- nesting |
152 | liftIO . atomically $ do | 167 | liftIO . atomically $ do |
153 | writeTChan chan (Just stanza) | 168 | writeTChan chan stanzaTag |
154 | modifyTVar' clsrs (closerFor stanza:) | 169 | modifyTVar' clsrs (fmap (closerFor stanzaTag:)) |
155 | copyToChannel Just chan clsrs =$= do | 170 | copyToChannel id chan clsrs =$= do |
171 | let mid = lookupAttrib "id" (tagAttrs stanzaTag) | ||
172 | mfrom = lookupAttrib "from" (tagAttrs stanzaTag) | ||
173 | mto = lookupAttrib "to" (tagAttrs stanzaTag) | ||
156 | dispatch <- | 174 | dispatch <- |
157 | case () of | 175 | case () of |
158 | _ | stanza `isServerIQOf` "get" -> grockStanzaIQGet stanza | 176 | _ | stanzaTag `isServerIQOf` "get" -> grockStanzaIQGet stanzaTag |
159 | _ -> return $ Just UnrecognizedStanza | 177 | _ -> return $ Just Unrecognized |
160 | flip (maybe $ return ()) dispatch $ \dispatch -> | 178 | flip (maybe $ return ()) dispatch $ \dispatch -> |
161 | case dispatch chan of | 179 | case dispatch of |
162 | d@(PingStanza {}) -> do | 180 | Ping -> do |
163 | let to = "todo" | 181 | let to = maybe "todo" id mto |
164 | from = "todo" | 182 | from = maybe "todo" id mfrom |
165 | let pong = peerPong (stanzaId d) to from | 183 | let pong = peerPong mid to from |
166 | liftIO $ wlog "got ping, sending pong..." | 184 | -- liftIO $ wlog "got ping, sending pong..." |
167 | pongChan <- liftIO $ atomically newTChan | 185 | pongChan <- liftIO $ atomically newTChan |
168 | ioWriteChan output (PongStanza pongChan) | 186 | pongClsrs <- liftIO $ atomically $ newTVar (Just []) |
187 | ioWriteChan output $ Stanza { stanzaType = Pong | ||
188 | , stanzaId = mid | ||
189 | , stanzaTo = mto | ||
190 | , stanzaFrom = mfrom | ||
191 | , stanzaChan = pongChan | ||
192 | , stanzaClosers = pongClsrs | ||
193 | , stanzaInterrupt = donevar | ||
194 | } | ||
169 | void . liftIO . forkIO $ do | 195 | void . liftIO . forkIO $ do |
170 | mapM_ (ioWriteChan pongChan . Just) pong | 196 | mapM_ (ioWriteChan pongChan) pong |
171 | ioWriteChan pongChan Nothing | 197 | liftIO . atomically $ writeTVar pongClsrs Nothing |
172 | liftIO $ wlog "finished pong stanza" | 198 | -- liftIO $ wlog "finished pong stanza" |
173 | disp -> ioWriteChan stanzas disp | 199 | stype -> ioWriteChan stanzas Stanza |
200 | { stanzaType = stype | ||
201 | , stanzaId = mid | ||
202 | , stanzaTo = mto | ||
203 | , stanzaFrom = mfrom | ||
204 | , stanzaChan = chan | ||
205 | , stanzaClosers = clsrs | ||
206 | , stanzaInterrupt = donevar | ||
207 | } | ||
174 | awaitCloser stanza_lvl | 208 | awaitCloser stanza_lvl |
175 | ioWriteChan chan Nothing | 209 | liftIO . atomically $ writeTVar clsrs Nothing |
176 | loop | 210 | loop |
177 | 211 | ||
178 | 212 | ||
@@ -283,15 +317,20 @@ forkConnection k pingflag src snk stanzas = do | |||
283 | what <- atomically $ foldr1 orElse | 317 | what <- atomically $ foldr1 orElse |
284 | [readTChan output >>= \stanza -> return $ do | 318 | [readTChan output >>= \stanza -> return $ do |
285 | let xchan = stanzaChan stanza | 319 | let xchan = stanzaChan stanza |
320 | xfin = stanzaClosers stanza | ||
286 | fix $ \inner -> do | 321 | fix $ \inner -> do |
287 | what <- atomically $ orElse | 322 | what <- atomically $ foldr1 orElse |
288 | (readTChan xchan >>= \mxml -> return $ do | 323 | [readTChan xchan >>= \xml -> return $ do |
289 | case mxml of | 324 | atomically $ Slotted.push slots Nothing xml |
290 | Just xml -> do | 325 | inner |
291 | atomically $ Slotted.push slots Nothing xml | 326 | ,do mb <- readTVar xfin |
292 | inner | 327 | cempty <- isEmptyTChan xchan |
293 | Nothing -> loop) | 328 | if isNothing mb |
294 | (readTMVar rdone >> return (return ())) | 329 | then if cempty then return loop else retry |
330 | else retry -- todo: send closers | ||
331 | ,do isEmptyTChan xchan >>= check | ||
332 | readTMVar rdone | ||
333 | return (return ())] | ||
295 | what | 334 | what |
296 | ,do pingflag >>= check | 335 | ,do pingflag >>= check |
297 | return $ do | 336 | return $ do |
@@ -303,7 +342,7 @@ forkConnection k pingflag src snk stanzas = do | |||
303 | mapM_ (atomically . Slotted.push slots (Just $ PingSlot)) | 342 | mapM_ (atomically . Slotted.push slots (Just $ PingSlot)) |
304 | ping | 343 | ping |
305 | wlog "" | 344 | wlog "" |
306 | prettyPrint "P<- " ping | 345 | prettyPrint "P<-PING " ping |
307 | loop | 346 | loop |
308 | ,readTMVar rdone >> return (return ()) | 347 | ,readTMVar rdone >> return (return ()) |
309 | ] | 348 | ] |
@@ -363,9 +402,11 @@ monitor sv params = do | |||
363 | RequiresPing -> return () -- wlog $ tomsg k "RequiresPing" | 402 | RequiresPing -> return () -- wlog $ tomsg k "RequiresPing" |
364 | _ -> return () | 403 | _ -> return () |
365 | , readTChan stanzas >>= \stanza -> return $ do | 404 | , readTChan stanzas >>= \stanza -> return $ do |
366 | xs <- readUntilNothing (stanzaChan stanza) | 405 | -- xs <- readUntilNothing (stanzaChan stanza) |
406 | xs <- chanContents (stanzaChan stanza) | ||
407 | let typ = Strict8.pack $ "P->"++(show (stanzaType stanza))++" " | ||
367 | wlog "" | 408 | wlog "" |
368 | prettyPrint "P-> " xs | 409 | prettyPrint typ xs |
369 | ] | 410 | ] |
370 | action | 411 | action |
371 | loop | 412 | loop |