1 /* Base class providing common code for game engine implementations. */
6 this.next_client_id = 1;
9 /* Suport for game meta-data.
11 * What we want here is an effectively static field that is
12 * accessible through either the class name (SomeGame.meta) or an
13 * instance (some_game.meta). To pull this off we do keep two copies
14 * of the data. But the game classes can just set SomeGame.meta once
15 * and then reference it either way.
17 static set meta(data) {
18 /* This allows class access (SomeGame.meta) via the get method below. */
21 /* While this allows access via an instance (some_game.meta). */
22 this.prototype.meta = data;
29 add_client(response) {
30 const id = this.next_client_id;
31 this.clients.push({id: id,
33 this.next_client_id++;
39 this.clients = this.clients.filter(client => client.id !== id);
42 /* Send a string to all clients */
43 broadcast_string(str) {
44 this.clients.forEach(client => client.response.write(str + '\n'));
47 /* Send an event to all clients.
49 * An event has both a declared type and a separate data block.
50 * It also ends with two newlines (to mark the end of the event).
52 broadcast_event(type, data) {
53 this.broadcast_string(`event: ${type}\ndata: ${data}\n`);
56 handle_events(request, response) {
57 /* These headers will keep the connection open so we can stream events. */
59 "Content-type": "text/event-stream",
60 "Connection": "keep-alive",
61 "Cache-Control": "no-cache"
63 response.writeHead(200, headers);
65 /* Add this new client to our list of clients. */
66 const id = this.add_client(response);
68 /* And queue up cleanup to be triggered on client close. */
69 request.on('close', () => {
70 this.remove_client(id);
76 module.exports = Game;