Skip to content

Commit eddfa5d

Browse files
committed
trying to improve our gevent api to support chaussette's usage
1 parent 4396e8b commit eddfa5d

3 files changed

Lines changed: 81 additions & 19 deletions

File tree

example/echo_chaussette_server.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# -*- coding: utf-8 -*-
2+
import logging
3+
4+
from gevent import monkey; monkey.patch_all()
5+
import gevent
6+
from ws4py.server.geventserver import WebSocketWSGIApplication, \
7+
WebSocketWSGIHandler, GEventWebSocketPool
8+
from ws4py.websocket import EchoWebSocket
9+
10+
from chaussette.backend._gevent import Server as GeventServer
11+
12+
class ws4pyServer(GeventServer):
13+
handler_class = WebSocketWSGIHandler
14+
15+
def __init__(self, *args, **kwargs):
16+
GeventServer.__init__(self, *args, **kwargs)
17+
self.pool = GEventWebSocketPool()
18+
19+
def stop(self, *args, **kwargs):
20+
self.pool.clear()
21+
self.pool = None
22+
GeventServer.stop(self, *args, **kwargs)
23+
24+
if __name__ == '__main__':
25+
import os, socket, sys
26+
from ws4py import configure_logger
27+
logger = configure_logger()
28+
29+
from chaussette.backend import register
30+
register('ws4py', ws4pyServer)
31+
32+
from chaussette.server import make_server
33+
server = make_server(app=WebSocketWSGIApplication(handler_cls=EchoWebSocket),
34+
host='unix:///%s/ws.sock' % os.getcwd(),
35+
address_family=socket.AF_UNIX,
36+
backend='ws4py',
37+
logger=logger)
38+
try:
39+
server.serve_forever()
40+
except KeyboardInterrupt:
41+
sys.exit(0)

ws4py/__init__.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,11 @@ def configure_logger(stdout=True, filepath=None, level=logging.INFO):
5757
return logger
5858

5959
def format_addresses(ws):
60-
me_ip, me_port = ws.local_address
61-
peer_ip, peer_port = ws.peer_address
62-
return "[Local => %s:%d | Remote => %s:%d]" % (me_ip, me_port, peer_ip, peer_port)
63-
60+
me = ws.local_address
61+
peer = ws.peer_address
62+
if isinstance(me, tuple) and isinstance(peer, tuple):
63+
me_ip, me_port = ws.local_address
64+
peer_ip, peer_port = ws.peer_address
65+
return "[Local => %s:%d | Remote => %s:%d]" % (me_ip, me_port, peer_ip, peer_port)
66+
67+
return "[Bound to '%s']" % me

ws4py/server/geventserver.py

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727

2828
logger = logging.getLogger('ws4py')
2929

30-
__all__ = ['WebSocketWSGIHandler', 'WSGIServer']
30+
__all__ = ['WebSocketWSGIHandler', 'WSGIServer',
31+
'GEventWebSocketPool']
3132

3233
class WebSocketWSGIHandler(WSGIHandler):
3334
"""
@@ -56,10 +57,35 @@ def run_application(self):
5657

5758
ws = self.environ.pop('ws4py.websocket')
5859
if ws:
59-
self.server.link_websocket_to_server(ws)
60+
self.server.pool.track(ws)
6061
else:
6162
gevent.pywsgi.WSGIHandler.run_application(self)
6263

64+
class GEventWebSocketPool(Group):
65+
"""
66+
Simple pool of bound websockets.
67+
Internally it uses a gevent group to track
68+
the websockets. The server should call the ``clear``
69+
method to initiate the closing handshake when the
70+
server is shutdown.
71+
"""
72+
73+
def track(self, websocket):
74+
logger.info("Managing websocket %s" % format_addresses(websocket))
75+
return self.spawn(websocket.run)
76+
77+
def clear(self):
78+
logger.info("Terminating server and all connected websockets")
79+
for greenlet in self:
80+
try:
81+
websocket = greenlet._run.im_self
82+
if websocket:
83+
websocket.close(1001, 'Server is shutting down')
84+
except:
85+
pass
86+
finally:
87+
self.discard(greenlet)
88+
6389
class WSGIServer(_WSGIServer):
6490
handler_class = WebSocketWSGIHandler
6591

@@ -74,24 +100,15 @@ def __init__(self, *args, **kwargs):
74100
base.
75101
"""
76102
_WSGIServer.__init__(self, *args, **kwargs)
77-
self._websockets = Group()
78-
79-
def link_websocket_to_server(self, websocket):
80-
logger.info("Managing websocket %s" % format_addresses(websocket))
81-
self._websockets.spawn(websocket.run)
103+
self.pool = GEventWebSocketPool()
82104

83105
def stop(self, *args, **kwargs):
84-
logger.info("Terminating server and all connected websockets")
85-
for greenlet in self._websockets:
86-
try:
87-
websocket = greenlet._run.im_self
88-
if websocket:
89-
websocket.close(1001, 'Server is shutting down')
90-
except:
91-
pass
106+
self.pool.clear()
92107
_WSGIServer.stop(self, *args, **kwargs)
93108

94109
if __name__ == '__main__':
110+
import os
111+
95112
from ws4py import configure_logger
96113
configure_logger()
97114

0 commit comments

Comments
 (0)