-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgrid_server.py
More file actions
110 lines (85 loc) · 3.05 KB
/
grid_server.py
File metadata and controls
110 lines (85 loc) · 3.05 KB
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
from tornado.web import RequestHandler, Application, StaticFileHandler
from tornado.ioloop import IOLoop
from tornado.template import Loader
from tornado.websocket import WebSocketHandler
import json
from copy import copy
import os
class Grid(object):
"""
Keeps track of each grid's state and its websocket connections.
"""
def __init__(self, side):
self.side = side
self.state = {}
self.socket_connections = set()
def update(self, key, value):
# add change to grid's state
if value == '':
# remove item from state dict if square is empty
del self.state[key]
else:
self.state[key] = value
class GridManager(object):
"""
Manages all active grids. There's only one grid of each size; all requests
for the same sized grid will get the same grid object.
"""
grid_collection = {}
def get_or_create(self, side):
if side in self.grid_collection:
return self.grid_collection[side]
else:
grid = Grid(side)
self.grid_collection[side] = grid
return grid
class GridHome(RequestHandler):
"""
Returns a rendered grid template of the requested size.
"""
def get(self, *args, **kwargs):
loader = Loader("templates")
template = loader.load("grid.html")
self.write(template.generate(length=int(kwargs['side'])))
class GridSocket(WebSocketHandler):
"""
Represents a connection from a single client.
"""
def __init__(self, application, request, **kwargs):
self.grid = None
super(GridSocket, self).__init__(application, request, **kwargs)
def open(self, *args, **kwargs):
"""Open new connection, get or create a grid, and update the grid's state."""
self.grid = gridmgr.get_or_create(kwargs['side'])
self.grid.socket_connections.add(self)
self.write_message(self.grid.state)
def on_message(self, message):
"""Whenever a grid state is received, broadcast the new state to all of the grid's active connections."""
data = json.loads(message)
# update grid's state
for key, value in data.items():
self.grid.update(key, value)
for connection in copy(self.grid.socket_connections):
if connection.ws_connection:
# only update other connections
if connection is not self:
connection.write_message(message)
else:
self.grid.socket_connections.remove(connection)
# print(self)
# print(self.grid)
# print(self.grid.state)
def on_close(self):
self.grid.socket_connections.remove(self)
def main():
global gridmgr
gridmgr = GridManager()
app = Application([
(r"^/(?P<side>\d+)", GridHome),
(r"^/websocket/(?P<side>\d+)", GridSocket),
(r"^/static/(.*)", StaticFileHandler, {'path': os.path.dirname(__file__) + '/static'}),
])
app.listen(8888)
IOLoop.current().start()
if __name__ == '__main__':
main()