summaryrefslogtreecommitdiff
path: root/Presence/Server.hs
diff options
context:
space:
mode:
authorjoe <joe@jerkface.net>2013-06-15 15:07:19 -0400
committerjoe <joe@jerkface.net>2013-06-15 15:07:19 -0400
commit9fd2107e6a7469fe7ba51448e4fe195bf54d7d29 (patch)
treebb37572b478170e461990695e7d9e6ab823f7606 /Presence/Server.hs
started project
Diffstat (limited to 'Presence/Server.hs')
-rw-r--r--Presence/Server.hs81
1 files changed, 81 insertions, 0 deletions
diff --git a/Presence/Server.hs b/Presence/Server.hs
new file mode 100644
index 00000000..c41f047f
--- /dev/null
+++ b/Presence/Server.hs
@@ -0,0 +1,81 @@
1{-# LANGUAGE TypeFamilies #-}
2{-# LANGUAGE TypeOperators #-}
3module Server where
4
5import Network.Socket
6import qualified Data.ByteString as S (ByteString)
7import Data.ByteString.Lazy.Char8 as L
8 ( ByteString
9 , hPutStrLn
10 , fromChunks
11 , putStrLn )
12import Data.ByteString.Char8
13 ( hGetNonBlocking
14 )
15import System.IO
16 ( Handle
17 , IOMode(..)
18 , hSetBuffering
19 , BufferMode(..)
20 , hWaitForInput
21 , hClose
22 , hIsEOF
23 )
24import Control.Monad
25import Control.Monad.Fix (fix)
26import Todo
27import Control.Concurrent (forkIO)
28import Control.Exception (handle,SomeException(..))
29import Data.HList
30import Data.HList.TypeEqGeneric1()
31import Data.HList.TypeCastGeneric1()
32
33
34newtype ConnId = ConnId Int
35 deriving Eq
36
37newtype ConnectionFinalizer = ConnectionFinalizer (IO ())
38
39getPacket h = do { hWaitForInput h (-1) ; fmap (fromChunks . (:[])) $ hGetNonBlocking h 1024 }
40
41{-
42doServer ::
43 HList st
44 => PortNumber :*: st
45 -> ( Handle :*: ConnId :*: PortNumber :*: st
46 -> S.ByteString
47 -> (() -> IO ())
48 -> IO () )
49 -> IO b
50-}
51doServer port g startCon = runServer2 port (runConn2 g)
52 where
53 runConn2 g st (sock,_) = do
54 h <- socketToHandle sock ReadWriteMode
55 hSetBuffering h NoBuffering
56 st'' <- startCon (h .*. st)
57 handle (\(SomeException _) -> return ()) $ fix $ \loop -> do
58 let continue () = hIsEOF h >>= flip when loop . not
59 packet <- getPacket h
60 g st'' packet continue
61 let ConnectionFinalizer cleanup = hOccursFst st''
62 cleanup
63 hClose h
64
65 {-
66 runServer2 ::
67 Num num =>
68 PortNumber -> (num -> (Socket, SockAddr) -> IO b -> IO b) -> IO b
69 -}
70 runServer2 st@(HCons port _) go = do
71 sock <- socket AF_INET Stream 0
72 setSocketOption sock ReuseAddr 1
73 bindSocket sock (SockAddrInet port iNADDR_ANY)
74 listen sock 2
75 mainLoop sock (ConnId 0) go
76 where
77 mainLoop sock idnum@(ConnId n) go = do
78 con <- accept sock
79 forkIO $ go (idnum .*. st) con
80 mainLoop sock (ConnId (n+1)) go
81