summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjoe <joe@jerkface.net>2014-02-12 20:35:52 -0500
committerjoe <joe@jerkface.net>2014-02-12 20:35:52 -0500
commit7ccaa169bc2309df7df2db118dd646177867f2b0 (patch)
tree82b5e8f7e744f7d919b49ebcb0b0654def7d7d32
parent5ad7794bcd86a0049d1e62cae2f04f6088a0ef34 (diff)
Reply to pings with pongs.
-rw-r--r--Data/Conduit/Lift.hs526
-rw-r--r--Presence/EventUtil.hs34
-rw-r--r--Presence/Nesting.hs79
-rw-r--r--xmppServer.hs64
4 files changed, 689 insertions, 14 deletions
diff --git a/Data/Conduit/Lift.hs b/Data/Conduit/Lift.hs
new file mode 100644
index 00000000..341fce53
--- /dev/null
+++ b/Data/Conduit/Lift.hs
@@ -0,0 +1,526 @@
1
2
3{-# LANGUAGE RankNTypes #-}
4-- | Allow monad transformers to be run/eval/exec in a section of conduit
5-- rather then needing to run across the whole conduit. The circumvents many
6-- of the problems with breaking the monad transformer laws. For more
7-- information, see the announcement blog post:
8-- <http://www.yesodweb.com/blog/2014/01/conduit-transformer-exception>
9--
10-- This module was added in conduit 1.0.11.
11module Data.Conduit.Lift (
12 -- * ErrorT
13 errorC,
14 runErrorC,
15 catchErrorC,
16-- liftCatchError,
17
18 -- * MaybeT
19 maybeC,
20 runMaybeC,
21
22 -- * ReaderT
23 readerC,
24 runReaderC,
25
26 -- * StateT
27 stateC,
28 runStateC,
29 evalStateC,
30 execStateC,
31
32 -- ** Strict
33 stateSC,
34 runStateSC,
35 evalStateSC,
36 execStateSC,
37
38 -- * WriterT
39 writerC,
40 runWriterC,
41 execWriterC,
42
43 -- ** Strict
44 writerSC,
45 runWriterSC,
46 execWriterSC,
47
48 -- * RWST
49 rwsC,
50 runRWSC,
51 evalRWSC,
52 execRWSC,
53
54 -- ** Strict
55 rwsSC,
56 runRWSSC,
57 evalRWSSC,
58 execRWSSC,
59
60 -- * Utilities
61
62 distribute
63 ) where
64
65import Data.Conduit
66import Data.Conduit.Internal (ConduitM (..), Pipe (..))
67
68import Control.Monad.Morph (hoist, lift, MFunctor(..), )
69import Control.Monad.Trans.Class (MonadTrans(..))
70
71import Data.Monoid (Monoid(..))
72
73
74import qualified Control.Monad.Trans.Error as E
75import qualified Control.Monad.Trans.Maybe as M
76import qualified Control.Monad.Trans.Reader as R
77
78import qualified Control.Monad.Trans.State.Strict as SS
79import qualified Control.Monad.Trans.Writer.Strict as WS
80import qualified Control.Monad.Trans.RWS.Strict as RWSS
81
82import qualified Control.Monad.Trans.State.Lazy as SL
83import qualified Control.Monad.Trans.Writer.Lazy as WL
84import qualified Control.Monad.Trans.RWS.Lazy as RWSL
85
86
87catAwaitLifted
88 :: (Monad (t (ConduitM o1 o m)), Monad m, MonadTrans t) =>
89 ConduitM i o1 (t (ConduitM o1 o m)) ()
90catAwaitLifted = go
91 where
92 go = do
93 x <- lift . lift $ await
94 case x of
95 Nothing -> return ()
96 Just x2 -> do
97 yield x2
98 go
99
100catYieldLifted
101 :: (Monad (t (ConduitM i o1 m)), Monad m, MonadTrans t) =>
102 ConduitM o1 o (t (ConduitM i o1 m)) ()
103catYieldLifted = go
104 where
105 go = do
106 x <- await
107 case x of
108 Nothing -> return ()
109 Just x2 -> do
110 lift . lift $ yield x2
111 go
112
113
114distribute
115 :: (Monad (t (ConduitM b o m)), Monad m, Monad (t m), MonadTrans t,
116 MFunctor t) =>
117 ConduitM b o (t m) () -> t (ConduitM b o m) ()
118distribute p = catAwaitLifted =$= hoist (hoist lift) p $$ catYieldLifted
119
120-- | Run 'E.ErrorT' in the base monad
121--
122-- Since 1.0.11
123errorC
124 :: (Monad m, Monad (t (E.ErrorT e m)), MonadTrans t, E.Error e,
125 MFunctor t) =>
126 t m (Either e b) -> t (E.ErrorT e m) b
127errorC p = do
128 x <- hoist lift p
129 lift $ E.ErrorT (return x)
130
131-- | Run 'E.ErrorT' in the base monad
132--
133-- Since 1.0.11
134runErrorC
135 :: (Monad m, E.Error e) =>
136 ConduitM i o (E.ErrorT e m) r -> ConduitM i o m (Either e r)
137runErrorC =
138 ConduitM . go . unConduitM
139 where
140 go (Done r) = Done (Right r)
141 go (PipeM mp) = PipeM $ do
142 eres <- E.runErrorT mp
143 return $ case eres of
144 Left e -> Done $ Left e
145 Right p -> go p
146 go (Leftover p i) = Leftover (go p) i
147 go (HaveOutput p f o) = HaveOutput (go p) (E.runErrorT f >> return ()) o
148 go (NeedInput x y) = NeedInput (go . x) (go . y)
149{-# INLINABLE runErrorC #-}
150
151-- | Catch an error in the base monad
152--
153-- Since 1.0.11
154catchErrorC
155 :: (Monad m, E.Error e) =>
156 ConduitM i o (E.ErrorT e m) r
157 -> (e -> ConduitM i o (E.ErrorT e m) r)
158 -> ConduitM i o (E.ErrorT e m) r
159catchErrorC c0 h =
160 ConduitM $ go $ unConduitM c0
161 where
162 go (Done r) = Done r
163 go (PipeM mp) = PipeM $ do
164 eres <- lift $ E.runErrorT mp
165 return $ case eres of
166 Left e -> unConduitM $ h e
167 Right p -> go p
168 go (Leftover p i) = Leftover (go p) i
169 go (HaveOutput p f o) = HaveOutput (go p) f o
170 go (NeedInput x y) = NeedInput (go . x) (go . y)
171{-# INLINABLE catchErrorC #-}
172
173-- | Wrap the base monad in 'M.MaybeT'
174--
175-- Since 1.0.11
176maybeC
177 :: (Monad m, Monad (t (M.MaybeT m)),
178 MonadTrans t,
179 MFunctor t) =>
180 t m (Maybe b) -> t (M.MaybeT m) b
181maybeC p = do
182 x <- hoist lift p
183 lift $ M.MaybeT (return x)
184{-# INLINABLE maybeC #-}
185
186-- | Run 'M.MaybeT' in the base monad
187--
188-- Since 1.0.11
189runMaybeC
190 :: Monad m =>
191 ConduitM i o (M.MaybeT m) r -> ConduitM i o m (Maybe r)
192runMaybeC =
193 ConduitM . go . unConduitM
194 where
195 go (Done r) = Done (Just r)
196 go (PipeM mp) = PipeM $ do
197 mres <- M.runMaybeT mp
198 return $ case mres of
199 Nothing -> Done Nothing
200 Just p -> go p
201 go (Leftover p i) = Leftover (go p) i
202 go (HaveOutput p c o) = HaveOutput (go p) (M.runMaybeT c >> return ()) o
203 go (NeedInput x y) = NeedInput (go . x) (go . y)
204{-# INLINABLE runMaybeC #-}
205
206-- | Wrap the base monad in 'R.ReaderT'
207--
208-- Since 1.0.11
209readerC
210 :: (Monad m, Monad (t1 (R.ReaderT t m)),
211 MonadTrans t1,
212 MFunctor t1) =>
213 (t -> t1 m b) -> t1 (R.ReaderT t m) b
214readerC k = do
215 i <- lift R.ask
216 hoist lift (k i)
217{-# INLINABLE readerC #-}
218
219-- | Run 'R.ReaderT' in the base monad
220--
221-- Since 1.0.11
222runReaderC
223 :: Monad m =>
224 r -> ConduitM i o (R.ReaderT r m) res -> ConduitM i o m res
225runReaderC r = hoist (`R.runReaderT` r)
226{-# INLINABLE runReaderC #-}
227
228
229-- | Wrap the base monad in 'SL.StateT'
230--
231-- Since 1.0.11
232stateC
233 :: (Monad m, Monad (t1 (SL.StateT t m)),
234 MonadTrans t1,
235 MFunctor t1) =>
236 (t -> t1 m (b, t)) -> t1 (SL.StateT t m) b
237stateC k = do
238 s <- lift SL.get
239 (r, s') <- hoist lift (k s)
240 lift (SL.put s')
241 return r
242{-# INLINABLE stateC #-}
243
244thread :: Monad m
245 => (r -> s -> res)
246 -> (forall a. t m a -> s -> m (a, s))
247 -> s
248 -> ConduitM i o (t m) r
249 -> ConduitM i o m res
250thread toRes runM s0 =
251 ConduitM . go s0 . unConduitM
252 where
253 go s (Done r) = Done (toRes r s)
254 go s (PipeM mp) = PipeM $ do
255 (p, s') <- runM mp s
256 return $ go s' p
257 go s (Leftover p i) = Leftover (go s p) i
258 go s (NeedInput x y) = NeedInput (go s . x) (go s . y)
259 go s (HaveOutput p f o) = HaveOutput (go s p) (runM f s >> return ()) o
260{-# INLINABLE thread #-}
261
262-- | Run 'SL.StateT' in the base monad
263--
264-- Since 1.0.11
265runStateC
266 :: Monad m =>
267 s -> ConduitM i o (SL.StateT s m) r -> ConduitM i o m (r, s)
268runStateC = thread (,) SL.runStateT
269{-# INLINABLE runStateC #-}
270
271-- | Evaluate 'SL.StateT' in the base monad
272--
273-- Since 1.0.11
274evalStateC
275 :: Monad m =>
276 s -> ConduitM i o (SL.StateT s m) r -> ConduitM i o m r
277evalStateC s p = fmap fst $ runStateC s p
278{-# INLINABLE evalStateC #-}
279
280-- | Execute 'SL.StateT' in the base monad
281--
282-- Since 1.0.11
283execStateC
284 :: Monad m =>
285 s -> ConduitM i o (SL.StateT s m) r -> ConduitM i o m s
286execStateC s p = fmap snd $ runStateC s p
287{-# INLINABLE execStateC #-}
288
289
290-- | Wrap the base monad in 'SS.StateT'
291--
292-- Since 1.0.11
293stateSC
294 :: (Monad m, Monad (t1 (SS.StateT t m)),
295 MonadTrans t1,
296 MFunctor t1) =>
297 (t -> t1 m (b, t)) -> t1 (SS.StateT t m) b
298stateSC k = do
299 s <- lift SS.get
300 (r, s') <- hoist lift (k s)
301 lift (SS.put s')
302 return r
303{-# INLINABLE stateSC #-}
304
305-- | Run 'SS.StateT' in the base monad
306--
307-- Since 1.0.11
308runStateSC
309 :: Monad m =>
310 s -> ConduitM i o (SS.StateT s m) r -> ConduitM i o m (r, s)
311runStateSC = thread (,) SS.runStateT
312{-# INLINABLE runStateSC #-}
313
314-- | Evaluate 'SS.StateT' in the base monad
315--
316-- Since 1.0.11
317evalStateSC
318 :: Monad m =>
319 s -> ConduitM i o (SS.StateT s m) r -> ConduitM i o m r
320evalStateSC s p = fmap fst $ runStateSC s p
321{-# INLINABLE evalStateSC #-}
322
323-- | Execute 'SS.StateT' in the base monad
324--
325-- Since 1.0.11
326execStateSC
327 :: Monad m =>
328 s -> ConduitM i o (SS.StateT s m) r -> ConduitM i o m s
329execStateSC s p = fmap snd $ runStateSC s p
330{-# INLINABLE execStateSC #-}
331
332
333-- | Wrap the base monad in 'WL.WriterT'
334--
335-- Since 1.0.11
336writerC
337 :: (Monad m, Monad (t (WL.WriterT w m)), MonadTrans t, Monoid w,
338 MFunctor t) =>
339 t m (b, w) -> t (WL.WriterT w m) b
340writerC p = do
341 (r, w) <- hoist lift p
342 lift $ WL.tell w
343 return r
344{-# INLINABLE writerC #-}
345
346-- | Run 'WL.WriterT' in the base monad
347--
348-- Since 1.0.11
349runWriterC
350 :: (Monad m, Monoid w) =>
351 ConduitM i o (WL.WriterT w m) r -> ConduitM i o m (r, w)
352runWriterC = thread (,) run mempty
353 where
354 run m w = do
355 (a, w') <- WL.runWriterT m
356 return (a, w `mappend` w')
357{-# INLINABLE runWriterC #-}
358
359-- | Execute 'WL.WriterT' in the base monad
360--
361-- Since 1.0.11
362execWriterC
363 :: (Monad m, Monoid w) =>
364 ConduitM i o (WL.WriterT w m) r -> ConduitM i o m w
365execWriterC p = fmap snd $ runWriterC p
366{-# INLINABLE execWriterC #-}
367
368
369-- | Wrap the base monad in 'WS.WriterT'
370--
371-- Since 1.0.11
372writerSC
373 :: (Monad m, Monad (t (WS.WriterT w m)), MonadTrans t, Monoid w,
374 MFunctor t) =>
375 t m (b, w) -> t (WS.WriterT w m) b
376writerSC p = do
377 (r, w) <- hoist lift p
378 lift $ WS.tell w
379 return r
380{-# INLINABLE writerSC #-}
381
382-- | Run 'WS.WriterT' in the base monad
383--
384-- Since 1.0.11
385runWriterSC
386 :: (Monad m, Monoid w) =>
387 ConduitM i o (WS.WriterT w m) r -> ConduitM i o m (r, w)
388runWriterSC = thread (,) run mempty
389 where
390 run m w = do
391 (a, w') <- WS.runWriterT m
392 return (a, w `mappend` w')
393{-# INLINABLE runWriterSC #-}
394
395-- | Execute 'WS.WriterT' in the base monad
396--
397-- Since 1.0.11
398execWriterSC
399 :: (Monad m, Monoid w) =>
400 ConduitM i o (WS.WriterT w m) r -> ConduitM i o m w
401execWriterSC p = fmap snd $ runWriterSC p
402{-# INLINABLE execWriterSC #-}
403
404
405-- | Wrap the base monad in 'RWSL.RWST'
406--
407-- Since 1.0.11
408rwsC
409 :: (Monad m, Monad (t1 (RWSL.RWST t w t2 m)), MonadTrans t1,
410 Monoid w, MFunctor t1) =>
411 (t -> t2 -> t1 m (b, t2, w)) -> t1 (RWSL.RWST t w t2 m) b
412rwsC k = do
413 i <- lift RWSL.ask
414 s <- lift RWSL.get
415 (r, s', w) <- hoist lift (k i s)
416 lift $ do
417 RWSL.put s'
418 RWSL.tell w
419 return r
420{-# INLINABLE rwsC #-}
421
422-- | Run 'RWSL.RWST' in the base monad
423--
424-- Since 1.0.11
425runRWSC
426 :: (Monad m, Monoid w) =>
427 r
428 -> s
429 -> ConduitM i o (RWSL.RWST r w s m) res
430 -> ConduitM i o m (res, s, w)
431runRWSC r s0 = thread toRes run (s0, mempty)
432 where
433 toRes a (s, w) = (a, s, w)
434 run m (s, w) = do
435 (res, s', w') <- RWSL.runRWST m r s
436 return (res, (s', w `mappend` w'))
437{-# INLINABLE runRWSC #-}
438
439-- | Evaluate 'RWSL.RWST' in the base monad
440--
441-- Since 1.0.11
442evalRWSC
443 :: (Monad m, Monoid w) =>
444 r
445 -> s
446 -> ConduitM i o (RWSL.RWST r w s m) res
447 -> ConduitM i o m (res, w)
448evalRWSC i s p = fmap f $ runRWSC i s p
449 where f x = let (r, _, w) = x in (r, w)
450{-# INLINABLE evalRWSC #-}
451
452-- | Execute 'RWSL.RWST' in the base monad
453--
454-- Since 1.0.11
455execRWSC
456 :: (Monad m, Monoid w) =>
457 r
458 -> s
459 -> ConduitM i o (RWSL.RWST r w s m) res
460 -> ConduitM i o m (s, w)
461execRWSC i s p = fmap f $ runRWSC i s p
462 where f x = let (_, s2, w2) = x in (s2, w2)
463{-# INLINABLE execRWSC #-}
464
465
466-- | Wrap the base monad in 'RWSS.RWST'
467--
468-- Since 1.0.11
469rwsSC
470 :: (Monad m, Monad (t1 (RWSS.RWST t w t2 m)), MonadTrans t1,
471 Monoid w, MFunctor t1) =>
472 (t -> t2 -> t1 m (b, t2, w)) -> t1 (RWSS.RWST t w t2 m) b
473rwsSC k = do
474 i <- lift RWSS.ask
475 s <- lift RWSS.get
476 (r, s', w) <- hoist lift (k i s)
477 lift $ do
478 RWSS.put s'
479 RWSS.tell w
480 return r
481{-# INLINABLE rwsSC #-}
482
483-- | Run 'RWSS.RWST' in the base monad
484--
485-- Since 1.0.11
486runRWSSC
487 :: (Monad m, Monoid w) =>
488 r
489 -> s
490 -> ConduitM i o (RWSS.RWST r w s m) res
491 -> ConduitM i o m (res, s, w)
492runRWSSC r s0 = thread toRes run (s0, mempty)
493 where
494 toRes a (s, w) = (a, s, w)
495 run m (s, w) = do
496 (res, s', w') <- RWSS.runRWST m r s
497 return (res, (s', w `mappend` w'))
498{-# INLINABLE runRWSSC #-}
499
500-- | Evaluate 'RWSS.RWST' in the base monad
501--
502-- Since 1.0.11
503evalRWSSC
504 :: (Monad m, Monoid w) =>
505 r
506 -> s
507 -> ConduitM i o (RWSS.RWST r w s m) res
508 -> ConduitM i o m (res, w)
509evalRWSSC i s p = fmap f $ runRWSSC i s p
510 where f x = let (r, _, w) = x in (r, w)
511{-# INLINABLE evalRWSSC #-}
512
513-- | Execute 'RWSS.RWST' in the base monad
514--
515-- Since 1.0.11
516execRWSSC
517 :: (Monad m, Monoid w) =>
518 r
519 -> s
520 -> ConduitM i o (RWSS.RWST r w s m) res
521 -> ConduitM i o m (s, w)
522execRWSSC i s p = fmap f $ runRWSSC i s p
523 where f x = let (_, s2, w2) = x in (s2, w2)
524{-# INLINABLE execRWSSC #-}
525
526
diff --git a/Presence/EventUtil.hs b/Presence/EventUtil.hs
index e62f8afc..bdea9fa2 100644
--- a/Presence/EventUtil.hs
+++ b/Presence/EventUtil.hs
@@ -3,6 +3,7 @@ module EventUtil where
3 3
4import Control.Monad 4import Control.Monad
5import Data.XML.Types as XML 5import Data.XML.Types as XML
6import qualified Data.List as List
6 7
7getStreamName (EventBeginElement name _) = name 8getStreamName (EventBeginElement name _) = name
8 9
@@ -21,3 +22,36 @@ elementAttrs _ _ = mzero
21streamP name = Name name (Just "http://etherx.jabber.org/streams") (Just "stream") 22streamP name = Name name (Just "http://etherx.jabber.org/streams") (Just "stream")
22 23
23attr name value = (name,[ContentText value]) 24attr name value = (name,[ContentText value])
25
26isServerIQOf (EventBeginElement name attrs) testType
27 | name=="{jabber:server}iq"
28 && matchAttrib "type" testType attrs
29 = True
30isServerIQOf _ _ = False
31
32matchAttrib name value attrs =
33 case List.find ( (==name) . fst) attrs of
34 Just (_,[ContentText x]) | x==value -> True
35 Just (_,[ContentEntity x]) | x==value -> True
36 _ -> False
37
38lookupAttrib name attrs =
39 case List.find ( (==name) . fst) attrs of
40 Just (_,[ContentText x]) -> Just x
41 Just (_,[ContentEntity x]) -> Just x
42 _ -> Nothing
43
44tagAttrs (EventBeginElement _ xs) = xs
45tagAttrs _ = []
46
47
48{-
49iqTypeSet = "set"
50iqTypeGet = "get"
51iqTypeResult = "result"
52iqTypeError = "error"
53-}
54
55
56tagName (EventBeginElement n _) = n
57tagName _ = ""
diff --git a/Presence/Nesting.hs b/Presence/Nesting.hs
new file mode 100644
index 00000000..24f9baad
--- /dev/null
+++ b/Presence/Nesting.hs
@@ -0,0 +1,79 @@
1{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE FlexibleContexts #-}
3module Nesting where
4
5import Data.Conduit
6import Data.Conduit.Lift
7import Data.XML.Types
8import qualified Data.Text as S
9import Control.Monad.State
10import qualified Data.List as List
11
12type Lang = S.Text
13
14data StrictList a = a :! !(StrictList a) | StrictNil
15
16data XMLState = XMLState {
17 nestingLevel :: Int,
18 langStack :: StrictList (Int,Lang)
19}
20
21type NestingXML o m a = ConduitM Event o (StateT XMLState m) a
22
23doNestingXML :: Monad m => NestingXML o m r -> ConduitM Event o m r
24doNestingXML m =
25 evalStateC (XMLState 0 StrictNil) (trackNesting =$= m)
26
27nesting :: Monad m => NestingXML o m Int
28nesting = lift $ (return . nestingLevel) =<< get
29
30
31trackNesting :: Monad m => ConduitM Event Event (StateT XMLState m) ()
32trackNesting = awaitForever doit
33 where
34 doit xml = do
35 XMLState lvl langs <- lift get
36 lift . put $ case xml of
37 EventBeginElement _ attrs ->
38 case lookupLang attrs of
39 Nothing -> XMLState (lvl+1) langs
40 Just lang -> XMLState (lvl+1) ( (lvl+1,lang) :! langs)
41 EventEndElement _ ->
42 case langs of
43 (llvl,_) :! ls | llvl==lvl -> XMLState (lvl-1) ls
44 _ | otherwise -> XMLState (lvl-1) langs
45 _ -> XMLState lvl langs
46 yield xml
47
48
49lookupLang attrs =
50 case List.find ( (=="xml:lang") . fst) attrs of
51 Just (_,[ContentText x]) -> Just x
52 Just (_,[ContentEntity x]) -> Just x
53 _ -> Nothing
54
55
56awaitCloser :: Monad m => Int -> NestingXML o m ()
57awaitCloser lvl = do
58 fix $ \loop -> do
59 lvl' <- nesting
60 when (lvl' >= lvl) $ do
61 xml <- await
62 maybe (return ()) (const loop) xml
63
64withXML f = await >>= maybe (return ()) f
65
66nextElement :: Monad m => NestingXML o m (Maybe Event)
67nextElement = do
68 lvl <- nesting
69 fix $ \loop -> do
70 xml <- await
71 case xml of
72 Nothing -> return Nothing
73 Just (EventBeginElement _ _) -> do
74 return xml
75 Just _ -> do
76 lvl' <- nesting
77 if (lvl'>=lvl) then loop
78 else return Nothing
79
diff --git a/xmppServer.hs b/xmppServer.hs
index 85e0cb5c..f91c20ce 100644
--- a/xmppServer.hs
+++ b/xmppServer.hs
@@ -23,14 +23,14 @@ import Data.Conduit.Blaze (builderToByteStringFlush)
23import qualified Text.XML.Stream.Render as XML 23import qualified Text.XML.Stream.Render as XML
24import qualified Text.XML.Stream.Parse as XML 24import qualified Text.XML.Stream.Parse as XML
25import Data.XML.Types as XML 25import Data.XML.Types as XML
26import Data.Maybe (catMaybes) 26import Data.Maybe (catMaybes,fromJust)
27import Data.Monoid ( (<>) ) 27import Data.Monoid ( (<>) )
28import Data.Text (Text) 28import Data.Text (Text)
29import qualified Data.Text as Text (pack) 29import qualified Data.Text as Text (pack)
30 30
31import qualified Control.Concurrent.STM.UpdateStream as Slotted 31import qualified Control.Concurrent.STM.UpdateStream as Slotted
32import ControlMaybe 32import ControlMaybe
33import NestingXML 33import Nesting
34import EventUtil 34import EventUtil
35import Server 35import Server
36 36
@@ -80,6 +80,17 @@ type WriteCommand = ByteString -> IO Bool
80 80
81data Stanza 81data Stanza
82 = UnrecognizedStanza { stanzaChan :: TChan (Maybe XML.Event) } 82 = UnrecognizedStanza { stanzaChan :: TChan (Maybe XML.Event) }
83 | PingStanza { stanzaId :: Maybe Text
84 , stanzaChan :: TChan (Maybe XML.Event) }
85 | PongStanza { -- stanzaId :: Maybe Text
86 stanzaChan :: TChan (Maybe XML.Event) }
87
88copyToChannel f chan = awaitForever copy
89 where
90 copy x = do
91 liftIO . atomically $ writeTChan chan (f x)
92 yield x
93
83 94
84prettyPrint prefix xs = 95prettyPrint prefix xs =
85 liftIO $ 96 liftIO $
@@ -88,6 +99,19 @@ prettyPrint prefix xs =
88 =$= CB.lines 99 =$= CB.lines
89 $$ CL.mapM_ (wlogb . (prefix <>)) 100 $$ CL.mapM_ (wlogb . (prefix <>))
90 101
102grockStanzaIQGet :: Monad m => XML.Event -> NestingXML o m (Maybe (TChan (Maybe Event) -> Stanza))
103grockStanzaIQGet stanza = do
104 let mid = lookupAttrib "id" (tagAttrs stanza)
105 -- mfrom = lookupAttrib "from" (tagAttrs stanza)
106 mtag <- nextElement
107 flip (maybe $ return Nothing) mtag $ \tag -> do
108 case tagName tag of
109 "{urn:xmpp:ping}ping" -> do
110 return $ Just (PingStanza mid)
111 _ -> return Nothing
112
113ioWriteChan c v = liftIO . atomically $ writeTChan c v
114
91xmppInbound :: ConnectionKey -> FlagCommand 115xmppInbound :: ConnectionKey -> FlagCommand
92 -> Source IO XML.Event 116 -> Source IO XML.Event
93 -> TChan Stanza 117 -> TChan Stanza
@@ -99,18 +123,30 @@ xmppInbound k pingflag src stanzas output = doNestingXML $ do
99 whenJust nextElement $ \xml -> do 123 whenJust nextElement $ \xml -> do
100 withJust (elementAttrs "stream" xml) $ \stream_attrs -> do 124 withJust (elementAttrs "stream" xml) $ \stream_attrs -> do
101 fix $ \loop -> do 125 fix $ \loop -> do
102 -- liftIO . wlog $ "waiting for stanza." 126 -- liftIO . wlog $ "waiting for stanza."
103 chan <- liftIO $ atomically newTChan 127 chan <- liftIO $ atomically newTChan
104 whenJust nextElement $ \stanza -> do 128 whenJust nextElement $ \stanza -> do
105 stanza_lvl <- nesting 129 stanza_lvl <- nesting
106 liftIO . atomically $ writeTChan chan (Just stanza) 130 ioWriteChan chan (Just stanza)
107 131 copyToChannel Just chan =$= do
108 liftIO . atomically $ writeTChan stanzas $ 132 dispatch <-
109 UnrecognizedStanza chan 133 case () of
110 doUntilCloser stanza_lvl $ \xml -> do 134 _ | stanza `isServerIQOf` "get" -> grockStanzaIQGet stanza
111 liftIO . atomically $ writeTChan chan (Just xml) 135 _ -> return $ Just UnrecognizedStanza
112 liftIO . atomically $ writeTChan chan Nothing 136 flip (maybe $ return ()) dispatch $ \dispatch ->
113 loop 137 case dispatch chan of
138 d@(PingStanza {}) -> do
139 let to = "todo"
140 from = "todo"
141 let pong = peerPong (stanzaId d) to from
142 pongChan <- liftIO $ atomically newTChan
143 ioWriteChan output (PongStanza pongChan)
144 mapM_ (ioWriteChan pongChan . Just) pong
145 ioWriteChan pongChan Nothing
146 disp -> ioWriteChan stanzas disp
147 awaitCloser stanza_lvl
148 ioWriteChan chan Nothing
149 loop
114 150
115 151
116chanContents :: TChan x -> IO [x] 152chanContents :: TChan x -> IO [x]