Permalink
Browse files

Added session implementation

  • Loading branch information...
mrjoes committed Jan 10, 2011
1 parent 0804a94 commit 05f28dd6014ea7dff60e8c88b02f77f09070ca99
Showing with 210 additions and 0 deletions.
  1. +4 −0 .gitignore
  2. +9 −0 README.rst
  3. +6 −0 flashpolicy.xml
  4. +36 −0 setup.py
  5. 0 README → tornadio/__init__.py
  6. +155 −0 tornadio/session.py
View
@@ -0,0 +1,4 @@
+*.swp
+*.swo
+*.pyc
+pyenv
View
@@ -0,0 +1,9 @@
+========
+TornadIO
+========
+
+Credits
+-------
+Authors of SocketTornad.IO project:
+- Brendan W. McAdams bwmcadams@evilmonkeylabs.com
+- `Matt Swanson <http://github.com/swanson>`_
View
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<!DOCTYPE cross-domain-policy SYSTEM "/xml/dtds/cross-domain-policy.dtd">
+<cross-domain-policy>
+ <allow-access-from domain="*" to-ports="*" />
+</cross-domain-policy>
+
View
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+
+try:
+ from setuptools import setup, find_packages
+except ImportError:
+ from distribute_setup import use_setuptools
+ use_setuptools()
+ from setuptools import setup, find_packages
+
+try:
+ license = open('LICENSE').read()
+except:
+ license = None
+
+try:
+ readme = open('README.rst').read()
+except:
+ readme = None
+
+setup(
+ name='TornadIO',
+ version='0.0.1',
+ author='Serge S. Koval',
+ author_email='serge@in-square.net',
+ packages=['tornadio'],
+ scripts=[],
+ url='http://github.com/MrJoes/tornadio/',
+ license=license,
+ description='Socket.io server implementation on top of Tornado framework',
+ long_description=readme,
+ requires=['simplejson', 'tornado'],
+ install_requires=[
+ 'simplejson >= 2.1.0',
+ 'tornado >= 1.1.0'
+ ]
+)
File renamed without changes.
View
@@ -0,0 +1,155 @@
+from heapq import heappush, heappop, heapify
+from time import time, sleep, clock
+from hashlib import md5
+from random import random, randint
+
+class Session(object):
+ def __init__(self, session_id, expiry=None, on_delete=None):
+ self.session_id = session_id
+ self._items = dict()
+ self.promoted = None
+ self.expiry = expiry
+ self.on_delete = on_delete
+ if self.expiry is not None:
+ self.expiry_date = time() + self.expiry
+
+ def promote(self):
+ if self.expiry is not None:
+ self.promoted = time() + self.expiry
+
+ def _item_deleted(self):
+ self.promoted = -1
+
+ if self.on_delete is not None:
+ self.on_delete()
+
+ def get(self, key, default=None):
+ return self._items.get(key, default)
+
+ def set(self, key, value):
+ self._items[key] = value
+
+ def __cmp__(self, other):
+ return cmp(self.expiry_date, other.expiry_date)
+
+ def __repr__(self):
+ return '%f %s %d' % (getattr(self, 'expiry_date', -1), self.session_id, self.promoted or 0)
+
+class SessionManager(object):
+ _items = dict()
+ _queue = []
+
+ @classmethod
+ def _random_key(cls):
+ m = md5()
+ m.update('%s%s' % (random(), time()))
+ return m.hexdigest()
+
+ @classmethod
+ def create(cls, expiry=None, on_delete=None):
+ session = Session(cls._random_key(), expiry, on_delete)
+ cls._items[session.session_id] = session
+
+ if expiry is not None:
+ heappush(cls._queue, session)
+
+ return session
+
+ @classmethod
+ def get(cls, session_id, promote=True):
+ session = cls._items.get(session_id, None)
+
+ if session is not None and promote:
+ session.promote()
+
+ return session
+
+ @classmethod
+ def remove(cls, session_id):
+ session = cls._items.get(session_id, None)
+
+ if session is not None:
+ del cls._items[session_id]
+ session._item_deleted()
+ return True
+
+ return False
+
+ @classmethod
+ def expire(cls, current_time=None):
+ if not cls._queue:
+ return
+
+ if current_time is None:
+ current_time = time()
+
+ while cls._queue:
+ # Top most item is not expired yet
+ top = cls._queue[0]
+
+ # Early exit if item was not promoted and its expiration time
+ # is greater than now.
+ if top.promoted is None and top.expiry_date > current_time:
+ break
+
+ # Pop item from the stack
+ top = heappop(cls._queue)
+
+ # If item is promoted and expiration time somewhere in future
+ # just reschedule it
+ if top.promoted is not None and top.promoted > current_time:
+ top.current_time = top.promoted
+ top.promoted = None
+ heappush(cls._queue, top)
+ else:
+ # Otherwise - remove session
+ del cls._items[top.session_id]
+ top._item_deleted()
+
+def test():
+ while True:
+ for j in xrange(0, 1000):
+ op = randint(0, 5)
+
+ if op == 0:
+ SessionManager.create(randint(1, 10))
+ elif op == 1 and SessionManager._queue:
+ idx = randint(0, len(SessionManager._queue) - 1)
+ item = SessionManager._queue[idx]
+ item.promote()
+ sleep(randint(0,2))
+
+ t = time()
+
+ print 'Before: %d' % (len(SessionManager._queue))
+
+ start = clock()
+
+ SessionManager.expire(t)
+
+ delta = clock() - start
+
+ print 'Queue size: %d, %f' % (len(SessionManager._queue), delta)
+
+ nl = []
+ idx = 0
+ errored = False
+ while SessionManager._queue:
+ x = heappop(SessionManager._queue)
+
+ if t > x.expiry_date:
+ print 'Error: (%d) %f vs %s' % (idx, t, x)
+ errored = True
+
+ nl.append(x)
+ idx += 1;
+
+ if errored:
+ import pdb
+ pdb.set_trace()
+
+ heapify(nl)
+ SessionManager._queue = nl
+
+if __name__ == "__main__":
+ test()

0 comments on commit 05f28dd

Please sign in to comment.