-
Notifications
You must be signed in to change notification settings - Fork 1
/
Lobby.hs
144 lines (138 loc) · 6.97 KB
/
Lobby.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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
module Lobby ( lobby, lobbyClient ) where
import TCP.Client ( Client, ioClient, forkClient )
import TCP.ServerTypes ( Server, ServerMessage(N,M),
ioServer, forkServer )
import TCP.Chan ( ShowRead, writeOutput, readInput, pipe, readLine )
import TCP.Message ( Message(..) )
import Data.Maybe ( fromJust )
import Control.Monad ( forever )
import Control.Concurrent ( forkIO )
data LobbyMsg tablename tablemsg = Chat String
| JoinTable tablename
| TableMsg tablename tablemsg
deriving ( Eq, Show, Read )
instance (ShowRead name, ShowRead msg) => ShowRead (LobbyMsg name msg)
data LobbyClient name tablename tablemsg
= Chatted name String
| JoinedTable name tablename
| AtTable tablename tablemsg
| Joined name
deriving ( Eq, Show, Read )
instance (ShowRead name, ShowRead tablename, ShowRead msg) =>
ShowRead (LobbyClient name tablename msg)
lobby :: (Eq name, ShowRead name,
Eq tablename, ShowRead tablename,
ShowRead toclient, ShowRead toserver) =>
tablename -> -- hokey trick to define tablename type...
Server name toclient (ServerMessage toserver)
-> Server name (LobbyClient name tablename toclient)
(ServerMessage (LobbyMsg tablename toserver))
lobby _ mktable = ioServer $ \o i ->
do let handle us ts =
do let sendToOthers m =
mapM_ (\t ->
if t /= fromAgent m
then writeOutput o (m { toAgent = t })
else return ()) us
sendToAll m =
mapM_ (\t -> writeOutput o (m { fromAgent= toAgent m,
toAgent = t })) us
m <- readInput i
case m of
Message f t N ->
do putStrLn (show f++" joined!")
-- the following message is probably ignored...
writeOutput o (Message f f (Joined f))
sendToAll (Message f t (Joined f))
handle (f:filter (/= f) us) ts
Message f t (M (Chat c)) ->
do putStrLn (show f++" says "++c)
sendToOthers (Message f t (Chatted f c))
handle us ts
Message f t (M (JoinTable tab)) ->
case lookup tab ts of
Just table ->
do writeOutput table (Message f t N)
writeOutput o (Message f f (JoinedTable f tab))
sendToAll (Message f t (JoinedTable f tab))
handle us ts
Nothing ->
do putStrLn ("creating table "++show tab)
(ii,oo) <- forkServer mktable
-- Any messages emerging from the
-- table get wrapped up with a table
-- label and forwarded to the
-- clients.
forkIO $ forever $
do Message f' t' x <- readInput ii
writeOutput o
(Message f' t' (AtTable tab x))
writeOutput oo (Message f t N)
writeOutput o (Message f f (JoinedTable f tab))
sendToAll (Message f t (JoinedTable f tab))
handle us ((tab,oo):ts)
Message f t (M (TableMsg tab mm)) ->
case lookup tab ts of
Just table ->
do putStrLn $ "passing message "++show mm++
" to table "++ show tab
writeOutput table (Message f t (M mm))
handle us ts
Nothing ->
do putStrLn "BOGUS MESSAGE!!!"
handle us ts
handle [] []
lobbyClient :: (Eq tablename, ShowRead tablename,
ShowRead toclient, ShowRead toserver) =>
tablename -> Client toclient toserver
-> Client (LobbyClient String tablename toclient)
(LobbyMsg tablename toserver)
lobbyClient _ dotable = ioClient $ \i o ->
do -- Don't grab stdin until *after* we've gotten one input over
-- the chan. This gives any modifiers a chance to get some
-- input first.
--
-- I'm telling it to ignore the first message, so it had better
-- be an awknowledgement message.
Joined me <- readInput i
putStrLn ("My name is "++show me)
(tablei, tableo) <- pipe
let dumpout mytab@(Just (mytable, tableout)) =
do m <- readInput i
case m of
Chatted _ _ -> dumpout mytab
JoinedTable _ _ -> dumpout mytab
Joined _ -> dumpout mytab
AtTable t x | t == mytable ->
do writeOutput tableout x
dumpout mytab
| otherwise -> dumpout mytab
dumpout Nothing =
do m <- readInput i
case m of
Chatted name mm ->
do putStrLn (show name++" says "++mm)
dumpout Nothing
JoinedTable n t
| n == me ->
do putStrLn ("I joined table "++show t)
tchan <- readInput tablei
dumpout (Just (t, tchan))
| otherwise ->
do putStrLn (show n++" joined "++show t)
dumpout Nothing
Joined n ->
do putStrLn (show n++" has joined us.")
dumpout Nothing
AtTable _ _ -> dumpout Nothing
forkIO $ dumpout Nothing
forever $ do x <- getLine
if take 5 x == "join "
then do let tname = fromJust $ readLine (drop 5 x)
writeOutput o (JoinTable tname)
(ii,oo) <- forkClient dotable
-- send the output chan to the other thread
writeOutput tableo oo
forever $ do m <- readInput ii
writeOutput o (TableMsg tname m)
else writeOutput o (Chat x)