X-Git-Url: https://jasonwoof.com/gitweb/?p=peach-cgt.git;a=blobdiff_plain;f=server.coffee;h=ab0ca9f06fef926624c4b29c34fea7586c4c94e9;hp=9beb901339f9af8fd2fcd70322669aac0b603e92;hb=4ae9f3f4c527c3565fa7e82c114f025053927df3;hpb=bff997aff6d7220a8183421bdff64c9a1ef352c3 diff --git a/server.coffee b/server.coffee index 9beb901..ab0ca9f 100644 --- a/server.coffee +++ b/server.coffee @@ -2,9 +2,16 @@ listen_port = 8333 sys = require 'sys' fs = require 'fs' http = require 'http' +querystring = require 'querystring' url = require 'url' less = require 'less' coffee = require 'coffee-script' +model = require './common.coffee' + +games = {} + +# timeout function with args in convenient order +timeout = (ms, func) -> setTimeout func, ms css_handler = (args, out, request, url_parts) -> fs.readFile 'style.less', 'utf8', (err, data) -> @@ -57,6 +64,130 @@ javascript_handler = (args, out, request, url_parts) -> out.end data +get_handler = (args, out, request, url_parts) -> + console.log "get handler: ", args + unless args.game?.length + out.writeHead 404, "Content-Type": 'text/plain' + out.end 'Missing (or empty) "game" argument' + return + + unless args.agent is 'p1' or args.agent is 'p2' + out.writeHead 404, "Content-Type": 'text/plain' + out.end '"agent" argument must be set to p1 or p2' + return + + unless games[args.game]? + out.writeHead 404, "Content-Type": 'text/plain' + out.end 'Game not found' + return + + game = games[args.game] + + waiter = games["#{args.agent}_waiter"] + if waiter? + waiter.writeHead 200, 'Content-Type': 'text/javascript' + waiter.end '[]' + + game["#{args.agent}_waiter"] = out + + answer_soon game # in case there's something queued already + +set_handler = (args, out, request, url_parts) -> + console.log "set handler: ", args + unless args.game?.length + out.writeHead 404, "Content-Type": 'text/plain' + out.end 'Missing (or empty) "game" argument' + return + + unless args.agent is 'p1' or args.agent is 'p2' + out.writeHead 404, "Content-Type": 'text/plain' + out.end '"agent" argument must be set to p1 or p2' + return + + unless args.messages? + out.writeHead 404, "Content-Type": 'text/plain' + out.end '"messages" argument must be set' + return + + unless games[args.game]? + out.writeHead 404, "Content-Type": 'text/plain' + out.end 'Game not found' + return + + game = games[args.game] + + # FIXME add error checking (json validity at least) + game.process_messages JSON.parse args.messages + + out.writeHead 200, "Content-Type": 'text/plain' + out.end 'ok' + +# don't call this directly, call answer_soon instead +answer_now = (game) -> + if game.p1_waiter and game.p1_queue.length + waiter = game.p1_waiter + queue = game.p1_queue + game.p1_waiter = false + game.p1_queue = [] + waiter.writeHead 200, 'Content-Type': 'text/javascript' + waiter.end JSON.stringify queue + if game.p2_waiter and game.p2_queue.length + waiter = game.p2_waiter + queue = game.p2_queue + game.p2_waiter = false + game.p2_queue = [] + waiter.writeHead 200, 'Content-Type': 'text/javascript' + waiter.end JSON.stringify queue + +# this marks a game as "dirty" and makes sure there's exactly one timeout +# that'll respond to any clients that are waiting, and now have messages. +answer_soon = (game) -> + unless game.replier_id + game.replier_id = timeout 1, -> + delete game.replier_id + answer_now game + +forward_events = (message...) -> + unless message[1] is 'p1' + @p1_queue.push message + answer_soon this + unless message[1] is 'p2' + @p2_queue.push message + answer_soon this + console.log this + +new_game = (id) -> + game = games[id] = model.new 'server' + game.p1_waiter = false + game.p2_waiter = false + game.p1_queue = [] + game.p2_queue = [] + + game.on 'move', (agent, card, x, y) -> + forward_events.call this, 'move', agent, card, x, y + game.on 'mark', (agent, card, state) -> + forward_events.call this, 'mark', agent, card, state + game.on 'flip', (agent, card, state) -> + forward_events.call this, 'flip', agent, card, state + game.on 'set_cards', (cards) -> + forward_events.call this, 'set_cards', cards + + return game + +test_init = -> + test_game = new_game 'test' + timeout 4000, -> + test_game.set_cards [ + { text: "Wildabeast 2/2", x: 20, y: 140} + { text: "Wild beast 2/2", x: 150, y: 140} + { text: "Angora bunny 1/1", x: 300, y: 140} + { text: "Ambulatory Cactus 2/1", x: 450, y: 140} + { text: "Ent 0/5", x: 600, y: 140} + ] + +test_init() + + http_server = http.createServer (req, res) -> url_parts = url.parse req.url, true if url_parts.query is undefined @@ -69,9 +200,25 @@ http_server = http.createServer (req, res) -> else if rel_path.substr(rel_path.length - 4) is '.css' res.writeHead 200, 'Content-Type': 'text/css' return css_handler url_parts.query, res, req, url_parts - else if rel_path.substr rel_path.length - 3 is '.js' + else if rel_path.substr(rel_path.length - 3) is '.js' res.writeHead 200, 'Content-Type': 'text/javascript' return js_handler url_parts.query, res, req, url_parts + else if rel_path.substr(rel_path.length - 4) is '/set' + data = '' + req.on 'data', (chunk) -> + data += chunk + req.on 'end', -> + query = url_parts.query + post_args = querystring.parse data + console.log data, post_args + for key, parg of post_args + query[key] = parg + return set_handler query, res, req, url_parts + else if rel_path.substr(rel_path.length - 4) is '/get' + return get_handler url_parts.query, res, req, url_parts + else if rel_path.substr(rel_path.length - 4) is '.ico' + res.writeHead 404 + return res.end() return html_handler url_parts.query, res, req, url_parts