5 querystring = require 'querystring'
8 coffee = require 'coffee-script'
9 model = require './common.coffee'
13 # timeout function with args in convenient order
14 timeout = (ms, func) -> setTimeout func, ms
16 css_handler = (args, out, request, url_parts) ->
17 fs.readFile 'style.less', 'utf8', (err, data) ->
19 return out.end 'Server failed to read style.less'
20 less.render data, (err, css) ->
22 return out.end "Server failed to make css: #{err}"
25 js_handler = (args, out, request, url_parts) ->
26 basename = url_parts.pathname.substr 1, (url_parts.pathname.length - 4)
27 if basename is 'client'
28 filename = 'client.coffee'
29 else if basename is 'common'
30 filename = 'common.coffee'
32 error = "Unknown js basename: #{basename}"
37 fs.readFile filename, 'utf8', (err, data) ->
39 return out.end "Server failed to read #{filename}"
40 out.end coffee.compile data
42 html_handler = (args, out, request, url_parts) ->
43 fs.readFile 'index.html', 'utf8', (err, data) ->
45 return out.end 'Server failed to read index.html'
48 clean_pathname_regex = new RegExp('[^a-zA-Z/_.-]')
49 clean_pathname_regex2 = new RegExp('/[.]')
50 clean_pathname_regex3 = new RegExp('^[.-]')
51 clean_pathname = (str) ->
52 str = str.replace clean_pathname_regex, '_'
53 str = str.replace clean_pathname_regex2, '/_'
54 return str.replace clean_pathname_regex3, '_'
56 # serve javascript files from within /usr/share/javascript
57 javascript_handler = (args, out, request, url_parts) ->
58 filename = clean_pathname "/usr/share/#{url_parts.pathname}"
59 fs.readFile filename, 'utf8', (err, data) ->
62 return out.end "Server failed to read #{filename}"
63 out.writeHead 200, 'Content-Type': 'text/javascript'
67 get_handler = (args, out, request, url_parts) ->
68 console.log "get handler: ", args
69 unless args.game?.length
70 out.writeHead 404, "Content-Type": 'text/plain'
71 out.end 'Missing (or empty) "game" argument'
74 unless args.agent is 'p1' or args.agent is 'p2'
75 out.writeHead 404, "Content-Type": 'text/plain'
76 out.end '"agent" argument must be set to p1 or p2'
79 unless games[args.game]?
80 out.writeHead 404, "Content-Type": 'text/plain'
81 out.end 'Game not found'
84 game = games[args.game]
86 waiter = games["#{args.agent}_waiter"]
88 waiter.writeHead 200, 'Content-Type': 'text/javascript'
91 game["#{args.agent}_waiter"] = out
93 answer_soon game # in case there's something queued already
95 set_handler = (args, out, request, url_parts) ->
96 console.log "set handler: ", args
97 unless args.game?.length
98 out.writeHead 404, "Content-Type": 'text/plain'
99 out.end 'Missing (or empty) "game" argument'
102 unless args.agent is 'p1' or args.agent is 'p2'
103 out.writeHead 404, "Content-Type": 'text/plain'
104 out.end '"agent" argument must be set to p1 or p2'
107 unless args.messages?
108 out.writeHead 404, "Content-Type": 'text/plain'
109 out.end '"messages" argument must be set'
112 unless games[args.game]?
113 out.writeHead 404, "Content-Type": 'text/plain'
114 out.end 'Game not found'
117 game = games[args.game]
119 # FIXME add error checking (json validity at least)
120 game.process_messages JSON.parse args.messages
122 out.writeHead 200, "Content-Type": 'text/plain'
125 # don't call this directly, call answer_soon instead
126 answer_now = (game) ->
127 if game.p1_waiter and game.p1_queue.length
128 waiter = game.p1_waiter
129 queue = game.p1_queue
130 game.p1_waiter = false
132 waiter.writeHead 200, 'Content-Type': 'text/javascript'
133 waiter.end JSON.stringify queue
134 if game.p2_waiter and game.p2_queue.length
135 waiter = game.p2_waiter
136 queue = game.p2_queue
137 game.p2_waiter = false
139 waiter.writeHead 200, 'Content-Type': 'text/javascript'
140 waiter.end JSON.stringify queue
142 # this marks a game as "dirty" and makes sure there's exactly one timeout
143 # that'll respond to any clients that are waiting, and now have messages.
144 answer_soon = (game) ->
145 unless game.replier_id
146 game.replier_id = timeout 1, ->
147 delete game.replier_id
150 forward_events = (message...) ->
151 unless message[1] is 'p1'
152 @p1_queue.push message
154 unless message[1] is 'p2'
155 @p2_queue.push message
160 game = games[id] = model.new 'server'
161 game.p1_waiter = false
162 game.p2_waiter = false
166 game.on 'move', (agent, card, x, y) ->
167 forward_events.call this, 'move', agent, card, x, y
168 game.on 'mark', (agent, card, state) ->
169 forward_events.call this, 'mark', agent, card, state
170 game.on 'flip', (agent, card, state) ->
171 forward_events.call this, 'flip', agent, card, state
172 game.on 'set_cards', (cards) ->
173 forward_events.call this, 'set_cards', cards
178 test_game = new_game 'test'
180 test_game.set_cards [
181 { text: "Wildabeast 2/2", x: 20, y: 140}
182 { text: "Wild beast 2/2", x: 150, y: 140}
183 { text: "Angora bunny 1/1", x: 300, y: 140}
184 { text: "Ambulatory Cactus 2/1", x: 450, y: 140}
185 { text: "Ent 0/5", x: 600, y: 140}
191 http_server = http.createServer (req, res) ->
192 url_parts = url.parse req.url, true
193 if url_parts.query is undefined
196 rel_path = url_parts.pathname.substr 1
198 if rel_path.substr(0, 11) is 'javascript/'
199 return javascript_handler url_parts.query, res, req, url_parts
200 else if rel_path.substr(rel_path.length - 4) is '.css'
201 res.writeHead 200, 'Content-Type': 'text/css'
202 return css_handler url_parts.query, res, req, url_parts
203 else if rel_path.substr(rel_path.length - 3) is '.js'
204 res.writeHead 200, 'Content-Type': 'text/javascript'
205 return js_handler url_parts.query, res, req, url_parts
206 else if rel_path.substr(rel_path.length - 4) is '/set'
208 req.on 'data', (chunk) ->
211 query = url_parts.query
212 post_args = querystring.parse data
213 console.log data, post_args
214 for key, parg of post_args
216 return set_handler query, res, req, url_parts
217 else if rel_path.substr(rel_path.length - 4) is '/get'
218 return get_handler url_parts.query, res, req, url_parts
219 else if rel_path.substr(rel_path.length - 4) is '.ico'
223 return html_handler url_parts.query, res, req, url_parts
225 http_server.listen listen_port, "127.0.0.1"
226 console.log "Server running at http://127.0.0.1:#{listen_port}/"