Skip to content

Commit ad3fb2d

Browse files
committed
Moved client cleanup code from the end of the socket.io view into a function that is then called for each client in the atexit.register'd cleanup handler. Also call the cleanup handler when the server is reloaded. Moved all cleanup handling and adding to CLIENTS into a clients module.
1 parent ee28e7a commit ad3fb2d

File tree

5 files changed

+58
-31
lines changed

5 files changed

+58
-31
lines changed

django_socketio/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def send(session_id, message):
1212
"""
1313
Send a message to the socket for the given session ID.
1414
"""
15-
from django_socketio.views import CLIENTS
15+
from django_socketio.clients import CLIENTS
1616
try:
1717
socket = CLIENTS[session_id][1]
1818
except KeyError:
@@ -25,7 +25,7 @@ def broadcast(message):
2525
Find the first socket and use it to broadcast to all sockets
2626
including the socket itself.
2727
"""
28-
from django_socketio.views import CLIENTS
28+
from django_socketio.clients import CLIENTS
2929
try:
3030
socket = CLIENTS.values()[0][1]
3131
except IndexError:
@@ -38,7 +38,7 @@ def broadcast_channel(message, channel):
3838
Find the first socket for the given channel, and use it to
3939
broadcast to the channel, including the socket itself.
4040
"""
41-
from django_socketio.views import CLIENTS
41+
from django_socketio.clients import CLIENTS
4242
from django_socketio.channels import CHANNELS
4343
try:
4444
socket = CLIENTS[CHANNELS.get(channel, [])[0]][1]

django_socketio/clients.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
2+
from atexit import register
3+
4+
from django_socketio import events
5+
6+
7+
# Maps open Socket.IO session IDs to request/socket pairs for
8+
# running cleanup code and events when the server is shut down
9+
# or reloaded.
10+
CLIENTS = {}
11+
12+
13+
def client_start(request, socket, context):
14+
"""
15+
Adds the client triple to CLIENTS.
16+
"""
17+
CLIENTS[socket.session.session_id] = (request, socket, context)
18+
19+
20+
def client_end(request, socket, context):
21+
"""
22+
Handles cleanup when a session ends for the given client triple.
23+
Sends unsubscribe and finish events, actually unsubscribes from
24+
any channels subscribed to, and removes the client triple from
25+
CLIENTS.
26+
"""
27+
# Send the unsubscribe event prior to actually unsubscribing, so
28+
# that the finish event can still match channels if applicable.
29+
for channel in socket.channels:
30+
events.on_unsubscribe.send(request, socket, context, channel)
31+
events.on_finish.send(request, socket, context)
32+
# Actually unsubscribe to cleanup channel data.
33+
for channel in socket.channels:
34+
socket.unsubscribe(channel)
35+
# Remove the client.
36+
del CLIENTS[socket.session.session_id]
37+
38+
39+
@register
40+
def client_end_all():
41+
"""
42+
Performs cleanup on all clients - called when the server is shut
43+
down (via atexit.register) or reloaded (via runserver_socketio).
44+
"""
45+
for request, socket, context in list(CLIENTS.values()):
46+
client_end(request, socket, context)

django_socketio/example_project/chat/events.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
from chat.models import ChatRoom
77

8-
98
@events.on_message(channel="^room-")
109
def message(request, socket, context, message):
1110
"""
@@ -14,7 +13,8 @@ def message(request, socket, context, message):
1413
"""
1514
room = get_object_or_404(ChatRoom, id=message["room"])
1615
if message["action"] == "start":
17-
user, created = room.users.get_or_create(name=strip_tags(message["name"]))
16+
name = strip_tags(message["name"])
17+
user, created = room.users.get_or_create(name=name)
1818
if not created:
1919
socket.send({"action": "in-use"})
2020
else:
@@ -45,5 +45,6 @@ def finish(request, socket, context):
4545
user = context["user"]
4646
except KeyError:
4747
return
48-
socket.broadcast_channel({"action": "leave", "name": user.name, "id": user.id})
48+
left = {"action": "leave", "name": user.name, "id": user.id}
49+
socket.broadcast_channel(left)
4950
user.delete()

django_socketio/management/commands/runserver_socketio.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from django.utils.autoreload import code_changed, restart_with_reloader
1313
from socketio import SocketIOServer
1414

15+
from django_socketio.clients import client_end_all
1516
from django_socketio.settings import HOST, PORT
1617

1718

@@ -57,6 +58,7 @@ def handle(self, addrport="", *args, **options):
5758
server.serve_forever()
5859
except KeyboardInterrupt:
5960
if RELOAD:
61+
client_end_all()
6062
server.kill()
6163
print
6264
print "Reloading..."

django_socketio/views.py

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,15 @@
11

2-
from atexit import register
32
from datetime import datetime
43
from traceback import print_exc
54

65
from django.http import HttpResponse
76

87
from django_socketio import events
98
from django_socketio.channels import SocketIOChannelProxy
9+
from django_socketio.clients import client_start, client_end
1010
from django_socketio.settings import MESSAGE_LOG_FORMAT
1111

1212

13-
# Maps open Socket.IO session IDs to request/socket pairs for
14-
# guaranteeing the on_finish signal being sent when the server
15-
# stops.
16-
CLIENTS = {}
17-
18-
@register
19-
def cleanup():
20-
"""
21-
Sends the on_finish signal to any open clients when the server
22-
is unexpectedly stopped.
23-
"""
24-
for client in CLIENTS.values():
25-
events.on_finish.send(*client)
26-
2713
def format_log(request, message_type, message):
2814
"""
2915
Formats a log message similar to gevent's pywsgi request logging.
@@ -42,7 +28,7 @@ def socketio(request):
4228
"""
4329
context = {}
4430
socket = SocketIOChannelProxy(request.environ["socketio"])
45-
CLIENTS[socket.session.session_id] = (request, socket, context)
31+
client_start(request, socket, context)
4632
try:
4733
if socket.on_connect():
4834
events.on_connect.send(request, socket, context)
@@ -82,13 +68,5 @@ def socketio(request):
8268
except Exception, exception:
8369
print_exc()
8470
events.on_error.send(request, socket, context, exception)
85-
# Send the unsubscribe event prior to actually unsubscribing, so
86-
# that the finish event can still match channels if applicable.
87-
for channel in socket.channels:
88-
events.on_unsubscribe.send(request, socket, context, channel)
89-
events.on_finish.send(request, socket, context)
90-
# Actually unsubscribe to cleanup channel data.
91-
for channel in socket.channels:
92-
socket.unsubscribe(channel)
93-
del CLIENTS[socket.session.session_id]
71+
client_end(request, socket, context)
9472
return HttpResponse("")

0 commit comments

Comments
 (0)