文档章节

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

Franca
 Franca
发布于 2016/12/12 21:44
字数 557
阅读 149
收藏 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
【原创】如何在 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
Android数据的四种存储方式之三——SharedPreferences

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

Airship
2015/03/25
0
0
发布至今18年,为什么SQLite一定要用C语言来开发?

SQLite 选择 C 语言的理由是?为什么不选择 Go 或者 Rust? C 语言是最好的 SQLite 在 2000 年 5 月 29 日发布,并一直使用 C 语言实现。C 语言一直是实现 SQLite 这类软件库的最佳语言,目前...

程序师
08/23
0
0
解决SQLite database is locked

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

会飞的蝌蚪
2014/05/12
0
0

没有更多内容

加载失败,请刷新页面

加载更多

kubeadm部署kubernetes集群

一、环境要求 这里使用RHEL7.5 master、etcd:192.168.10.101,主机名:master node1:192.168.10.103,主机名:node1 node2:192.168.10.104,主机名:node2 所有机子能基于主机名通信,编辑...

人在艹木中
28分钟前
1
0
Shell特殊符号总结以及cut,sort,wc,uniq,tee,tr,split命令

特殊符号总结一 * 任意个任意字符 ? 任意一个字符 # 注释字符 \ 脱义字符 | 管道符 # #号后的备注被忽略[root@centos01 ~]# ls a.txt # 备注 a.txt[root@centos01 ~]# a=1[root@centos01...

野雪球
今天
2
0
OSChina 周二乱弹 —— 程序员圣衣

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @达尔文:分享Skeeter Davis的单曲《The End of the World》 《The End of the World》- Skeeter Davis 手机党少年们想听歌,请使劲儿戳(这里...

小小编辑
今天
13
0
[ python import module ] 导入模块

import moudle_name ----> import module_name.py ---> import module_name.py文件路径 -----> sys.path (这里进行查找文件) # from app.web import Personimport app.web.Person as Pe......

_______-
昨天
5
0
Redis性能问题排查解决手册

一、性能相关的数据指标 通过Redis-cli命令行界面访问到Redis服务器,然后使用info命令获取所有与Redis服务相关的信息。通过这些信息来分析文章后面提到的一些性能指标。 nfo命令输出的数据可...

IT--小哥
昨天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部