Exemple #1
0
    class RedisSessionObject():
        implements(ISession)

        def __init__(self, request):
            self._options = _options
            self.rd = None
            self._master_rd = False
            self.request = request
            self._data = None
            self.id = None
            self._new_session = True
            self._changed = False

            cookie = self.request.headers.get('Cookie')
            if cookie is None:
                self.__create_id()
            else:
                c = SimpleCookie()
                c.load(cookie)
                session_cookie = c.get(self._options['_cookie_name'])
                if session_cookie is None:
                    #new session!
                    self.__create_id()
                else:
                    self.id = session_cookie.value
                    self._new_session = False

            def session_callback(request, response):
                exception = getattr(request, 'exception', None)
                commit = self._changed
                increase_expire_mod = _options['_increase_expire_mod']
                if increase_expire_mod > 0:
                    rnd = round(random.random() * 1000000)
                    mod = rnd % increase_expire_mod
                    if not mod:
                        #                        print 'Saving due to increase_expire_mod'
                        commit = True

                if exception is None and commit:
                    self.__save()
                    cookie = SimpleCookie()
                    _cname = self._options['_cookie_name']
                    cookie[_cname] = self.id
                    domain = self._options.get('cookie_domain')
                    cookie[_cname]['path'] = _options['_path']
                    if domain is not None:
                        cookie[_cname]['domain'] = domain
                    if self._options['_secure']:
                        cookie[_cname]['secure'] = True
                    header = cookie[_cname].output(header='')
                    #                    print 'Writing cookie header:',header
                    response.headerlist.append(('Set-Cookie', header))

            request.add_response_callback(session_callback)

        # private methods
        def __init_rd(self, master=False):
            if self.rd is None:
                if master:
                    self.rd = StrictRedis(host=_redis_servers[0][0],
                                          port=_redis_servers[0][1],
                                          db=_redis_servers[0][2])
                    self._master_rd = True
                else:
                    server = random.choice(_redis_servers)
                    self.rd = StrictRedis(host=server[0],
                                          port=server[1],
                                          db=server[2])
                    self._master_rd = False
            elif master and not self._master_rd:
                self.rd = StrictRedis(host=_redis_servers[0][0],
                                      port=_redis_servers[0][1],
                                      db=_redis_servers[0][2])
                self._master_rd = True

        def __key(self):
            return 'rd:ses:%s' % self.id

        def __load(self):
            if self._data is None:
                self.__init_rd()
                data = self.rd.get(self.__key())
                if data is not None:
                    self._data = msgpack.unpackb(data,
                                                 use_list=False,
                                                 encoding='utf-8')
                else:
                    self._data = {}

        def __save(self):
            if self._data is not None and len(self._data):
                self.__init_rd(master=True)
                self.rd.setex(self.__key(), self._options['_expire'],
                              msgpack.packb(self._data, encoding='utf-8'))

        def __create_id(self):
            self.id = hashlib.sha1(
                hashlib.sha1("%f%s%f%s" %
                             (time.time(), id({}), random.random(),
                              getpid())).hexdigest(), ).hexdigest()

        def init_with_id(self, session_id):
            """
            Init the session with custom id. the session data is no loaded immediately but loaded only when data is accessed
            :param session_id:
            :return: self
            """
            self.id = session_id
            self._data = None
            return self

        def set_expire(self, expire):
            self._options['_expire'] = expire

        # ISession API
        def save(self):
            self._changed = True

        def invalidate(self):
            self.__init_rd(master=True)
            self.rd.delete(self.__key())
            #todo: delete cookie

        def changed(self):
            self._changed = True

        def flash(self, msg, queue='', allow_duplicate=True):
            self.__load()
            key = '_flsh:%s_' % queue
            q = self.get(key, [])
            if not allow_duplicate:
                if msg not in q:
                    q.append(msg)
            else:
                q.append(msg)
            self[key] = q

        def pop_flash(self, queue=''):
            self.__load()
            key = '_flsh:%s_' % queue
            q = self.get(key, [])
            if len(q):
                e = q.pop()
                self[key] = q
                return e
            return None

        def peek_flash(self, queue=''):
            self.__load()
            key = '_flsh:%s_' % queue
            q = self.get(key, [])
            if len(q):
                e = q[0]
                return e
            return None

        def new_csrf_token(self):
            token = os.urandom(20).encode('hex')
            self['_csrft_'] = token
            return token

        def get_csrf_token(self):
            token = self.get('_csrft_', None)
            if token is None:
                token = self.new_csrf_token()
            return token

        # mapping methods
        def __getitem__(self, key):
            self.__load()
            return self._data[key]

        def get(self, key, default=None):
            self.__load()
            return self._data.get(key, default)

        def __delitem__(self, key):
            self.__load()
            del self._data[key]
            self._changed = True

        def __setitem__(self, key, value):
            self.__load()
            self._data[key] = value
            self._changed = True

        def keys(self):
            self.__load()
            return self._data.keys()

        def values(self):
            self.__load()
            return self._data.values()

        def items(self):
            self.__load()
            return self._data.items()

        def iterkeys(self):
            self.__load()
            return iter(self._data.keys())

        def itervalues(self):
            self.__load()
            return iter(self._data.values())

        def iteritems(self):
            self.__load()
            return iter(self._data.items())

        def clear(self):
            self.__load()
            self._data = {}
            self._changed = True

        def update(self, d):
            self.__load()
            for k in self._data.keys():
                d[k] = self._data[k]

        def multi_set(self, d):
            #            print '[update]', self.id
            self.__load()
            for k in d.keys():
                self._data[k] = d[k]
            self._changed = True

        def setdefault(self, key, default=None):
            """D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D"""
            self.__load()
            if key in self._data:
                return self._data[key]
            else:
                self._data[key] = default
                self._changed = True
                return default

        def pop(self, k, *args):
            """remove specified key and return the corresponding value
            ``*args`` may contain a single default value, or may not be supplied.
            If key is not found, default is returned if given, otherwise
            ``KeyError`` is raised"""
            pass

        def popitem(self):
            """remove and return some (key, value) pair as a
            2-tuple; but raise ``KeyError`` if mapping is empty"""
            pass

        def __len__(self):
            self.__load()
            return len(self._data)

        def __iter__(self):
            return self.iterkeys()

        def __contains__(self, key):
            self.__load()
            return key in self._data

        @property
        def new(self):
            return self._new_session
    class RedisSessionObject():
        implements(ISession)

        def __init__(self, request):
            self._options = _options
            self.rd = None
            self._master_rd = False
            self.request = request
            self._data = None
            self.id = None
            self._new_session = True
            self._changed = False

            cookie = self.request.headers.get('Cookie')
            if cookie is None:
                self.__create_id()
            else:
                c = SimpleCookie()
                c.load(cookie)
                session_cookie = c.get(self._options['_cookie_name'])
                if session_cookie is None:
                    #new session!
                    self.__create_id()
                else:
                    self.id = session_cookie.value
                    self._new_session = False

            def session_callback(request, response):
                exception = getattr(request, 'exception', None)
                commit = self._changed
                increase_expire_mod = _options['_increase_expire_mod']
                if increase_expire_mod > 0:
                    rnd = round(random.random() * 1000000)
                    mod = rnd % increase_expire_mod
                    if not mod:
                    #                        print 'Saving due to increase_expire_mod'
                        commit = True

                if exception is None and commit:
                    self.__save()
                    cookie = SimpleCookie()
                    _cname = self._options['_cookie_name']
                    cookie[_cname] = self.id
                    domain = self._options.get('cookie_domain')
                    cookie[_cname]['path'] = _options['_path']
                    if domain is not None:
                        cookie[_cname]['domain'] = domain
                    if self._options['_secure']:
                        cookie[_cname]['secure'] = True
                    header = cookie[_cname].output(header='')
                    #                    print 'Writing cookie header:',header
                    response.headerlist.append(('Set-Cookie', header))

            request.add_response_callback(session_callback)

        # private methods
        def __init_rd(self, master=False):
            if self.rd is None:
                if master:
                    self.rd = StrictRedis(host=_redis_servers[0][0], port=_redis_servers[0][1], db=_redis_servers[0][2])
                    self._master_rd = True
                else:
                    server = random.choice(_redis_servers)
                    self.rd = StrictRedis(host=server[0], port=server[1], db=server[2])
                    self._master_rd = False
            elif master and not self._master_rd:
                self.rd = StrictRedis(host=_redis_servers[0][0], port=_redis_servers[0][1], db=_redis_servers[0][2])
                self._master_rd = True

        def __key(self):
            return 'rd:ses:%s' % self.id

        def __load(self):
            if self._data is None:
                self.__init_rd()
                data = self.rd.get(self.__key())
                if data is not None:
                    self._data = msgpack.unpackb(data, use_list=True, encoding='utf-8')
                else:
                    self._data = {}

        def __save(self):
            if self._data is not None and len(self._data):
                self.__init_rd(master=True)
                self.rd.setex(self.__key(), self._options['_expire'], msgpack.packb(self._data, encoding='utf-8'))

        def __create_id(self):
            self.id = hashlib.sha1(hashlib.sha1("%f%s%f%s" % (time.time(), id({}), random.random(), getpid())).hexdigest(), ).hexdigest()

        def init_with_id(self, session_id):
            """
            Init the session with custom id. the session data is no loaded immediately but loaded only when data is accessed
            :param session_id:
            :return: self
            """
            self.id = session_id
            self._data = None
            return self

        def set_expire(self, expire):
            self._options['_expire'] = expire

        # ISession API
        def save(self):
            self._changed = True

        def invalidate(self):
            self.__init_rd(master=True)
            self.rd.delete(self.__key())
            #todo: delete cookie

        def changed(self):
            self._changed = True

        def flash(self, msg, queue='', allow_duplicate=True):
            self.__load()
            key = '_flsh:%s_' % queue
            q = self.get(key, [])
            if not allow_duplicate:
                if msg not in q:
                    q.append(msg)
            else:
                q.append(msg)
            self[key] = q

        def pop_flash(self, queue=''):
            self.__load()
            key = '_flsh:%s_' % queue
            q = self.get(key, [])
            if len(q):
                e = q.pop()
                self[key] = q
                return e
            return None

        def peek_flash(self, queue=''):
            self.__load()
            key = '_flsh:%s_' % queue
            q = self.get(key, [])
            if len(q):
                e = q[0]
                return e
            return None

        def new_csrf_token(self):
            token = os.urandom(20).encode('hex')
            self['_csrft_'] = token
            return token

        def get_csrf_token(self):
            token = self.get('_csrft_', None)
            if token is None:
                token = self.new_csrf_token()
            return token

        # mapping methods
        def __getitem__(self, key):
            self.__load()
            return self._data[key]

        def get(self, key, default=None):
            self.__load()
            return self._data.get(key, default)

        def __delitem__(self, key):
            self.__load()
            del self._data[key]
            self._changed = True

        def __setitem__(self, key, value):
            self.__load()
            self._data[key] = value
            self._changed = True

        def keys(self):
            self.__load()
            return self._data.keys()

        def values(self):
            self.__load()
            return self._data.values()

        def items(self):
            self.__load()
            return self._data.items()

        def iterkeys(self):
            self.__load()
            return iter(self._data.keys())

        def itervalues(self):
            self.__load()
            return iter(self._data.values())

        def iteritems(self):
            self.__load()
            return iter(self._data.items())

        def clear(self):
            self.__load()
            self._data = {}
            self._changed = True

        def update(self, d):
            self.__load()
            for k in self._data.keys():
                d[k] = self._data[k]

        def multi_set(self, d):
#            print '[update]', self.id
            self.__load()
            for k in d.keys():
                self._data[k] = d[k]
            self._changed = True

        def setdefault(self, key, default=None):
            """D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D"""
            pass

        def pop(self, k, *args):
            """remove specified key and return the corresponding value
            ``*args`` may contain a single default value, or may not be supplied.
            If key is not found, default is returned if given, otherwise
            ``KeyError`` is raised"""
            pass

        def popitem(self):
            """remove and return some (key, value) pair as a
            2-tuple; but raise ``KeyError`` if mapping is empty"""
            pass

        def __len__(self):
            self.__load()
            return len(self._data)


        def __iter__(self):
            return self.iterkeys()

        def __contains__(self, key):
            self.__load()
            return key in self._data

        @property
        def new(self):
            return self._new_session