Skat Engine und AI auf Haskell Basis
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

106 lines
3.2KB

  1. module AI.Server where
  2. import qualified Network.Socket as Net
  3. import qualified System.IO as Sys
  4. import Control.Concurrent
  5. import Control.Concurrent.Chan
  6. import Control.Monad (forever)
  7. import Control.Monad.Reader
  8. import Data.List.Split
  9. data Buffering = NoBuffering
  10. | LengthBuffering
  11. | DelimiterBuffering String
  12. deriving (Show)
  13. data ServerEnv = ServerEnv
  14. { buffering :: Buffering -- ^ Buffermode
  15. , socket :: Net.Socket -- ^ the socket used to communicate
  16. , global :: Chan String
  17. , onReceive :: OnReceive
  18. }
  19. instance Show ServerEnv where
  20. show env = "A Server"
  21. type Server = ReaderT ServerEnv IO
  22. type OnReceive = Sys.Handle -> Net.SockAddr -> String -> Server ()
  23. broadcast :: String -> Server ()
  24. broadcast msg = do
  25. bufmode <- asks buffering
  26. chan <- asks global
  27. case bufmode of
  28. DelimiterBuffering delim -> liftIO $ writeChan chan $ msg ++ delim
  29. _ -> liftIO $ writeChan chan msg
  30. send :: Sys.Handle -> String -> Server ()
  31. send connhdl msg = do
  32. bufmode <- asks buffering
  33. case bufmode of
  34. DelimiterBuffering delim -> liftIO $ Sys.hPutStr connhdl $ msg ++ delim
  35. _ -> liftIO $ Sys.hPutStr connhdl msg
  36. -- | Initialize a new server with the given port number and buffering mode
  37. initServer :: Net.PortNumber -> Buffering -> OnReceive -> IO ServerEnv
  38. initServer port buffermode handler = do
  39. sock <- Net.socket Net.AF_INET Net.Stream 0
  40. Net.setSocketOption sock Net.ReuseAddr 1
  41. Net.bind sock (Net.SockAddrInet port Net.iNADDR_ANY)
  42. Net.listen sock 5
  43. chan <- newChan
  44. forkIO $ forever $ do
  45. msg <- readChan chan -- clearing the main channel
  46. return ()
  47. return (ServerEnv buffermode sock chan handler)
  48. close :: ServerEnv -> IO ()
  49. close = Net.close . socket
  50. -- | Looping over requests and establish connection
  51. procRequests :: Server ()
  52. procRequests = do
  53. sock <- asks socket
  54. (conn, clientaddr) <- liftIO $ Net.accept sock
  55. env <- ask
  56. liftIO $ forkIO $ runReaderT (procMessages conn clientaddr) env
  57. procRequests
  58. -- | Handle one client
  59. procMessages :: Net.Socket -> Net.SockAddr -> Server ()
  60. procMessages conn clientaddr = do
  61. connhdl <- liftIO $ Net.socketToHandle conn Sys.ReadWriteMode
  62. liftIO $ Sys.hSetBuffering connhdl Sys.NoBuffering
  63. globalChan <- asks global
  64. commChan <- liftIO $ dupChan globalChan
  65. reader <- liftIO $ forkIO $ forever $ do
  66. msg <- readChan commChan
  67. Sys.hPutStrLn connhdl msg
  68. handler <- asks onReceive
  69. messages <- liftIO $ Sys.hGetContents connhdl
  70. buffermode <- asks buffering
  71. case buffermode of
  72. DelimiterBuffering delimiter ->
  73. mapM_ (handler connhdl clientaddr) (splitOn delimiter messages)
  74. LengthBuffering -> liftIO $ putStrLn (take 4 messages)
  75. _ -> return ()
  76. -- clean up
  77. liftIO $ do killThread reader
  78. Sys.hClose connhdl
  79. sampleHandler :: OnReceive
  80. sampleHandler connhdl addr query = do
  81. liftIO $ putStrLn $ "new query " ++ query
  82. send connhdl $ "> " ++ query
  83. main :: IO ()
  84. main = do
  85. env <- initServer 4242 LengthBuffering sampleHandler
  86. runReaderT procRequests env