-
Notifications
You must be signed in to change notification settings - Fork 2
/
mud.hs
89 lines (64 loc) · 2.24 KB
/
mud.hs
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
module Main (main) where
import World
import User
import Data
import Network.Socket
import System.IO
import Control.Exception
import Control.Concurrent
import Control.Concurrent.Chan
import Control.Concurrent.MVar
import Control.Monad
import Control.Monad.Fix (fix)
type Msg = (Int, String)
type Cmd = (User, String)
saveFile = "save_instanceOfWorld.txt"
data Trie a = Leaf a | Branch [Trie a]
main =
loadWorld saveFile defaultWorld >>= \instanceOfWorld ->
newMVar instanceOfWorld >>= \boxOfWorld ->
newChan >>= \chan ->
socket AF_INET Stream 0 >>= \sock ->
setSocketOption sock ReuseAddr 1
>> bindSocket sock (SockAddrInet 4242 iNADDR_ANY)
>> listen sock 2
>> (forkIO $ fix $ \loop -> readChan chan >>= \(_, msg) -> loop)
>> mainLoop boxOfWorld sock chan 0
mainLoop boxOfWorld sock chan nr =
accept sock >>= \conn ->
forkIO (runConn boxOfWorld conn chan nr)
>> (mainLoop boxOfWorld sock chan $! nr + 1)
runConn boxOfWorld (sock, _) chan nr =
let broadcast msg = writeChan chan (nr, msg) in
socketToHandle sock ReadWriteMode >>= \hdl ->
hSetBuffering hdl NoBuffering
>> hPutStrLn hdl "Who are you?"
>> liftM init (hGetLine hdl) >>= \name ->
getUser name boxOfWorld >>= \user ->
broadcast ("-->" ++ (userName user) ++ " entered.")
>> hPutStrLn hdl ("Hi, " ++ (userName user) ++ ".")
>> dupChan chan >>= \chan' ->
readLoop chan' hdl nr >>= \reader ->
userLoop chan' hdl nr user boxOfWorld
>> takeMVar boxOfWorld >>= \instanceOfWorld ->
saveWorld saveFile instanceOfWorld
>> putMVar boxOfWorld instanceOfWorld
>> killThread reader
>> broadcast ("<--" ++ (userName user) ++ " left.")
>> hClose hdl
readLoop chan hdl nr =
forkIO $ fix $ \loop ->
(readChan chan >>= \(nr', line) -> when (nr /= nr') $ hPutStrLn hdl line)
>> loop
userLoop chan hdl nr user boxOfWorld =
handle (\(SomeException _) -> return ()) $ fix $ \loop ->
liftM init (hGetLine hdl) >>= \line ->
case line of
"look" -> (hPutStrLn hdl $ roomName $ userRoom user)
>> loop
"quit" -> hPutStrLn hdl "Farewell"
>> takeMVar boxOfWorld >>= \instanceOfWorld ->
let instanceOfWorld' = disconnectUser user instanceOfWorld in
putMVar boxOfWorld instanceOfWorld'
_ -> (writeChan chan (nr, ((userName user) ++ ": " ++ line)))
>> loop