JunKikuchi-rack-session-stack 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
File without changes
data/COPYING ADDED
@@ -0,0 +1,18 @@
1
+ Copyright (c) 2009 Jun Kikuchi
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to
5
+ deal in the Software without restriction, including without limitation the
6
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
+ sell copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16
+ THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,137 @@
1
+ = rack-session-stack
2
+
3
+ セッションの保存先を積み重ねられたらどうかと思ってやってみた。
4
+
5
+ == Memcache から Sequel さらに RAWS::SDB へフォールバック
6
+
7
+ これは 3 段重ねの極端な例です。あらかじめご了承下さい。
8
+
9
+ セッション情報を書き込む場合は Memcache と Sequel, RAWS::SDB (Ruby Amazon Web Service - SimpleDB) の全てに書き込みます。
10
+
11
+ セッション情報を読み込む場合は、最初に Memcache から読み込みます。データが取得出来れば Memcache のデータを使い、データが取得出来なかった場合は Sequel からデータを読み込んで使います。Sequel からデータを取得出来なかった場合は RAWS::SDB へと同様にフォールバックします。
12
+
13
+ 書き込みは遅いのですが、読み込みはそこそこ。
14
+
15
+ require 'rubygems'
16
+ require 'sinatra'
17
+ require 'rack-session-stack'
18
+
19
+ require 'sequel'
20
+ DB = Sequel.sqlite
21
+ DB.create_table(:session) do
22
+ primary_key :id
23
+ String :sid, :unique => true, :null => false
24
+ Datetime :created
25
+ Datetime :updated
26
+ column :session, File
27
+ end
28
+
29
+ require 'raws'
30
+ RAWS.aws_access_key_id = _AWS_ACCESS_KEY_ID_
31
+ RAWS.aws_secret_access_key = _AWS_SECRET_ACCESS_KEY_
32
+ RAWS::SDB.create_domain 'session'
33
+
34
+ use Rack::Session::Stack,
35
+ :stack => Rack::Session::Stack::Memcache.new(
36
+ {:server => 'localhost:11211'},
37
+ Rack::Session::Stack::Sequel.new(
38
+ {:dataset => DB[:session]},
39
+ Rack::Session::Stack::RAWS::SDB.new(
40
+ {:domain => 'session'}
41
+ )
42
+ )
43
+ )
44
+
45
+ get '/' do
46
+ if session['cnt']
47
+ session['cnt'] += 1
48
+ else
49
+ session['cnt'] = 1
50
+ end
51
+
52
+ "cnt = #{session['cnt']}"
53
+ end
54
+
55
+ = Memcache
56
+
57
+ Memcache を単体で使う場合。
58
+
59
+ require 'rubygems'
60
+ require 'sinatra'
61
+ require 'rack-session-stack'
62
+
63
+ use Rack::Session::Stack,
64
+ :stack => Rack::Session::Stack::Memcache.new(
65
+ :server => 'localhost:11211'
66
+ )
67
+
68
+ get '/' do
69
+ if session['cnt']
70
+ session['cnt'] += 1
71
+ else
72
+ session['cnt'] = 1
73
+ end
74
+
75
+ "cnt = #{session['cnt']}"
76
+ end
77
+
78
+ = Sequel
79
+
80
+ Sequel を単体で使う場合。
81
+
82
+ require 'rubygems'
83
+ require 'sinatra'
84
+ require 'rack-session-stack'
85
+
86
+ require 'sequel'
87
+ DB = Sequel.sqlite
88
+ DB.create_table(:session) do
89
+ primary_key :id
90
+ String :sid, :unique => true, :null => false
91
+ Datetime :created
92
+ Datetime :updated
93
+ column :session, File
94
+ end
95
+
96
+ use Rack::Session::Stack,
97
+ :stack => Rack::Session::Stack::Sequel.new(
98
+ {:dataset => DB[:session]},
99
+ )
100
+
101
+ get '/' do
102
+ if session['cnt']
103
+ session['cnt'] += 1
104
+ else
105
+ session['cnt'] = 1
106
+ end
107
+
108
+ "cnt = #{session['cnt']}"
109
+ end
110
+
111
+ == RAWS::SDB
112
+
113
+ RAWS::SDB を単体で使う場合。
114
+
115
+ require 'rubygems'
116
+ require 'sinatra'
117
+ require 'rack-session-stack'
118
+
119
+ require 'raws'
120
+ RAWS.aws_access_key_id = _AWS_ACCESS_KEY_ID_
121
+ RAWS.aws_secret_access_key = _AWS_SECRET_ACCESS_KEY_
122
+ RAWS::SDB.create_domain 'session'
123
+
124
+ use Rack::Session::Stack,
125
+ :stack => Rack::Session::Stack::RAWS::SDB.new(
126
+ :domain => 'session'
127
+ )
128
+
129
+ get '/' do
130
+ if session['cnt']
131
+ session['cnt'] += 1
132
+ else
133
+ session['cnt'] = 1
134
+ end
135
+
136
+ "cnt = #{session['cnt']}"
137
+ end
@@ -0,0 +1,29 @@
1
+ require 'rubygems'
2
+ require 'spec/rake/spectask'
3
+
4
+ NAME = 'rack-session-stack'
5
+
6
+ begin
7
+ require 'jeweler'
8
+ Jeweler::Tasks.new do |s|
9
+ s.name = NAME
10
+ s.platform = Gem::Platform::RUBY
11
+ s.summary = NAME
12
+ s.description = NAME
13
+ s.author = "Jun Kikuchi"
14
+ s.email = "kikuchi@bonnou.com"
15
+ s.homepage = "http://github.com/JunKikuchi/rack-session-stack"
16
+ s.files = %w(COPYING CHANGELOG README.rdoc Rakefile) + Dir.glob("{bin,doc,spec,lib}/**/*")
17
+ s.require_path = "lib"
18
+ s.has_rdoc = true
19
+ s.add_dependency('uuidtools','>= 2.0.0')
20
+ end
21
+ rescue LoadError
22
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
23
+ end
24
+
25
+ Spec::Rake::SpecTask.new do |t|
26
+ #t.spec_opts = ['-c --format specdoc']
27
+ t.spec_opts = ['-c']
28
+ t.spec_files = FileList['spec/**/*_spec.rb']
29
+ end
@@ -0,0 +1,78 @@
1
+ require 'rack/session/abstract/id'
2
+ require 'uuidtools'
3
+
4
+ module Rack
5
+ module Session
6
+ class Stack < Abstract::ID
7
+ DEFAULT_OPTIONS = Abstract::ID::DEFAULT_OPTIONS.merge(:stack => nil)
8
+
9
+ def initialize(app, options={})
10
+ super
11
+ @stack = @default_options[:stack]
12
+ end
13
+
14
+ def generate_sid
15
+ UUIDTools::UUID.random_create.to_s
16
+ end
17
+
18
+ def get_session(env, sid)
19
+ unless sid && session = @stack[sid]
20
+ @stack.create(sid = generate_sid, session = {})
21
+ end
22
+
23
+ session.instance_variable_set('@old', {}.merge(session))
24
+
25
+ return [sid, session]
26
+ end
27
+
28
+ def set_session(env, sid, session, options)
29
+ if options[:drop]
30
+ @stack.delete(sid)
31
+ return nil
32
+ end
33
+
34
+ if options[:renew]
35
+ @stack.delete(sid)
36
+ @stack.create(sid = generate_sid, session)
37
+ else
38
+ old = session.instance_variable_get('@old') || {}
39
+ @stack[sid] = session if session != old
40
+ end
41
+
42
+ return sid
43
+ end
44
+
45
+ class Base
46
+ PARAMS = {}
47
+
48
+ def initialize(params={}, fallback=nil)
49
+ @params, @fallback = self.class::PARAMS.merge(params), fallback
50
+ end
51
+
52
+ def create(sid, session)
53
+ @fallback && @fallback.create(sid, session)
54
+ end
55
+
56
+ def delete(sid)
57
+ @fallback && @fallback.delete(sid)
58
+ end
59
+
60
+ def [](sid)
61
+ @fallback && @fallback[sid]
62
+ end
63
+
64
+ def []=(sid, session)
65
+ @fallback && (@fallback[sid] = session)
66
+ session
67
+ end
68
+ end
69
+
70
+ autoload :Memcache, 'rack-session-stack/memcache'
71
+ autoload :Sequel, 'rack-session-stack/sequel'
72
+
73
+ module RAWS
74
+ autoload :SDB, 'rack-session-stack/raws/sdb'
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,40 @@
1
+ require 'memcache'
2
+
3
+ class Rack::Session::Stack::Memcache < Rack::Session::Stack::Base
4
+ attr_reader :pool
5
+ PARAMS = {:server => 'localhost:11211'}
6
+
7
+ def initialize(params={}, fallback=nil)
8
+ super
9
+ @pool = ::MemCache.new(@params[:server], @params)
10
+ raise 'No memcache servers' unless @pool.servers.any? { |s| s.alive? }
11
+ end
12
+
13
+ def create(sid, session)
14
+ unless /^STORED/ =~ @pool.add(sid, session)
15
+ raise "Session collision on '#{sid.inspect}'"
16
+ end
17
+ ensure
18
+ super
19
+ end
20
+
21
+ def delete(sid)
22
+ @pool.delete(sid)
23
+ ensure
24
+ super
25
+ end
26
+
27
+ def [](sid)
28
+ @pool.fetch(sid) do
29
+ super(sid)
30
+ end
31
+ rescue
32
+ super(sid)
33
+ end
34
+
35
+ def []=(sid, session)
36
+ @pool.set(sid, session, 0)
37
+ ensure
38
+ super
39
+ end
40
+ end
@@ -0,0 +1,58 @@
1
+ require 'raws'
2
+ require 'time'
3
+
4
+ class Rack::Session::Stack::RAWS::SDB < Rack::Session::Stack::Base
5
+ attr_reader :pool
6
+ PARAMS = {:domain => nil}
7
+
8
+ def initialize(params={}, fallback=nil)
9
+ super
10
+ @pool = ::RAWS::SDB[@params[:domain]]
11
+ end
12
+
13
+ def create(sid, session)
14
+ @pool.put(
15
+ sid,
16
+ {
17
+ 'session' => [Marshal.dump(session)].pack('m*'),
18
+ 'created' => Time.now.utc.iso8601,
19
+ 'updated' => Time.now.utc.iso8601
20
+ },
21
+ 'session',
22
+ 'created',
23
+ 'updated'
24
+ )
25
+ super
26
+ end
27
+
28
+ def delete(sid)
29
+ @pool.delete(sid)
30
+ super
31
+ end
32
+
33
+ def store(sid, session)
34
+ @pool.put(
35
+ sid,
36
+ {
37
+ 'session' => [Marshal.dump(session)].pack('m*'),
38
+ 'updated' => Time.now.utc.iso8601
39
+ },
40
+ 'session',
41
+ 'updated'
42
+ )
43
+ session
44
+ end
45
+
46
+ def [](sid)
47
+ if data = @pool.get(sid)
48
+ Marshal.load(data['session'].unpack("m*").first)
49
+ else
50
+ store(sid, super)
51
+ end
52
+ end
53
+
54
+ def []=(sid, session)
55
+ store(sid, session)
56
+ super
57
+ end
58
+ end
@@ -0,0 +1,48 @@
1
+ require 'sequel'
2
+
3
+ class Rack::Session::Stack::Sequel < Rack::Session::Stack::Base
4
+ PARAMS = {:dataset => nil}
5
+
6
+ def initialize(params={}, fallback=nil)
7
+ super
8
+ @pool = @params[:dataset]
9
+ end
10
+
11
+ def create(sid, session)
12
+ @pool.insert(
13
+ :sid => sid,
14
+ :session => [Marshal.dump(session)].pack('m*'),
15
+ :created => Time.now.utc,
16
+ :updated => Time.now.utc
17
+ )
18
+ super
19
+ end
20
+
21
+ def delete(sid)
22
+ if data = @pool.filter('sid = ?', sid).first
23
+ data.delete
24
+ end
25
+ super
26
+ end
27
+
28
+ def store(sid, session)
29
+ @pool.filter('sid = ?', sid).update(
30
+ :session => [Marshal.dump(session)].pack('m*'),
31
+ :updated => Time.now.utc
32
+ )
33
+ session
34
+ end
35
+
36
+ def [](sid)
37
+ if data = @pool.filter('sid = ?', sid).first
38
+ Marshal.load(data[:session].unpack("m*").first)
39
+ else
40
+ store(sid, super)
41
+ end
42
+ end
43
+
44
+ def []=(sid, session)
45
+ store(sid, session)
46
+ super
47
+ end
48
+ end
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: JunKikuchi-rack-session-stack
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Jun Kikuchi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-08-28 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: uuidtools
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 2.0.0
24
+ version:
25
+ description: rack-session-stack
26
+ email: kikuchi@bonnou.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README.rdoc
33
+ files:
34
+ - CHANGELOG
35
+ - COPYING
36
+ - README.rdoc
37
+ - Rakefile
38
+ - lib/rack-session-stack.rb
39
+ - lib/rack-session-stack/memcache.rb
40
+ - lib/rack-session-stack/raws/sdb.rb
41
+ - lib/rack-session-stack/sequel.rb
42
+ has_rdoc: false
43
+ homepage: http://github.com/JunKikuchi/rack-session-stack
44
+ licenses:
45
+ post_install_message:
46
+ rdoc_options:
47
+ - --charset=UTF-8
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: "0"
55
+ version:
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: "0"
61
+ version:
62
+ requirements: []
63
+
64
+ rubyforge_project:
65
+ rubygems_version: 1.3.5
66
+ signing_key:
67
+ specification_version: 3
68
+ summary: rack-session-stack
69
+ test_files: []
70
+