1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
|
require 'rack/session/abstract/id'
require 'redis-store'
require 'thread'
require 'redis/rack/connection'
module Rack
module Session
class Redis < Abstract::PersistedSecure
attr_reader :mutex
DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge(
:redis_server => 'redis://127.0.0.1:6379/0/rack:session'
)
def initialize(app, options = {})
super
@mutex = Mutex.new
@conn = ::Redis::Rack::Connection.new(@default_options)
end
def generate_unique_sid(session)
return generate_sid if session.empty?
loop do
sid = generate_sid
first = with do |c|
[*c.setnx(sid.private_id, session, @default_options)].first
end
break sid if [1, true].include?(first)
end
end
def find_session(req, sid)
if req.session.options[:skip]
[generate_sid, {}]
else
with_lock(req, [nil, {}]) do
unless sid and session = get_session_with_fallback(sid)
session = {}
sid = generate_unique_sid(session)
end
[sid, session]
end
end
end
def write_session(req, sid, new_session, options)
with_lock(req, false) do
with { |c| c.set sid.private_id, new_session, options }
sid
end
end
def delete_session(req, sid, options)
with_lock(req) do
with do |c|
c.del(sid.public_id)
c.del(sid.private_id)
end
generate_sid unless options[:drop]
end
end
def threadsafe?
@default_options.fetch(:threadsafe, true)
end
def with_lock(req, default=nil)
@mutex.lock if req.multithread? && threadsafe?
yield
rescue Errno::ECONNREFUSED
if $VERBOSE
warn "#{self} is unable to find Redis server."
warn $!.inspect
end
default
ensure
@mutex.unlock if @mutex.locked?
end
def with(&block)
@conn.with(&block)
end
private
def get_session_with_fallback(sid)
with { |c| c.get(sid.private_id) || c.get(sid.public_id) }
end
end
end
end
|