Skip to content

Commit

Permalink
More granularity in session failure modes.
Browse files Browse the repository at this point in the history
  • Loading branch information
sdiehl committed Mar 7, 2012
1 parent 3d89922 commit ea2360a
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 4 deletions.
14 changes: 14 additions & 0 deletions gevent_sockjs/devserver.py
@@ -1,4 +1,18 @@
"""
This module is most like what a user would define in their
application, namely the
- Routes
- Connection Handlers
The one's sketched here are the Echo, Disabled Websockets, and
the Close connection handlers which are used by the protocol test
suite.
"""

import gevent.monkey

# Moneky patching stdlib is not a neccesity for all use cases
gevent.monkey.patch_all()

from server import SockJSServer
Expand Down
2 changes: 1 addition & 1 deletion gevent_sockjs/router.py
Expand Up @@ -103,7 +103,7 @@ def broadcast(self, channel, message):

def close(self):
if self.session:
self.session.kill()
self.session.interrupt()
else:
raise Exception("Tried to close closed session")

Expand Down
31 changes: 28 additions & 3 deletions gevent_sockjs/session.py
Expand Up @@ -23,6 +23,15 @@ def __init__(self, server, session_id=None):
self.forever = False
self.session_id = self.generate_uid()

# Whether this was closed explictly by client vs
# internally by garbage collection.
self.interrupted = False

# When a polling request is closed by a network error - not by
# server, the session should be automatically closed. When there
# is a network error - we're in an undefined state. Some messages
# may have been lost, there is not much we can do about it.
self.network_error = False

# Async event, use rawlink to string callbacks
self.timeout = Event()
Expand Down Expand Up @@ -57,6 +66,10 @@ def persist(self, extension=None, forever=False):
def post_delete(self):
pass

def kill(self):
self.killed = True
self.expire()

def expire(self):
"""
Manually expire a session.
Expand All @@ -81,15 +94,18 @@ def add_message(self, msg):
def get_messages(self, **kwargs):
raise NotImplemented()

def kill(self):
raise NotImplemented()

def is_locked(self):
return self.locked.is_set()

def is_network_error(self):
return self.network_error

def is_expired(self):
return self.expired

def is_interrupted(self):
return self.interrupted

def lock(self):
self.locked.set()

Expand Down Expand Up @@ -137,6 +153,15 @@ def get_messages(self, **kwargs):
finally:
return accum

def interrupt(self):
"""
A kill event trigged through a client accessible endpoint
Internal expires will not have is_interupted() == True
"""
self.interrupted = True
self.kill()

def kill(self):
self.connected = False

Expand Down
8 changes: 8 additions & 0 deletions gevent_sockjs/transports.py
Expand Up @@ -179,12 +179,20 @@ def __call__(self, handler, request_method, raw_request_data):
handler.enable_cors()
handler.write_js(protocol.OPEN)
return []

elif self.session.is_network_error():
interrupt_error = protocol.close_frame(1002, "Connection interrupted")
handler.write_text(interrupt_error)
return []

elif self.session.is_expired():
close_error = protocol.close_frame(3000, "Go away!")
handler.write_text(close_error)
return []

elif self.session.is_locked():
lock_error = protocol.close_frame(2010, "Another connection still open")
self.session.network_error = True
handler.write_text(lock_error)
return []
else:
Expand Down

0 comments on commit ea2360a

Please sign in to comment.