diff options
author | Joshua Peek <josh@joshpeek.com> | 2008-11-22 14:33:00 -0600 |
---|---|---|
committer | Joshua Peek <josh@joshpeek.com> | 2008-11-22 14:33:00 -0600 |
commit | cc67272cba35e50afa73cfec856c1677b204ae7e (patch) | |
tree | 1bdbc4862fe0ea486bf8d2476ab12184e4b71807 /actionpack/lib/action_controller/vendor/rack-0.4.0/rack/session/memcache.rb | |
parent | 4b36f76e7a997fb03a6cccb08b8272ddccde5a3e (diff) | |
download | rails-cc67272cba35e50afa73cfec856c1677b204ae7e.tar.gz rails-cc67272cba35e50afa73cfec856c1677b204ae7e.tar.bz2 rails-cc67272cba35e50afa73cfec856c1677b204ae7e.zip |
Vendor rack 0.4.0
Diffstat (limited to 'actionpack/lib/action_controller/vendor/rack-0.4.0/rack/session/memcache.rb')
-rw-r--r-- | actionpack/lib/action_controller/vendor/rack-0.4.0/rack/session/memcache.rb | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/actionpack/lib/action_controller/vendor/rack-0.4.0/rack/session/memcache.rb b/actionpack/lib/action_controller/vendor/rack-0.4.0/rack/session/memcache.rb new file mode 100644 index 0000000000..7cda9d8697 --- /dev/null +++ b/actionpack/lib/action_controller/vendor/rack-0.4.0/rack/session/memcache.rb @@ -0,0 +1,97 @@ +# AUTHOR: blink <blinketje@gmail.com>; blink#ruby-lang@irc.freenode.net + +require 'rack/session/abstract/id' +require 'memcache' + +module Rack + module Session + # Rack::Session::Memcache provides simple cookie based session management. + # Session data is stored in memcached. The corresponding session key is + # maintained in the cookie. + # You may treat Session::Memcache as you would Session::Pool with the + # following caveats. + # + # * Setting :expire_after to 0 would note to the Memcache server to hang + # onto the session data until it would drop it according to it's own + # specifications. However, the cookie sent to the client would expire + # immediately. + # + # Note that memcache does drop data before it may be listed to expire. For + # a full description of behaviour, please see memcache's documentation. + + class Memcache < Abstract::ID + attr_reader :mutex, :pool + DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge({ + :namespace => 'rack:session', + :memcache_server => 'localhost:11211' + }) + + def initialize(app, options={}) + super + @pool = MemCache.new @default_options[:memcache_server], @default_options + unless @pool.servers.any?{|s|s.alive?} + raise "#{self} unable to find server during initialization." + end + @mutex = Mutex.new + end + + private + + def get_session(env, sid) + session = sid && @pool.get(sid) + unless session and session.is_a?(Hash) + session = {} + lc = 0 + @mutex.synchronize do + begin + raise RuntimeError, 'Unique id finding looping excessively' if (lc+=1) > 1000 + sid = "%08x" % rand(0xffffffff) + ret = @pool.add(sid, session) + end until /^STORED/ =~ ret + end + end + class << session + @deleted = [] + def delete key + (@deleted||=[]) << key + super + end + end + [sid, session] + rescue MemCache::MemCacheError, Errno::ECONNREFUSED # MemCache server cannot be contacted + warn "#{self} is unable to find server." + warn $!.inspect + return [ nil, {} ] + end + + def set_session(env, sid) + session = env['rack.session'] + options = env['rack.session.options'] + expiry = options[:expire_after] || 0 + o, s = @mutex.synchronize do + old_session = @pool.get(sid) + unless old_session.is_a?(Hash) + warn 'Session not properly initialized.' if $DEBUG + old_session = {} + @pool.add sid, old_session, expiry + end + session.instance_eval do + @deleted.each{|k| old_session.delete(k) } if defined? @deleted + end + @pool.set sid, old_session.merge(session), expiry + [old_session, session] + end + s.each do |k,v| + next unless o.has_key?(k) and v != o[k] + warn "session value assignment collision at #{k.inspect}:"+ + "\n\t#{o[k].inspect}\n\t#{v.inspect}" + end if $DEBUG and env['rack.multithread'] + return true + rescue MemCache::MemCacheError, Errno::ECONNREFUSED # MemCache server cannot be contacted + warn "#{self} is unable to find server." + warn $!.inspect + return false + end + end + end +end |