From 28ad1818ba1e74eaf358f01e4f5776a0c23aba81 Mon Sep 17 00:00:00 2001 From: Jared Kipe Date: Mon, 1 Jul 2019 13:51:03 -0700 Subject: [PATCH] Initial commit of `session_redis` for 11.0 --- session_redis/__init__.py | 2 + session_redis/__manifest__.py | 30 +++++++++++++ session_redis/session_redis.py | 77 ++++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+) create mode 100755 session_redis/__init__.py create mode 100755 session_redis/__manifest__.py create mode 100755 session_redis/session_redis.py diff --git a/session_redis/__init__.py b/session_redis/__init__.py new file mode 100755 index 00000000..612ceb86 --- /dev/null +++ b/session_redis/__init__.py @@ -0,0 +1,2 @@ +from . import session_redis + diff --git a/session_redis/__manifest__.py b/session_redis/__manifest__.py new file mode 100755 index 00000000..b669c933 --- /dev/null +++ b/session_redis/__manifest__.py @@ -0,0 +1,30 @@ +{ + "name": "Redis Sessions", + "version": "11.0.1.0.0", + "depends": ["base"], + "author": "Hibou Corp.", + "license": "AGPL-3", + "description": """Use Redis for Session storage instead of File system + +To use, you must load `session_redis` as a server wide module. +Example Configuration file overrides un-needed ones will be commented and show the default or example. + +server_wide_modules = web,session_redis +session_redis = True +;session_redis_host = localhost +;session_redis_port = 6379 +;session_redis_dbindex = 1 +;session_redis_pass = x +;session_redis_expire = 604800 + + """, + "summary": "", + "website": "", + "category": 'Tools', + "auto_install": False, + "installable": True, + "application": False, + "external_dependencies": { + 'python': ['redis'], + }, +} diff --git a/session_redis/session_redis.py b/session_redis/session_redis.py new file mode 100755 index 00000000..fcceaef6 --- /dev/null +++ b/session_redis/session_redis.py @@ -0,0 +1,77 @@ +import werkzeug.contrib.sessions +from odoo import http, tools +from odoo.tools.func import lazy_property + + +def is_redis_session_store_activated(): + return tools.config.get('session_redis') + + +try: + import cPickle +except ImportError: + import _pickle as cPickle + +try: + import redis +except ImportError: + if is_redis_session_store_activated(): + raise + + +DEFAULT_SESSION_TIMEOUT = 60 * 60 * 24 * 7 # 1 weeks in seconds + + +class RedisSessionStore(werkzeug.contrib.sessions.SessionStore): + + def __init__(self, *args, **kwargs): + super(RedisSessionStore, self).__init__(*args, **kwargs) + self.expire = kwargs.get('expire', DEFAULT_SESSION_TIMEOUT) + if self.expire == DEFAULT_SESSION_TIMEOUT: + self.expire = int(tools.config.get('session_redis_expire', DEFAULT_SESSION_TIMEOUT)) + self.key_prefix = kwargs.get('key_prefix', '') + self.redis = redis.Redis( + host=tools.config.get('session_redis_host', 'localhost'), + port=int(tools.config.get('session_redis_port', 6379)), + db=int(tools.config.get('session_redis_dbindex', 1)), + password=tools.config.get('session_redis_pass', None)) + self._is_redis_server_running() + + def _get_session_key(self, sid): + key = self.key_prefix + sid + return key.encode('utf-8') + + def _is_redis_server_running(self): + self.redis.ping() + + def save(self, session): + key = self._get_session_key(session.sid) + data = cPickle.dumps(dict(session)) + self.redis.setex(name=key, value=data, time=self.expire) + + def delete(self, session): + key = self._get_session_key(session.sid) + self.redis.delete(key) + + def get(self, sid): + key = self._get_session_key(sid) + data = self.redis.get(key) + if data: + self.redis.setex(name=key, value=data, time=self.expire) + data = cPickle.loads(data) + else: + data = {} + return self.session_class(data, sid, False) + + +if is_redis_session_store_activated(): + def session_gc(session_store): + pass + + @lazy_property + def session_store(self): + return RedisSessionStore(session_class=http.OpenERPSession) + + http.session_gc = session_gc + http.Root.session_store = session_store +