1 # Copyright (C) 2014 Ipsilon project Contributors, for license see COPYING
4 from cherrypy.lib.sessions import Session
5 from ipsilon.util.data import Store, SqlQuery
9 import cPickle as pickle
14 SESSION_TABLE = {'columns': ['id', 'data', 'expiration_time'],
15 'primary_key': ('id', ),
16 'indexes': [('expiration_time',)]
20 class SessionStore(Store):
21 def _initialize_schema(self):
22 q = self._query(self._db, 'sessions', SESSION_TABLE,
25 q._con.close() # pylint: disable=protected-access
27 def _upgrade_schema(self, old_version):
29 # In schema version 2, we added indexes and primary keys
30 # pylint: disable=protected-access
31 table = self._query(self._db, 'sessions', SESSION_TABLE,
33 self._db.add_constraint(table.primary_key)
34 for index in table.indexes:
35 self._db.add_index(index)
38 raise NotImplementedError()
41 # pylint: disable=protected-access
42 table = SqlQuery(self._db, 'sessions', SESSION_TABLE)._table
43 # pylint: disable=no-value-for-parameter
44 d = table.delete().where(table.c.expiration_time
45 <= datetime.datetime.now())
46 return d.execute().rowcount
49 class SqlSession(Session):
58 def setup(cls, **kwargs):
59 """Initialization from cherrypy"""
61 for k, v in kwargs.items():
62 if k == 'storage_dburi':
65 cls._store = SessionStore(database_url=cls.dburi)
66 # pylint: disable=protected-access
67 cls._db = cls._store._db
70 q = SqlQuery(self._db, 'sessions', SESSION_TABLE)
71 result = q.select({'id': self.id})
72 return True if result.fetchone() else False
75 q = SqlQuery(self._db, 'sessions', SESSION_TABLE)
76 result = q.select({'id': self.id})
79 data = str(base64.b64decode(r[1]))
80 return pickle.loads(data)
82 def _save(self, expiration_time):
85 q = SqlQuery(self._db, 'sessions', SESSION_TABLE, trans=True)
86 q.delete({'id': self.id})
87 data = pickle.dumps((self._data, expiration_time), self._proto)
88 q.insert((self.id, base64.b64encode(data), expiration_time))
90 except Exception: # pylint: disable=broad-except
96 q = SqlQuery(self._db, 'sessions', SESSION_TABLE)
97 q.delete({'id': self.id})
99 # copy what RamSession does for now
100 def acquire_lock(self):
101 """Acquire an exclusive lock on the currently-loaded session data."""
103 self.locks.setdefault(self.id, threading.RLock()).acquire()
105 def release_lock(self):
106 """Release the lock on the currently-loaded session data."""
107 self.locks[self.id].release()