Skip to content

Commit ddf73a5

Browse files
committed
initial try for an automated heartbeat
1 parent f0408b3 commit ddf73a5

5 files changed

Lines changed: 140 additions & 80 deletions

File tree

example/echo_cherrypy_server.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def index(self):
4545
window.onbeforeunload = function(e) {
4646
$('#chat').val($('#chat').val() + 'Bye bye...\\n');
4747
ws.close(1000, '%(username)s left the room');
48-
48+
4949
if(!e) e = window.event;
5050
e.stopPropagation();
5151
e.preventDefault();
@@ -57,7 +57,7 @@ def index(self):
5757
ws.send("%(username)s entered the room");
5858
};
5959
ws.onclose = function(evt) {
60-
$('#chat').val($('#chat').val() + 'Connection closed by server: ' + evt.code + ' \"' + evt.reason + '\"\\n');
60+
$('#chat').val($('#chat').val() + 'Connection closed by server: ' + evt.code + ' \"' + evt.reason + '\"\\n');
6161
};
6262
6363
$('#send').click(function() {
@@ -98,7 +98,7 @@ def ws(self):
9898
if args.ssl:
9999
cherrypy.config.update({'server.ssl_certificate': './server.crt',
100100
'server.ssl_private_key': './server.key'})
101-
101+
102102
WebSocketPlugin(cherrypy.engine).subscribe()
103103
cherrypy.tools.websocket = WebSocketTool()
104104

ws4py/client/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@
1313
__all__ = ['WebSocketBaseClient']
1414

1515
class WebSocketBaseClient(WebSocket):
16-
def __init__(self, url, protocols, extensions):
16+
def __init__(self, url, protocols, extensions, heartbeat_freq=None):
1717
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
18-
WebSocket.__init__(self, sock, protocols=protocols, extensions=extensions)
18+
WebSocket.__init__(self, sock, protocols=protocols, extensions=extensions,
19+
heartbeat_freq=heartbeat_freq)
1920
self.stream.always_mask = True
2021
self.stream.expect_masking = False
2122
self.key = b64encode(os.urandom(16))

ws4py/client/threadedclient.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
__all__ = ['WebSocketClient']
77

88
class WebSocketClient(WebSocketBaseClient):
9-
def __init__(self, url, protocols=None, extensions=None):
10-
WebSocketBaseClient.__init__(self, url, protocols, extensions)
9+
def __init__(self, url, protocols=None, extensions=None, heartbeat_freq=None):
10+
WebSocketBaseClient.__init__(self, url, protocols, extensions, heartbeat_freq)
1111
self._th = threading.Thread(target=self.run, name='WebSocketClient')
1212
self._th.daemon = True
1313

ws4py/server/cherrypyserver.py

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@
2525
request's processing. Enable that tool at
2626
any path you wish to handle as a WebSocket
2727
handler.
28-
28+
2929
* WebSocketPlugin: The plugin tracks the instanciated web socket handlers.
3030
It also cleans out websocket handler which connection
3131
have been closed down. The websocket connection then
3232
runs in its own thread that this plugin manages.
33-
33+
3434
Simple usage example:
3535
3636
.. code-block:: python
@@ -39,7 +39,7 @@
3939
import cherrypy
4040
from ws4py.server.cherrypyserver import WebSocketPlugin, WebSocketTool
4141
from ws4py.websocket import EchoWebSocket
42-
42+
4343
cherrypy.config.update({'server.socket_port': 9000})
4444
WebSocketPlugin(cherrypy.engine).subscribe()
4545
cherrypy.tools.websocket = WebSocketTool()
@@ -52,7 +52,7 @@ def index(self):
5252
@cherrypy.expose
5353
def ws(self):
5454
pass
55-
55+
5656
cherrypy.quickstart(Root(), '/', config={'/ws': {'tools.websocket.on': True,
5757
'tools.websocket.handler_cls': EchoWebSocket}})
5858
@@ -97,7 +97,8 @@ def _setup(self):
9797
hooks.attach('on_end_request', self.start_handler,
9898
priority=70)
9999

100-
def upgrade(self, protocols=None, extensions=None, version=WS_VERSION, handler_cls=WebSocket):
100+
def upgrade(self, protocols=None, extensions=None, version=WS_VERSION,
101+
handler_cls=WebSocket, heartbeat_freq=None):
101102
"""
102103
Performs the upgrade of the connection to the WebSocket
103104
protocol.
@@ -113,13 +114,13 @@ def upgrade(self, protocols=None, extensions=None, version=WS_VERSION, handler_c
113114
"""
114115
request = cherrypy.serving.request
115116
request.process_request_body = False
116-
117+
117118
ws_protocols = None
118119
ws_location = None
119120
ws_version = version
120121
ws_key = None
121122
ws_extensions = []
122-
123+
123124
if request.method != 'GET':
124125
raise HandshakeError('HTTP method must be a GET')
125126

@@ -131,25 +132,25 @@ def upgrade(self, protocols=None, extensions=None, version=WS_VERSION, handler_c
131132
if expected_value not in actual_value:
132133
raise HandshakeError('Illegal value for header %s: %s' %
133134
(key, actual_value))
134-
135+
135136
version = request.headers.get('Sec-WebSocket-Version')
136137
supported_versions = ', '.join([str(v) for v in ws_version])
137138
version_is_valid = False
138139
if version:
139140
try: version = int(version)
140141
except: pass
141142
else: version_is_valid = version in ws_version
142-
143+
143144
if not version_is_valid:
144145
cherrypy.response.headers['Sec-WebSocket-Version'] = supported_versions
145146
raise HandshakeError('Unhandled or missing WebSocket version')
146-
147+
147148
key = request.headers.get('Sec-WebSocket-Key')
148149
if key:
149150
ws_key = base64.b64decode(enc(key))
150151
if len(ws_key) != 16:
151152
raise HandshakeError("WebSocket key's length is invalid")
152-
153+
153154
protocols = protocols or []
154155
subprotocols = request.headers.get('Sec-WebSocket-Protocol')
155156
if subprotocols:
@@ -166,7 +167,7 @@ def upgrade(self, protocols=None, extensions=None, version=WS_VERSION, handler_c
166167
ext = ext.strip()
167168
if ext in exts:
168169
ws_extensions.append(ext)
169-
170+
170171
location = []
171172
include_port = False
172173
if request.scheme == "https":
@@ -199,8 +200,9 @@ def upgrade(self, protocols=None, extensions=None, version=WS_VERSION, handler_c
199200
addr = (request.remote.ip, request.remote.port)
200201
ws_conn = get_connection(request.rfile.rfile)
201202
request.ws_handler = handler_cls(ws_conn, ws_protocols, ws_extensions,
202-
request.wsgi_environ.copy())
203-
203+
request.wsgi_environ.copy(),
204+
heartbeat_freq=heartbeat_freq)
205+
204206
def complete(self):
205207
"""
206208
Sets some internal flags of CherryPy so that it
@@ -216,7 +218,7 @@ def cleanup_headers(self):
216218
response = cherrypy.response
217219
if not response.header_list:
218220
return
219-
221+
220222
headers = response.header_list[:]
221223
for (k, v) in headers:
222224
if k[:7] == 'Sec-Web':
@@ -226,7 +228,7 @@ def cleanup_headers(self):
226228
def start_handler(self):
227229
"""
228230
Runs at the end of the request processing by calling
229-
the opened method of the handler.
231+
the opened method of the handler.
230232
"""
231233
request = cherrypy.request
232234
if not hasattr(request, 'ws_handler'):
@@ -240,9 +242,9 @@ def start_handler(self):
240242
# By doing this we detach the socket from
241243
# the CherryPy stack avoiding memory leaks
242244
detach_connection(request.rfile.rfile)
243-
245+
244246
cherrypy.engine.publish('handle-websocket', ws_handler, addr)
245-
247+
246248
def _set_internal_flags(self):
247249
"""
248250
CherryPy has two internal flags that we are interested in
@@ -286,7 +288,7 @@ def start(self):
286288
self.bus.subscribe('stop', self.cleanup)
287289
self.bus.subscribe('handle-websocket', self.handle)
288290
self.bus.subscribe('websocket-broadcast', self.broadcast)
289-
291+
290292
def stop(self):
291293
cherrypy.log("Terminating WebSocket processing")
292294
self.bus.unsubscribe('main', self.monitor)
@@ -316,7 +318,7 @@ def monitor(self):
316318
handlers = list(self.pool.keys())
317319
else:
318320
handlers = self.pool.keys()[:]
319-
321+
320322
for handler in handlers:
321323
if handler.terminated:
322324
th, addr = self.pool[handler]
@@ -350,14 +352,14 @@ def broadcast(self, message, binary=False):
350352
ws_handler.send(message, binary)
351353
except:
352354
cherrypy.log(traceback=True)
353-
355+
354356
if __name__ == '__main__':
355357
import random
356358
cherrypy.config.update({'server.socket_host': '127.0.0.1',
357359
'server.socket_port': 9000})
358360
WebSocketPlugin(cherrypy.engine).subscribe()
359361
cherrypy.tools.websocket = WebSocketTool()
360-
362+
361363
class Root(object):
362364
@cherrypy.expose
363365
@cherrypy.tools.websocket(on=False)
@@ -369,13 +371,13 @@ def ws(self):
369371
$(document).ready(function() {
370372
var ws = new WebSocket('ws://192.168.0.10:9000/');
371373
ws.onmessage = function (evt) {
372-
$('#chat').val($('#chat').val() + evt.data + '\\n');
374+
$('#chat').val($('#chat').val() + evt.data + '\\n');
373375
};
374376
ws.onopen = function() {
375377
ws.send("Hello there");
376378
};
377379
ws.onclose = function(evt) {
378-
$('#chat').val($('#chat').val() + 'Connection closed by server: ' + evt.code + ' \"' + evt.reason + '\"\\n');
380+
$('#chat').val($('#chat').val() + 'Connection closed by server: ' + evt.code + ' \"' + evt.reason + '\"\\n');
379381
};
380382
$('#chatform').submit(function() {
381383
ws.send('%(username)s: ' + $('#message').val());
@@ -399,6 +401,6 @@ def ws(self):
399401
@cherrypy.expose
400402
def index(self):
401403
cherrypy.log("Handler created: %s" % repr(cherrypy.request.ws_handler))
402-
404+
403405
cherrypy.quickstart(Root(), '/', config={'/': {'tools.websocket.on': True,
404406
'tools.websocket.handler_cls': EchoWebSocketHandler}})

0 commit comments

Comments
 (0)