文档章节

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

Franca
 Franca
发布于 2016/12/12 21:44
字数 557
阅读 154
收藏 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 数据库

1. 介绍 SQLite 是一个开源的嵌入式关系数据库,实现自包容、零配置、支持事务的SQL数据库引擎。 其特点是高度便携、使用方便、结构紧凑、高效、可靠。 与其他数据库管理系统不同,SQLite 的...

红薯
2012/05/11
53K
59
一个小时内学习 SQLite 数据库

1. 介绍 SQLite 是一个开源的嵌入式关系数据库,实现自包容、零配置、支持事务的SQL数据库引擎。 其特点是高度便携、使用方便、结构紧凑、高效、可靠。 与其他数据库管理系统不同,SQLite 的...

曾沙
2012/11/27
1K
0
Tornado web实时聊天室

Chat Room web 实时聊天室 基于tornado服务器,Redis内存数据库,SQlite 源码:https://github.com/suliangxd/ChatRoom 思路: 当用户进入某个聊天室,即相当于订阅了此聊天室对应在redis里的...

su03121231
2015/08/12
715
1
SQLite学习手册(临时文件)

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

涩女郎
2015/08/26
0
0
数据库访问之Sqlite的不同之处

在我的Winform开发框架中,底层的数据访问支持多种不同的数据库,在数据库访问的开发过程中,发现Sqlite多数情况下,操作都和SqlServer或者说是和标准Sql差不多的。当然,Sqlite本身也有一些...

长平狐
2012/08/22
90
0

没有更多内容

加载失败,请刷新页面

加载更多

vue-cli 3 分环境打包

在vue-cli3的项目中, npm run serve时会把process.env.NODE_ENV设置为‘development’; npm run build 时会把process.env.NODE_ENV设置为‘production’; 此时只要根据process.env.NODE_...

灰白发
16分钟前
1
0
集合初始化,泛型及相关操作

集合初始化通常进行分配容量,设置特定参数等相关工作,推荐在任何情况下,都需要显式地设定集合容量的初始大小。 ArrayList 使用无参构造时,默认大小为 10 ,也就是说在第一次add的时候,分...

Canaan_
25分钟前
1
0
Sping之项目中pofile的应用

工程中,我们必须要面对的一件事就是, 开发环境中使用的数据库连接地址等与生产上的不同, 如果上线, 那么我们是否还要手动修改这些地址么, 这样做有很多弊端, 不方便, 这时我们就可以使用spr...

克虏伯
32分钟前
0
0
Linux中安装MySQL

Linux中安装MySQL 一、准备工作 此处准备的操作系统位CentOS 7。 MySQL安装包: MySQL-server-5.6.29-1.linux_glibc2.5.x86_64.rpm MySQL-client-5.6.29-1.linux_glibc2.5.x86_64.rpm 将准备......

星汉
37分钟前
1
0
深入理解Hadoop之HDFS架构

Hadoop分布式文件系统(HDFS)是一种分布式文件系统。它与现有的分布式文件系统有许多相似之处。但是,与其他分布式文件系统的差异是值得我们注意的: HDFS具有高度容错能力,旨在部署在低成...

架构师springboot
42分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部