mongo_rack 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +4 -4
- data/aa.rb +22 -0
- data/fred.rb +26 -0
- data/lib/mongo_rack.rb +87 -25
- data/spec/mongo_rack_spec.rb +55 -10
- data/spec/session_hash_spec.rb +1 -2
- data/spec/spec_helper.rb +5 -3
- data/tasks/gem.rake +1 -1
- data/tasks/rdoc.rake +3 -2
- metadata +17 -5
data/Rakefile
CHANGED
@@ -15,17 +15,17 @@ require 'mongo_rack'
|
|
15
15
|
task :default => 'spec:run'
|
16
16
|
|
17
17
|
PROJ.name = 'mongo_rack'
|
18
|
+
PROJ.version = "0.0.3"
|
18
19
|
PROJ.authors = 'Fernand Galiana'
|
19
20
|
PROJ.email = 'fernand.galiana@gmail.com'
|
20
21
|
PROJ.url = 'http://github.com/derailed/mongo_rack'
|
21
22
|
PROJ.summary = "Rackable mongoDB based session management"
|
22
|
-
PROJ.version = "0.0.2"
|
23
23
|
PROJ.ruby_opts = %w[-W0]
|
24
24
|
PROJ.readme = 'README.rdoc'
|
25
25
|
PROJ.rcov.opts = ["--sort", "coverage", "-T"]
|
26
26
|
PROJ.spec.opts << '--color'
|
27
27
|
|
28
28
|
# Dependencies
|
29
|
-
depend_on "rack" , ">= 1.0.
|
30
|
-
depend_on "mongo" , ">= 0.18.
|
31
|
-
depend_on "mongo_ext", ">= 0.18.
|
29
|
+
depend_on "rack" , ">= 1.0.1"
|
30
|
+
depend_on "mongo" , ">= 0.18.2"
|
31
|
+
depend_on "mongo_ext", ">= 0.18.2"
|
data/aa.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'yaml'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
class Fred
|
6
|
+
attr_accessor :blee, :duh, :zob
|
7
|
+
|
8
|
+
def initialize( blee, duh )
|
9
|
+
@blee = blee
|
10
|
+
@duh = duh
|
11
|
+
@zob = 100
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
f = Fred.new( 10, "Hello" )
|
16
|
+
|
17
|
+
buff = f.to_yaml
|
18
|
+
|
19
|
+
nf = YAML.load( buff )
|
20
|
+
|
21
|
+
puts nf.inspect
|
22
|
+
|
data/fred.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# tnum = 10
|
2
|
+
# r = Array.new(tnum) do
|
3
|
+
# Thread.new do
|
4
|
+
# puts "Making request"
|
5
|
+
# 10
|
6
|
+
# end
|
7
|
+
# end.reverse.map{|t| puts t.inspect;t.join; puts t.value }
|
8
|
+
#
|
9
|
+
# r.each do |res|
|
10
|
+
# puts "Checking request #{res}"
|
11
|
+
# end
|
12
|
+
|
13
|
+
|
14
|
+
a = Array.new( 10 ) do
|
15
|
+
Thread.new( 20 ) do |run|
|
16
|
+
puts "Blee + #{run}"
|
17
|
+
20
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
puts a.inspect
|
22
|
+
|
23
|
+
b = a.reverse.map{ |t| t.join.value }
|
24
|
+
|
25
|
+
puts "Here"
|
26
|
+
puts b.inspect
|
data/lib/mongo_rack.rb
CHANGED
@@ -2,6 +2,8 @@ require 'rack/session/abstract/id'
|
|
2
2
|
require 'mongo'
|
3
3
|
require File.expand_path( File.join( File.dirname(__FILE__), %w[mongo_rack session_hash.rb] ) )
|
4
4
|
require File.expand_path( File.join( File.dirname(__FILE__), %w[core_ext hash.rb] ) )
|
5
|
+
require 'yaml'
|
6
|
+
require 'logger'
|
5
7
|
|
6
8
|
module Rack
|
7
9
|
module Session
|
@@ -19,10 +21,13 @@ module Rack
|
|
19
21
|
# :pool_timeout ::
|
20
22
|
# The connection pool timeout. see mongo-ruby-driver docs for settings.
|
21
23
|
# Defaults to 1 sec.
|
24
|
+
# :logging ::
|
25
|
+
# Set to true to enable logger. Default is false
|
22
26
|
DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge \
|
23
27
|
:server => 'localhost:27017/mongo_session/sessions',
|
24
28
|
:pool_size => 1,
|
25
|
-
:pool_timeout => 1.0
|
29
|
+
:pool_timeout => 1.0,
|
30
|
+
:log_level => :fatal
|
26
31
|
|
27
32
|
# Initializes mongo_rack. Pass in options for default override.
|
28
33
|
def initialize(app, options={})
|
@@ -31,13 +36,18 @@ module Rack
|
|
31
36
|
host, port, db_name, cltn_name = parse_server_desc( @default_options[:server] )
|
32
37
|
|
33
38
|
@mutex = Mutex.new
|
34
|
-
@connection = ::Mongo::Connection.new(
|
39
|
+
@connection = ::Mongo::Connection.new(
|
40
|
+
host,
|
41
|
+
port,
|
35
42
|
:pool_size => @default_options[:pool_size],
|
36
43
|
:timeout => @default_options[:pool_timeout] )
|
37
44
|
@db = @connection.db( db_name )
|
38
45
|
@sessions = @db[cltn_name]
|
46
|
+
|
47
|
+
@logger = Logger.new( $stdout )
|
48
|
+
@logger.level = set_log_level( @default_options[:log_level] )
|
39
49
|
end
|
40
|
-
|
50
|
+
|
41
51
|
# Fetch session with optional session id. Retrieve session from mongodb if any
|
42
52
|
def get_session( env, sid )
|
43
53
|
return _get_session( env, sid ) unless env['rack.multithread']
|
@@ -85,35 +95,57 @@ module Rack
|
|
85
95
|
raise "Invalid host:port description" unless server_desc.size == 2
|
86
96
|
return server_desc.first, server_desc.last.to_i, tokens[1], tokens[2]
|
87
97
|
end
|
88
|
-
|
98
|
+
|
99
|
+
# Use YAML to store session objects
|
100
|
+
def serialize( ses )
|
101
|
+
YAML::dump( ses )
|
102
|
+
end
|
103
|
+
|
104
|
+
# Session object stored in YAML
|
105
|
+
def deserialize( buff )
|
106
|
+
YAML::load( buff )
|
107
|
+
end
|
108
|
+
|
89
109
|
# fetch session with optional session id
|
90
110
|
def _get_session(env, sid)
|
111
|
+
logger.debug "Getting session info for #{sid.inspect}"
|
91
112
|
if sid
|
92
113
|
ses_obj = sessions.find_one( { :_id => sid } )
|
93
|
-
|
114
|
+
if ses_obj
|
115
|
+
logger.debug "Found session object on #{sid.inspect}"
|
116
|
+
else
|
117
|
+
logger.debug "Unable to find session object #{sid.inspect}"
|
118
|
+
end
|
119
|
+
session = MongoRack::SessionHash.new( deserialize(ses_obj['data']) ) if ses_obj and fresh?( ses_obj )
|
94
120
|
end
|
95
121
|
|
96
122
|
unless sid and session
|
97
|
-
|
98
|
-
session =
|
123
|
+
logger.warn "Session ID not found - #{sid.inspect} - Creating new session"
|
124
|
+
session = MongoRack::SessionHash.new
|
99
125
|
sid = generate_sid
|
100
|
-
ret = sessions.save( { :_id => sid, :data => session } )
|
126
|
+
ret = sessions.save( { :_id => sid, :data => serialize(session) } )
|
101
127
|
raise "Session collision on '#{sid.inspect}'" unless ret
|
102
128
|
end
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
129
|
+
merged = MongoRack::SessionHash.new.merge(session)
|
130
|
+
logger.debug "Setting old session #{merged.inspect}"
|
131
|
+
session.instance_variable_set( '@old', merged )
|
132
|
+
return [sid, session]
|
133
|
+
rescue => boom
|
134
|
+
logger.error "#{self} Hoy! something bad happened loading session data"
|
135
|
+
logger.error $!.inspect
|
136
|
+
boom.backtrace.each{ |l| logger.error l }
|
137
|
+
return [ nil, MongoRack::SessionHash.new ]
|
109
138
|
end
|
110
139
|
|
111
140
|
# update session information with new settings
|
112
141
|
def _set_session(env, sid, new_session, options)
|
142
|
+
logger.debug "Setting session #{new_session.inspect}"
|
113
143
|
ses_obj = sessions.find_one( { :_id => sid } )
|
114
144
|
if ses_obj
|
115
|
-
session
|
145
|
+
logger.debug "Found existing session for -- #{sid.inspect}"
|
146
|
+
session = MongoRack::SessionHash.new( deserialize( ses_obj['data'] ) )
|
116
147
|
else
|
148
|
+
logger.debug "Unable to find session for -- #{sid.inspect}"
|
117
149
|
session = MongoRack::SessionHash.new
|
118
150
|
end
|
119
151
|
|
@@ -124,37 +156,67 @@ module Rack
|
|
124
156
|
sessions.insert( {:_id => sid, :data => {} } )
|
125
157
|
end
|
126
158
|
old_session = new_session.instance_variable_get('@old') || MongoRack::SessionHash.new
|
159
|
+
logger.debug "Setting old session -- #{old_session.inspect}"
|
127
160
|
merged = merge_sessions( sid, old_session, new_session, session )
|
128
161
|
|
129
162
|
expiry = options[:expire_after]
|
130
163
|
expiry = expiry ? Time.now + options[:expire_after] : 0
|
131
164
|
|
132
165
|
# BOZO ! Use upserts here if minor changes ?
|
133
|
-
|
166
|
+
logger.debug "Updating session -- #{merged.inspect}"
|
167
|
+
sessions.save( { :_id => sid, :data => serialize( merged ), :expire => expiry } )
|
134
168
|
return sid
|
135
|
-
rescue => boom
|
136
|
-
|
137
|
-
|
169
|
+
rescue => boom
|
170
|
+
logger.error "#{self} Hoy! Something went wrong. Unable to persist session."
|
171
|
+
logger.error $!.inspect
|
172
|
+
boom.backtrace.each{ |l| logger.error l }
|
138
173
|
return false
|
139
174
|
end
|
140
175
|
|
141
176
|
# merge old, new to current session state
|
142
177
|
def merge_sessions( sid, old_s, new_s, cur={} )
|
143
178
|
unless Hash === old_s and Hash === new_s
|
144
|
-
|
179
|
+
logger.error 'Bad old or new sessions provided.'
|
145
180
|
return cur
|
146
181
|
end
|
147
|
-
|
182
|
+
|
148
183
|
delete = old_s.keys - new_s.keys
|
149
|
-
|
184
|
+
logger.info "//@#{sid}: delete #{delete*','}" if not delete.empty?
|
150
185
|
delete.each{ |k| cur.delete(k) }
|
151
186
|
|
152
|
-
update = new_s.keys.select
|
153
|
-
|
154
|
-
|
187
|
+
update = new_s.keys.select do |k|
|
188
|
+
logger.debug "Update #{k}-#{new_s[k] != old_s[k]}? #{new_s[k].inspect} - #{old_s[k].inspect}";
|
189
|
+
new_s[k] != old_s[k]
|
190
|
+
end
|
155
191
|
|
192
|
+
logger.info "//@#{sid}: update #{update*','}" if not update.empty?
|
193
|
+
update.each{ |k| cur[k] = new_s[k] }
|
156
194
|
cur
|
157
195
|
end
|
196
|
+
|
197
|
+
# Logger handle
|
198
|
+
def logger
|
199
|
+
@logger
|
200
|
+
end
|
201
|
+
|
202
|
+
# Set the log level
|
203
|
+
def set_log_level( level )
|
204
|
+
case level
|
205
|
+
when :fatal
|
206
|
+
Logger::FATAL
|
207
|
+
when :error
|
208
|
+
Logger::ERROR
|
209
|
+
when :warn
|
210
|
+
Logger::WARN
|
211
|
+
when :info
|
212
|
+
Logger::INFO
|
213
|
+
when :debug
|
214
|
+
Logger::DEBUG
|
215
|
+
else
|
216
|
+
Logger::INFO
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
158
220
|
end
|
159
221
|
end
|
160
222
|
end
|
data/spec/mongo_rack_spec.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
-
require File.expand_path(
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), %w[spec_helper]))
|
2
|
+
require 'core_ext/hash'
|
2
3
|
|
3
4
|
describe Rack::Session::Mongo do
|
4
5
|
before :all do
|
5
6
|
@session_key = 'rack.session'
|
6
7
|
@session_match = /#{@session_key}=[0-9a-fA-F]+;/
|
7
|
-
@db_name = '
|
8
|
+
@db_name = 'mongo_rack_test'
|
8
9
|
@cltn_name = 'sessions'
|
9
10
|
|
10
11
|
@con = Mongo::Connection.new
|
@@ -45,9 +46,11 @@ describe Rack::Session::Mongo do
|
|
45
46
|
req = Rack::MockRequest.new( @pool )
|
46
47
|
res = req.get("/", 'rack.multithread' => false )
|
47
48
|
cookie = res["Set-Cookie"]
|
48
|
-
req.get("/", "HTTP_COOKIE" => cookie, 'rack.multithread' => false )
|
49
|
+
res = req.get("/", "HTTP_COOKIE" => cookie, 'rack.multithread' => false )
|
50
|
+
res.body.should == '{"counter"=>2}'
|
49
51
|
mongo_check( res, :counter, 2 )
|
50
|
-
req.get("/", "HTTP_COOKIE" => cookie, 'rack.multithread' => false )
|
52
|
+
res = req.get("/", "HTTP_COOKIE" => cookie, 'rack.multithread' => false )
|
53
|
+
res.body.should == '{"counter"=>3}'
|
51
54
|
mongo_check( res, :counter, 3 )
|
52
55
|
end
|
53
56
|
|
@@ -157,6 +160,7 @@ describe Rack::Session::Mongo do
|
|
157
160
|
res3.body.should == '{"counter"=>4}'
|
158
161
|
end
|
159
162
|
|
163
|
+
# BOZO !! Review...
|
160
164
|
it "multithread: should cleanly merge sessions" do
|
161
165
|
pending do
|
162
166
|
@pool = Rack::Session::Mongo.new( @incrementor, :server => "localhost:27017/#{@db_name}/#{@cltn_name}", :pool_size => 10 )
|
@@ -182,7 +186,7 @@ describe Rack::Session::Mongo do
|
|
182
186
|
drop_counter = proc do |env|
|
183
187
|
env['rack.session'].delete 'counter'
|
184
188
|
env['rack.session']['foo'] = 'bar'
|
185
|
-
[200, {'Content-Type'=>'text/plain'},
|
189
|
+
[200, {'Content-Type'=>'text/plain'}, env['rack.session'].inspect]
|
186
190
|
end
|
187
191
|
tses = Rack::Utils::Context.new @pool, drop_counter
|
188
192
|
treq = Rack::MockRequest.new( tses )
|
@@ -198,11 +202,52 @@ describe Rack::Session::Mongo do
|
|
198
202
|
res.body.should include('"foo"=>"bar"')
|
199
203
|
end
|
200
204
|
|
201
|
-
|
202
|
-
|
203
|
-
session['data']
|
204
|
-
session
|
205
|
+
result = @pool.sessions.find_one( {:_id => sess_id } )
|
206
|
+
result.should_not be_nil
|
207
|
+
session = YAML.load( result['data'] )
|
208
|
+
session.size.should == 1
|
209
|
+
session['counter'].should be_nil
|
210
|
+
session['foo'].should == 'bar'
|
205
211
|
end
|
206
|
-
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
describe "serialization" do
|
216
|
+
before( :all ) do
|
217
|
+
@pool = Rack::Session::Mongo.new( @incrementor, :server => "localhost:27017/#{@db_name}/#{@cltn_name}" )
|
218
|
+
@env = {}
|
219
|
+
@opts = {}
|
220
|
+
end
|
221
|
+
|
222
|
+
it "should store a hash in session correctly" do
|
223
|
+
sid = 10
|
224
|
+
ses = { 'a' => 1, 'b' => 2 }
|
225
|
+
@pool.send(:_set_session, @env, sid, ses, @opts )
|
226
|
+
results = @pool.send(:_get_session, @env, sid )
|
227
|
+
results.last.should == ses
|
228
|
+
end
|
229
|
+
|
230
|
+
it "should store an object in session correctly" do
|
231
|
+
sid = 11
|
232
|
+
fred = Fred.new( 10, "Hello" )
|
233
|
+
ses = { :fred => fred }
|
234
|
+
@pool.send(:_set_session, @env, sid, ses, @opts )
|
235
|
+
results = @pool.send(:_get_session, @env, sid )
|
236
|
+
[:fred, 'fred'].each do |key|
|
237
|
+
results.last[key].blee.should == 10
|
238
|
+
results.last[key].duh.should == "Hello"
|
239
|
+
results.last[key].zob.should == 100
|
240
|
+
end
|
241
|
+
end
|
207
242
|
end
|
243
|
+
|
244
|
+
class Fred
|
245
|
+
attr_accessor :blee, :duh, :zob
|
246
|
+
def initialize( blee, duh )
|
247
|
+
@blee = blee
|
248
|
+
@duh = duh
|
249
|
+
@zob = 100
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
208
253
|
end
|
data/spec/session_hash_spec.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
require File.expand_path(
|
2
|
-
require File.expand_path( File.join( File.dirname(__FILE__), %w[.. lib core_ext hash] ) )
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), %w[spec_helper]))
|
3
2
|
|
4
3
|
describe MongoRack::SessionHash do
|
5
4
|
before :all do
|
data/spec/spec_helper.rb
CHANGED
@@ -2,6 +2,7 @@ require 'rubygems'
|
|
2
2
|
require 'rack'
|
3
3
|
require 'rack/test'
|
4
4
|
require 'rack/response'
|
5
|
+
require 'yaml'
|
5
6
|
|
6
7
|
require File.expand_path( File.join( File.dirname(__FILE__), %w[.. lib mongo_rack] ) )
|
7
8
|
|
@@ -10,9 +11,10 @@ end
|
|
10
11
|
|
11
12
|
def mongo_check( res, key, val )
|
12
13
|
session_id = res['Set-Cookie'].match( /^#{@session_key}=(.*?);.*?/ )[1]
|
13
|
-
|
14
|
-
|
15
|
-
ses['data']
|
14
|
+
result = @sessions.find_one( { :_id => session_id } )
|
15
|
+
result.should_not be_nil
|
16
|
+
ses = YAML.load( result['data'] )
|
17
|
+
ses[key.to_s].should == val
|
16
18
|
end
|
17
19
|
|
18
20
|
def clear_sessions
|
data/tasks/gem.rake
CHANGED
@@ -50,7 +50,7 @@ class GemPackageTask < Rake::PackageTask
|
|
50
50
|
task :package => ['gem:prereqs', "#{package_dir_path}/#{gem_file}"]
|
51
51
|
file "#{package_dir_path}/#{gem_file}" => [package_dir_path] + package_files + bones_files do
|
52
52
|
when_writing("Creating GEM") {
|
53
|
-
chdir(package_dir_path) do
|
53
|
+
chdir(package_dir_path) do
|
54
54
|
Gem::Builder.new(gem_spec).build
|
55
55
|
verbose(true) {
|
56
56
|
mv gem_file, "../#{gem_file}"
|
data/tasks/rdoc.rake
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'rake/rdoctask'
|
2
|
+
# require 'darkfish-rdoc'
|
2
3
|
|
3
4
|
namespace :doc do
|
4
5
|
|
@@ -26,8 +27,8 @@ namespace :doc do
|
|
26
27
|
|
27
28
|
rd.options << "-t #{title}"
|
28
29
|
rd.options << "-SHN"
|
29
|
-
|
30
|
-
#
|
30
|
+
rd.options << "-f"
|
31
|
+
# rd.options << "darkfish"
|
31
32
|
rd.options.concat(rdoc.opts)
|
32
33
|
end
|
33
34
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongo_rack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Fernand Galiana
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-
|
12
|
+
date: 2010-02-03 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -20,7 +20,7 @@ dependencies:
|
|
20
20
|
requirements:
|
21
21
|
- - ">="
|
22
22
|
- !ruby/object:Gem::Version
|
23
|
-
version: 1.0.
|
23
|
+
version: 1.0.1
|
24
24
|
version:
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: mongo
|
@@ -30,7 +30,7 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.18.
|
33
|
+
version: 0.18.2
|
34
34
|
version:
|
35
35
|
- !ruby/object:Gem::Dependency
|
36
36
|
name: mongo_ext
|
@@ -40,7 +40,17 @@ dependencies:
|
|
40
40
|
requirements:
|
41
41
|
- - ">="
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
version: 0.18.
|
43
|
+
version: 0.18.2
|
44
|
+
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: bones
|
47
|
+
type: :development
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 2.5.1
|
44
54
|
version:
|
45
55
|
description: ""
|
46
56
|
email: fernand.galiana@gmail.com
|
@@ -54,6 +64,8 @@ files:
|
|
54
64
|
- HISTORY
|
55
65
|
- README.rdoc
|
56
66
|
- Rakefile
|
67
|
+
- aa.rb
|
68
|
+
- fred.rb
|
57
69
|
- lib/core_ext/hash.rb
|
58
70
|
- lib/mongo_rack.rb
|
59
71
|
- lib/mongo_rack/session_hash.rb
|