文档章节

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

Franca
 Franca
发布于 2016/12/12 21:44
字数 557
阅读 140
收藏 0

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()  
        
        
 

© 著作权归作者所有

共有 人打赏支持
Franca
粉丝 0
博文 1
码字总数 557
作品 0
南京
加载中

评论(1)

红薯
红薯
应该来点文字说明
SQLite学习手册(临时文件)

一、简介: 尽管SQLite的数据库是由单一文件构成,然而事实上在SQLite运行时却存在着一些隐含的临时文件,这些临时文件是出于不同的目的而存在的,对于开发者而言,它们是透明的,因此在开发...

涩女郎
2015/08/26
0
0
Android数据的四种存储方式之三——SharedPreferences

Android数据的四种存储方式SharedPreferences、SQLite、Content Provider和File (三) —— SharePreferences 除了SQLite数据库外,SharedPreferences也是一种轻型的数据存储方式,它的本质...

Airship
2015/03/25
0
0
【原创】如何在 libgda 和 SQLite 之间作出选择

How to choose between Libgda and SQLite 如何在 libgda 和 SQLite 之间作出选择 (本文为官方文档翻译,以中英对照形式呈现) Libgda has been added as a new external dependency for G...

摩云飞
2013/03/20
0
0
解决SQLite database is locked

前些时候,同事在站点服务端使用SQlite存储一些临时数据,但是在多人并发的时候Sqlite会抛出异常:The database file is locked , database is locked,而且这个是在客户生产环境下提示出来的...

会飞的蝌蚪
2014/05/12
0
0
Eclipse调试Android工具集锦之四-SQLITE3

原创文章,如有转载,请注明出处:http://blog.csdn.net/yihui823/article/details/6689922 本文章的前提:已经安装了Eclipse和ADT。android SDK也下载完毕。Eclipse里面已经设置好了andro本...

simpower
2014/10/09
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

HTTPS is easy

HTTPS is easy https://www.troyhunt.com/https-is-easy/ HTTPS is easy! In fact, it's so easy I decided to create 4 short videos around 5 minutes each to show people how to enable ......

openthings
17分钟前
0
0
bugList 2

用户端: 1. 上传文件时,当选择:彩色-A3-双面时,第二个图片有bug 应改为 和第一个图片的类型相同 2. 确认打印时,三个下拉选目前有bug 应改为:根据后台配置的商家,group by计算出不同城...

勇恒
20分钟前
2
0
keras cnn 网咯 mnist 分类

搭建貌似比tf是简单很多。。。。。 from keras.datasets import mnistfrom keras.utils import np_utilsfrom keras.models import Sequentialfrom keras.layers import Dense, Activat......

阿豪boy
22分钟前
0
0
解决 /var/run/nginx.pid failed

nginx: [error] open() "/var/run/nginx.pid" failed (2: No such file or directory) sudo nginx -c /etc/nginx/nginx.conf nginx -s reload...

驛路梨花醉美
24分钟前
0
0
nginx负载均衡-ssl原理-生成ssl密钥对-nginx配置ssl

nginx负载均衡: 1.创建配置文件 vim /usr/local/nginx/conf/vhost/load.conf #添加以下内容: upstream qq_com #名字自定义,借助此模块定义多个IP,后面...

ZHENG-JY
24分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部