基于 tornado框架 , 利用sqlite 的 内存数据库实现 session

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from sqlalchemy import Column, String, create_engine, Integer, Text
import time
import os
import base64
import hashlib
import hmac
import json
from globalstring import cookie_name
import tornado
from time import sleep
from utils.logger import WebLog, AlarmPoster

_Session = sessionmaker()
_Base = declarative_base()

def init(timeout = 900, isEcho=False):
    engine = create_engine('sqlite:///:memory:', echo=isEcho)
    _Session.configure(bind=engine)
    _Base.metadata.create_all(engine)
    UserSession.set_timeout(timeout)


class _UserSessionData(_Base):
    __tablename__ = 'sessiondata'
    sid = Column(String(64), primary_key = True, unique = True)
    createtime = Column(Integer, default = 0)
    lasttime = Column(Integer, default = 0)
    expiretime= Column(Integer, index=True, default = 0)
    content = Column(Text, default = '')


class UserSession(object):
    _timeout = 0
    @classmethod
    def set_timeout(cls, timeout):
        cls._timeout = timeout
    def __init__(self, requesthandler):
        self._requesthandler = requesthandler
        self._dbdata = None
        self._dbsession = _Session()
        self._delete = False
        self._isNew = False;

    def _gen_sid(self):
        h = hmac.new(str(time.time()), os.urandom(128), hashlib.sha256)
        return base64.b64encode(h.digest())
                                                      
    def prepare(self):
        #if it is run already, run
        if self._dbdata:
            return
        sid = self._requesthandler.get_cookie(cookie_name.sessionId)
        if sid :
            self._dbdata = self._dbsession.query(_UserSessionData).filter(_UserSessionData.sid == sid).one_or_none()

            try:
                if self._dbdata is not None:
                    self._data = json.loads(self._dbdata.content)                    
                    return
                else:
                    sid = None 
            except:
                sid = None
        sid = self._gen_sid()
        self._dbdata = _UserSessionData(sid=sid)
        self._data = dict()
        self._sync()
        self._dbsession.add(self._dbdata)
        self._isNew = True
        
    @property
    def isNew(self):
        return self._isNew
    
    def _sync(self):
        n =  int(time.time())
        if not self._dbdata.createtime:
            self._dbdata.createtime = n
        self._dbdata.lasttime = n
        self._dbdata.expiretime = (n + self._timeout + 9)//10 * 10 
        self._dbdata.content = json.dumps(self._data)
    
    def clear(self):
        self.prepare()
        self._delete = True
        #sync the session with the db data, or else we can NOT delete the record via that way
        self._dbsession.commit()
        self._dbsession.delete(self._dbdata)
        self._dbsession.commit()
        self._data.clear()
        self._requesthandler.clear_cookie(cookie_name.sessionId)
    
    def finish(self):
        if not self._dbdata:
            self._requesthandler.log.debug('do othing')
            return
        if self._delete:
            return
        try:
            if not self._delete:
                self._sync()
            self._dbsession.commit()
            self._requesthandler.set_cookie(cookie_name.sessionId, self.sid)
            self._requesthandler.log.debug('write sid %s', self.sid)
        except Exception as e:
            print e
            self._dbsession.rollback()
        finally:
            self._dbsession.close() 
    @property
    def data(self):
        self.prepare()
        return self._data
               
    @property
    def sid(self):
        self.prepare()
        return self._dbdata.sid
    
    @property
    def createtime(self):
        self.prepare()
        return self._dbdata.createtime
    
    @property
    def expiretime(self):
        self.prepare()
        return self._dbdata.expiretime

    @property
    def lasttime(self):
        self.prepare()
        return self._dbdata.lasttime
    
_log = WebLog()  
class UserSessionManager(object):
    
    @staticmethod
    def clear_expire_data():
        s = _Session()
        n =  int(time.time())//10 * 10
        try:
            _log.debug('clear_expire_data is running')
            s.query(_UserSessionData).filter(_UserSessionData.expiretime == n).delete()
            s.commit()
        except Exception as e:
            _log.error('clear_expire_data exception:' +e.msg)
        finally:
            s.close()
            del s

  
    @staticmethod
    def clear_expire_data_strick():
        s = _Session()
        n =  int(time.time())
        try:
            _log.info('clear_expire_data_strick is running')
            AlarmPoster.post('clear expire session strickly')
            s.query(_UserSessionData).filter(_UserSessionData.expiretime < n).delete()
            s.commit()
        except Exception as e:
            _log.info('clear_expire_data_strick exception:' +e.msg)
        finally:
            s.close()
            del s
    
    @classmethod
    def install(cls):
        m = UserSessionManager()
        _log.info('install')
        cls.normal = tornado.ioloop.PeriodicCallback(m.clear_expire_data, 5 * 1000)
        cls.normal.start()
        c = time.localtime(tornado.ioloop.IOLoop.instance().time())
        #after x hours, it is 3:00~4:00
        x = 24 + 3 - c.tm_hour 
        x = x if x < 24 else x - 24
        def cycle():
            m.clear_expire_data_strick()
            _log.info('install strick clear')
            cls.strick = tornado.ioloop.PeriodicCallback(m.clear_expire_data, 24 * 3600 * 1000)
            cls.strick.start()
        if x > 0:
            cls.delay = tornado.ioloop.IOLoop.instance().call_later(x * 3600, cycle)
        else:
            cycle()
    
    @classmethod
    def uninstall(cls):
        _log.info('uninstall')
        if hasattr(cls, 'normal'):
            cls.normal.stop()
        if hasattr(cls, 'delay'):
            tornado.ioloop.IOLoop.instance().remove_timeout(cls.delay)
        if hasattr(cls, 'strick'):
            cls.strick.stop()  
        
        
 

转载于:https://my.oschina.net/u/3133916/blog/804736

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值