From bcee52cf6f5ee86a3d16f1ca981d3f8b99106c12 Mon Sep 17 00:00:00 2001 From: Mathias Meyer Date: Thu, 31 Dec 2009 18:36:08 +0100 Subject: [PATCH] Initial commit. And it works! --- .gitignore | 1 + LICENSE | 20 +++++++++++++ README | 0 Rakefile | 24 +++++++++++++++ lib/redis_session_store.rb | 61 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 106 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README create mode 100644 Rakefile create mode 100644 lib/redis_session_store.rb diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0c6117d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +pkg \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..1cc481e --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2009 Mathias Meyer + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/README b/README new file mode 100644 index 0000000..e69de29 diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..8798984 --- /dev/null +++ b/Rakefile @@ -0,0 +1,24 @@ +require 'rubygems' +require 'rake/gempackagetask' +require 'rubygems/specification' + +spec = Gem::Specification.new do |s| + s.name = 'redis-session-store' + s.version = '0.1' + s.platform = Gem::Platform::RUBY + s.has_rdoc = true + s.extra_rdoc_files = ["LICENSE"] + s.summary = "A drop-in replacement for e.g. MemCacheStore to store Rails sessions (and Rails sessions only) in Redis." + s.description = s.summary + s.authors = "Mathias Meyer" + s.email = "meyer@paperplanes.de" + s.homepage = "" + s.add_dependency "redis" + s.require_path = 'lib' + s.autorequire = 'redis_session_store' + s.files = %w(README Rakefile) + Dir.glob("{lib}/**/*") +end + +Rake::GemPackageTask.new(spec) do |pkg| + pkg.gem_spec = spec +end diff --git a/lib/redis_session_store.rb b/lib/redis_session_store.rb new file mode 100644 index 0000000..7cbab3e --- /dev/null +++ b/lib/redis_session_store.rb @@ -0,0 +1,61 @@ +require 'redis' + +# Redis session storage for Rails, and for Rails only. Derived from +# the MemCacheStore code, simply dropping in Redis instead. +# +# Options: +# :key => Same as with the other cookie stores, key name +# :secret => Encryption secret for the key +# :host => Redis host name, default is localhost +# :port => Redis port, default is 6370 +# :db => Database number, defaults to 0. Useful to separate your session storage from other data +# :key_prefix => Prefix for keys used in Redis, e.g. myapp-. Useful to separate session storage keys visibly from others. + +class RedisSessionStore < ActionController::Session::AbstractStore + + def initialize(app, options = {}) + # Support old :expires option + options[:expire_after] ||= options[:expires] + + super + + @default_options = { + :namespace => 'rack:session', + :server => 'localhost', + :port => '6379', + :db => 0, + :key_prefix => "" + }.update(options) + + @pool = Redis.new(@default_options) + @mutex = Mutex.new + + super + end + + private + def prefixed(sid) + "#{@default_options[:key_prefix]}#{sid}" + end + + def get_session(env, sid) + sid ||= generate_sid + begin + data = @pool.call_command([:get, prefixed(sid)]) + session = data.nil? ? {} : Marshal.load(data) + rescue Errno::ECONNREFUSED + session = {} + end + [sid, session] + end + + def set_session(env, sid, session_data) + options = env['rack.session.options'] + expiry = options[:expire_after] || nil + @pool.set(prefixed(sid), Marshal.dump(session_data), expiry) + return true + rescue Errno::ECONNREFUSED + return false + end + +end