summaryrefslogtreecommitdiff
path: root/xmppServer.hs
blob: c720ea5f65e872a6156630e80958726a9fda32c7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import Control.Monad.Trans.Resource (runResourceT)
import Control.Monad.Trans (lift)
import Control.Monad.Fix (fix)
import Control.Concurrent (forkIO)
import Control.Concurrent.STM
-- import Control.Concurrent.STM.TChan
import Network.Socket
import XMPPTypes (withPort)
import Text.Printf
import System.Posix.Signals

import Data.Conduit

import qualified Text.XML.Stream.Render as XML
import qualified Text.XML.Stream.Parse as XML

import Server

wlog s = putStrLn s

control sv = atomically . putTMVar (serverCommand sv)

xmlStream conread conwrite = (xsrc,xsnk)
 where
    xsrc = src $= XML.parseBytes XML.def
    xsnk = XML.renderBytes XML.def =$ snk

    src = do
        v <- lift conread
        maybe (return ()) -- lift . wlog $ "conread: Nothing")
              (\v -> yield v >> src)
              v
    snk = awaitForever $ lift . conwrite
        

forkConnection k pingflag src snk = do
    forkIO $ do
        src $$ awaitForever (lift . putStrLn . takeWhile (/=' ') . show)
        wlog $ "end fork: " ++ show k
    return ()

monitor sv params = do
    chan <- return $ serverEvent sv
    fix $ \loop -> do
    (k,e) <- atomically $ readTChan chan
    case e of
        Connection pingflag conread conwrite -> do
             let (xsrc,xsnk) = xmlStream conread conwrite
             forkConnection k pingflag xsrc xsnk
             wlog $ tomsg k "Connection"
        EOF        -> wlog $ tomsg k "EOF"
        HalfConnection In -> do
            wlog $ tomsg k "ReadOnly"
            control sv (Connect (callBackAddress k) params)
        HalfConnection Out -> wlog $ tomsg k "WriteOnly"
        RequiresPing -> wlog $ tomsg k "RequiresPing"
        _ -> return ()
    loop
 where
    tomsg k str =  printf "%12s %s" str (show k)

data ConnectionKey
       = PeerKey { callBackAddress :: SockAddr }
       | ClientKey { localAddress :: SockAddr }
 deriving (Show, Ord, Eq)

peerKey (sock,addr) = do
    peer <- getPeerName sock
    return $ PeerKey (peer `withPort` fromIntegral peerport)

clientKey (sock,addr) = return $ ClientKey addr

peerport = 5269
clientport = 5222

main = runResourceT $ do
    sv <- server
    lift $ do
    peer_params <- return (connectionDefaults peerKey)
                          { pingInterval = 2000, duplex = False }
    client_params <- return $ connectionDefaults clientKey
    forkIO $ monitor sv peer_params
    control sv (Listen peerport peer_params)
    control sv (Listen clientport client_params)

    -- atomically $ newEmptyTMVar >>= readTMVar -- Wait for control-c
    quitVar <- newEmptyTMVarIO
    installHandler sigTERM (CatchOnce (atomically $ putTMVar quitVar True)) Nothing
    installHandler sigINT (CatchOnce (atomically $ putTMVar quitVar True)) Nothing
    quitMessage <- atomically $ takeTMVar quitVar

    wlog "goodbye."
    return ()