Permalink
Browse files

Moved client cleanup code from the end of the socket.io view into a f…

…unction 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.
  • Loading branch information...
1 parent ee28e7a commit ad3fb2d7d59caa00ffa5b74544537702a7529c9e @stephenmcd committed Feb 5, 2012
@@ -12,7 +12,7 @@ def send(session_id, message):
"""
Send a message to the socket for the given session ID.
"""
- from django_socketio.views import CLIENTS
+ from django_socketio.clients import CLIENTS
try:
socket = CLIENTS[session_id][1]
except KeyError:
@@ -25,7 +25,7 @@ def broadcast(message):
Find the first socket and use it to broadcast to all sockets
including the socket itself.
"""
- from django_socketio.views import CLIENTS
+ from django_socketio.clients import CLIENTS
try:
socket = CLIENTS.values()[0][1]
except IndexError:
@@ -38,7 +38,7 @@ def broadcast_channel(message, channel):
Find the first socket for the given channel, and use it to
broadcast to the channel, including the socket itself.
"""
- from django_socketio.views import CLIENTS
+ from django_socketio.clients import CLIENTS
from django_socketio.channels import CHANNELS
try:
socket = CLIENTS[CHANNELS.get(channel, [])[0]][1]
View
@@ -0,0 +1,46 @@
+
+from atexit import register
+
+from django_socketio import events
+
+
+# Maps open Socket.IO session IDs to request/socket pairs for
+# running cleanup code and events when the server is shut down
+# or reloaded.
+CLIENTS = {}
+
+
+def client_start(request, socket, context):
+ """
+ Adds the client triple to CLIENTS.
+ """
+ CLIENTS[socket.session.session_id] = (request, socket, context)
+
+
+def client_end(request, socket, context):
+ """
+ Handles cleanup when a session ends for the given client triple.
+ Sends unsubscribe and finish events, actually unsubscribes from
+ any channels subscribed to, and removes the client triple from
+ CLIENTS.
+ """
+ # Send the unsubscribe event prior to actually unsubscribing, so
+ # that the finish event can still match channels if applicable.
+ for channel in socket.channels:
+ events.on_unsubscribe.send(request, socket, context, channel)
+ events.on_finish.send(request, socket, context)
+ # Actually unsubscribe to cleanup channel data.
+ for channel in socket.channels:
+ socket.unsubscribe(channel)
+ # Remove the client.
+ del CLIENTS[socket.session.session_id]
+
+
+@register
+def client_end_all():
+ """
+ Performs cleanup on all clients - called when the server is shut
+ down (via atexit.register) or reloaded (via runserver_socketio).
+ """
+ for request, socket, context in list(CLIENTS.values()):
+ client_end(request, socket, context)
@@ -5,7 +5,6 @@
from chat.models import ChatRoom
-
@events.on_message(channel="^room-")
def message(request, socket, context, message):
"""
@@ -14,7 +13,8 @@ def message(request, socket, context, message):
"""
room = get_object_or_404(ChatRoom, id=message["room"])
if message["action"] == "start":
- user, created = room.users.get_or_create(name=strip_tags(message["name"]))
+ name = strip_tags(message["name"])
+ user, created = room.users.get_or_create(name=name)
if not created:
socket.send({"action": "in-use"})
else:
@@ -45,5 +45,6 @@ def finish(request, socket, context):
user = context["user"]
except KeyError:
return
- socket.broadcast_channel({"action": "leave", "name": user.name, "id": user.id})
+ left = {"action": "leave", "name": user.name, "id": user.id}
+ socket.broadcast_channel(left)
user.delete()
@@ -12,6 +12,7 @@
from django.utils.autoreload import code_changed, restart_with_reloader
from socketio import SocketIOServer
+from django_socketio.clients import client_end_all
from django_socketio.settings import HOST, PORT
@@ -57,6 +58,7 @@ def handle(self, addrport="", *args, **options):
server.serve_forever()
except KeyboardInterrupt:
if RELOAD:
+ client_end_all()
server.kill()
print
print "Reloading..."
View
@@ -1,29 +1,15 @@
-from atexit import register
from datetime import datetime
from traceback import print_exc
from django.http import HttpResponse
from django_socketio import events
from django_socketio.channels import SocketIOChannelProxy
+from django_socketio.clients import client_start, client_end
from django_socketio.settings import MESSAGE_LOG_FORMAT
-# Maps open Socket.IO session IDs to request/socket pairs for
-# guaranteeing the on_finish signal being sent when the server
-# stops.
-CLIENTS = {}
-
-@register
-def cleanup():
- """
- Sends the on_finish signal to any open clients when the server
- is unexpectedly stopped.
- """
- for client in CLIENTS.values():
- events.on_finish.send(*client)
-
def format_log(request, message_type, message):
"""
Formats a log message similar to gevent's pywsgi request logging.
@@ -42,7 +28,7 @@ def socketio(request):
"""
context = {}
socket = SocketIOChannelProxy(request.environ["socketio"])
- CLIENTS[socket.session.session_id] = (request, socket, context)
+ client_start(request, socket, context)
try:
if socket.on_connect():
events.on_connect.send(request, socket, context)
@@ -82,13 +68,5 @@ def socketio(request):
except Exception, exception:
print_exc()
events.on_error.send(request, socket, context, exception)
- # Send the unsubscribe event prior to actually unsubscribing, so
- # that the finish event can still match channels if applicable.
- for channel in socket.channels:
- events.on_unsubscribe.send(request, socket, context, channel)
- events.on_finish.send(request, socket, context)
- # Actually unsubscribe to cleanup channel data.
- for channel in socket.channels:
- socket.unsubscribe(channel)
- del CLIENTS[socket.session.session_id]
+ client_end(request, socket, context)
return HttpResponse("")

0 comments on commit ad3fb2d

Please sign in to comment.