aws-sessionstore-dynamodb 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/.yardopts +3 -0
  4. data/Gemfile +28 -0
  5. data/LICENSE.txt +12 -0
  6. data/README.md +171 -0
  7. data/Rakefile +15 -0
  8. data/aws-sessionstore-dynamodb.gemspec +18 -0
  9. data/lib/aws-sessionstore-dynamodb.rb +34 -0
  10. data/lib/aws/session_store/dynamo_db/configuration.rb +298 -0
  11. data/lib/aws/session_store/dynamo_db/errors/base_handler.rb +45 -0
  12. data/lib/aws/session_store/dynamo_db/errors/default_handler.rb +57 -0
  13. data/lib/aws/session_store/dynamo_db/garbage_collection.rb +128 -0
  14. data/lib/aws/session_store/dynamo_db/invalid_id_error.rb +21 -0
  15. data/lib/aws/session_store/dynamo_db/lock_wait_timeout_error.rb +21 -0
  16. data/lib/aws/session_store/dynamo_db/locking/base.rb +162 -0
  17. data/lib/aws/session_store/dynamo_db/locking/null.rb +40 -0
  18. data/lib/aws/session_store/dynamo_db/locking/pessimistic.rb +160 -0
  19. data/lib/aws/session_store/dynamo_db/missing_secret_key_error.rb +21 -0
  20. data/lib/aws/session_store/dynamo_db/rack_middleware.rb +130 -0
  21. data/lib/aws/session_store/dynamo_db/railtie.rb +28 -0
  22. data/lib/aws/session_store/dynamo_db/table.rb +98 -0
  23. data/lib/aws/session_store/dynamo_db/tasks/session_table.rake +21 -0
  24. data/lib/aws/session_store/dynamo_db/version.rb +21 -0
  25. data/lib/rails/generators/sessionstore/dynamodb/dynamodb_generator.rb +55 -0
  26. data/lib/rails/generators/sessionstore/dynamodb/templates/sessionstore/USAGE +13 -0
  27. data/lib/rails/generators/sessionstore/dynamodb/templates/sessionstore/dynamodb.yml +71 -0
  28. data/lib/rails/generators/sessionstore/dynamodb/templates/sessionstore_migration.rb +10 -0
  29. data/spec/aws/session_store/dynamo_db/app_config.yml +19 -0
  30. data/spec/aws/session_store/dynamo_db/config/dynamo_db_session.yml +24 -0
  31. data/spec/aws/session_store/dynamo_db/configuration_spec.rb +101 -0
  32. data/spec/aws/session_store/dynamo_db/error/default_error_handler_spec.rb +62 -0
  33. data/spec/aws/session_store/dynamo_db/garbage_collection_spec.rb +156 -0
  34. data/spec/aws/session_store/dynamo_db/locking/threaded_sessions_spec.rb +95 -0
  35. data/spec/aws/session_store/dynamo_db/rack_middleware_database_spec.rb +129 -0
  36. data/spec/aws/session_store/dynamo_db/rack_middleware_spec.rb +149 -0
  37. data/spec/aws/session_store/dynamo_db/rails_app_config.yml +24 -0
  38. data/spec/aws/session_store/dynamo_db/table_spec.rb +46 -0
  39. data/spec/spec_helper.rb +61 -0
  40. data/tasks/test.rake +29 -0
  41. metadata +123 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1395af7cb7211af4f4cb72dcd4037ee046627a64
4
+ data.tar.gz: 55d5c7eb166a8571b05c883fb05baa53d293152f
5
+ SHA512:
6
+ metadata.gz: a9f754fabdd1af66c5853249a946b39b76eca01db99ee569ba9f63b11eec8ba2be7f93d94f6e8055af7013371dde889d6af3c3e093967aeaa24dd56c9b4b52f3
7
+ data.tar.gz: 3d276410f121bdf18acc8217a14c4cc6967a0cd84863e562aa4dd17e1ce38765d4ee42da3472cc3a9ca75d10cbf20ec6cdac15877e2d7d01d84eac39072dca63
@@ -0,0 +1,4 @@
1
+ doc
2
+ coverage
3
+ .yardoc
4
+ Gemfile.lock
@@ -0,0 +1,3 @@
1
+ --title "Amazon DynamoDB Session Store"
2
+ --exclude /generators/
3
+ --hide-api private
data/Gemfile ADDED
@@ -0,0 +1,28 @@
1
+ # Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ # http://aws.amazon.com/apache2.0/
8
+ #
9
+ # or in the "license" file accompanying this file. This file is
10
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
+ # ANY KIND, either express or implied. See the License for the specific
12
+ # language governing permissions and limitations under the License.
13
+
14
+ source 'https://rubygems.org'
15
+
16
+ gemspec
17
+
18
+ gem 'rake', '~> 10.0'
19
+
20
+ group :documentation do
21
+ gem 'yard', '~> 0.0'
22
+ end
23
+
24
+ group :test do
25
+ gem 'rspec', '~> 2.0'
26
+ gem 'simplecov', '~> 0.0', :require => false
27
+ gem 'rack-test', '~> 0.0'
28
+ end
@@ -0,0 +1,12 @@
1
+ Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ may not use this file except in compliance with the License. A copy of
5
+ the License is located at
6
+
7
+ http://aws.amazon.com/apache2.0/
8
+
9
+ or in the "license" file accompanying this file. This file is
10
+ distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
+ ANY KIND, either express or implied. See the License for the specific
12
+ language governing permissions and limitations under the License.
@@ -0,0 +1,171 @@
1
+ # Amazon DynamoDB Session Store
2
+
3
+ The **Amazon DynamoDB Session Store** handles sessions for Ruby web applications
4
+ using a DynamoDB backend. The session store is compatible with Rails and other
5
+ Rack based frameworks.
6
+
7
+ ## Installation
8
+
9
+ #### Rails Installation
10
+
11
+ Install the session store gem by placing the following command into your
12
+ Gemfile:
13
+
14
+ gem 'aws-sessionstore-dynamodb'
15
+
16
+ You will need to have an existing Amazon DynamoDB session table in order for the
17
+ application to work. You can generate a migration file for the session table
18
+ with the following command:
19
+
20
+ rails generate sessionstore:dynamodb
21
+
22
+ To create the table, run migrations as normal with:
23
+
24
+ rake db:migrate
25
+
26
+ Change the session store to `:dynamodb_store` by editing
27
+ `config/initializers/session_store.rb` to contain the following:
28
+
29
+ YourAppName::Application.config.session_store :dynamodb_store
30
+
31
+ You can now start your Rails application with session support.
32
+
33
+ #### Basic Rack Application Installation
34
+
35
+ For non-Rails applications, you can create the Amazon DynamoDB table in a
36
+ Ruby file using the following method:
37
+
38
+ require 'aws-sessionstore-dynamodb'
39
+
40
+ AWS::SessionStore::DynamoDB::Table.create_table
41
+
42
+ Run the session store as a Rack middleware in the following way:
43
+
44
+ require 'aws-sessionstore-dynamodb'
45
+ require 'some_rack_app'
46
+
47
+ options = { :secret_key => 'SECRET_KEY' }
48
+
49
+ use AWS::SessionStore::DynamoDB::RackMiddleware.new(options)
50
+ run SomeRackApp
51
+
52
+ Note that `:secret_key` is a mandatory configuration option that must be set.
53
+
54
+ ## Detailed Usage
55
+
56
+ The session store is a Rack Middleware, meaning that it will implement the Rack
57
+ interface for dealing with HTTP request/responses.
58
+
59
+ This session store uses a DynamoDB backend in order to provide scaling and
60
+ centralized data benefits for session storage with more ease than other
61
+ containers, like local servers or cookies. Once an application scales beyond
62
+ a single web server, session data will need to be shared across the servers.
63
+ DynamoDB takes care of this burden for you by scaling with your application.
64
+ Cookie storage places all session data on the client side,
65
+ discouraging sensitive data storage. It also forces strict data size
66
+ limitations. DynamoDB takes care of these concerns by allowing for a safe and
67
+ scalable storage container with a much larger data size limit for session data.
68
+
69
+ Full API documentation of the library can be found on [RubyDoc.info][1].
70
+
71
+ ### Configuration Options
72
+
73
+ A number of options are available to be set in
74
+ `AWS::SessionStore::DynamoDB::Configuration`, which is used by the
75
+ `RackMiddleware` class. These options can be set in the YAML configuration
76
+ file in a Rails application (located in `config/sessionstore/dynamodb.yml`),
77
+ directly by Ruby code, or through environment variables.
78
+
79
+ The full set of options along with defaults can be found in the
80
+ [Configuration class documentation][2].
81
+
82
+ #### Environment Options
83
+
84
+ Certain configuration options can be loaded from the environment. These
85
+ options must be specified in the following format:
86
+
87
+ DYNAMO_DB_SESSION_NAME-OF-CONFIGURATION-OPTION
88
+
89
+ The example below would be a valid way to set the session table name:
90
+
91
+ export DYNAMO_DB_SESSION_TABLE_NAME='sessions'
92
+
93
+ ### Rails Generator Details
94
+
95
+ The generator command specified in the installation section will generate two
96
+ files: a migration file, `db/migration/VERSION_migration_name.rb`, and a
97
+ configuration YAML file, `config/sessionstore/dynamodb.yml`.
98
+
99
+ You can run the command with an argument that will define the name of the
100
+ migration file. Once the YAML file is created, you can uncomment any of the
101
+ lines to set configuration options to your liking. The session store will pull
102
+ options from `config/sessionstore/dynamodb.yml` by default if the file exists.
103
+ If you do not wish to place the configuration YAML file in that location,
104
+ you can also pass in a different file path to pull options from.
105
+
106
+ ### Garbage Collection
107
+
108
+ You may want to delete old sessions from your session table. The
109
+ following examples show how to clear old sessions from your table.
110
+
111
+ #### Rails
112
+
113
+ A Rake task for garbage collection is provided for Rails applications.
114
+ By default sessions do not expire. See `config/sessionstore/dynamodb.yml` to
115
+ configure the max age or stale period of a session. Once you have configured
116
+ those values you can clear the old sessions with:
117
+
118
+ rake dynamo_db:collect_garbage
119
+
120
+ #### Outside of Rails
121
+
122
+ You can create your own Rake task for garbage collection similar to below:
123
+
124
+ require "aws-sessionstore-dynamodb"
125
+
126
+ desc 'Perform Garbage Collection'
127
+ task :garbage_collect do |t|
128
+ options = {:max_age => 3600*24, max_stale => 5*3600 }
129
+ AWS::SessionStore::DynamoDB::GarbageCollection.collect_garbage(options)
130
+ end
131
+
132
+ The above example will clear sessions older than one day or that have been
133
+ stale for longer than an hour.
134
+
135
+ ### Locking Strategy
136
+
137
+ You may want the Session Store to implement the provided pessimistic locking
138
+ strategy if you are concerned about concurrency issues with session accesses.
139
+ By default, locking is not implemented for the session store. You must trigger
140
+ the locking strategy through the configuration of the session store. Pessimistic
141
+ locking, in this case, means that only one read can be made on a session at
142
+ once. While the session is being read by the process with the lock, other
143
+ processes may try to obtain a lock on the same session but will be blocked.
144
+
145
+ Locking is expensive and will drive up costs depending on how it is used.
146
+ Without locking, one read and one write are performed per request for session
147
+ data manipulation. If a locking strategy is implemented, as many as the total
148
+ maximum wait time divided by the lock retry delay writes to the database.
149
+ Keep these considerations in mind if you plan to enable locking.
150
+
151
+ #### Configuration for Locking
152
+
153
+ The following configuration options will allow you to configure the pessimistic
154
+ locking strategy according to your needs:
155
+
156
+ options = {
157
+ :enable_locking => true,
158
+ :lock_expiry_time => 500,
159
+ :lock_retry_delay => 500,
160
+ :lock_max_wait_time => 1
161
+ }
162
+
163
+ ### Error Handling
164
+
165
+ You can pass in your own error handler for raised exceptions or you can allow
166
+ the default error handler to them for you. See the API documentation
167
+ on the {AWS::SessionStore::DynamoDB::Errors::BaseHandler} class for more
168
+ details.
169
+
170
+ [1]: http://rubydoc.org/gems/aws-sessionstore-dynamodb/frames
171
+ [2]: http://rubydoc.org/gems/aws-sessionstore-dynamodb/AWS/SessionStore/DynamoDB/Configuration#initialize-instance_method
@@ -0,0 +1,15 @@
1
+ # Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ # http://aws.amazon.com/apache2.0/
8
+ #
9
+ # or in the "license" file accompanying this file. This file is
10
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
+ # ANY KIND, either express or implied. See the License for the specific
12
+ # language governing permissions and limitations under the License.
13
+
14
+ Dir.glob(File.dirname(__FILE__) + '/tasks/*.rake').each {|file| load file }
15
+ task :default => 'test:unit'
@@ -0,0 +1,18 @@
1
+ require File.dirname(__FILE__) + '/lib/aws/session_store/dynamo_db/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "aws-sessionstore-dynamodb"
5
+ spec.version = AWS::SessionStore::DynamoDB::VERSION
6
+ spec.authors = ["Ruby Robinson"]
7
+ spec.summary = "The Amazon DynamoDB Session Store handles sessions " +
8
+ "for Ruby web applications using a DynamoDB backend."
9
+ spec.homepage = "http://github.com/aws/aws-sessionstore-dynamodb-ruby"
10
+ spec.license = "Apache License 2.0"
11
+
12
+ spec.files = `git ls-files`.split($/)
13
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
14
+ spec.require_paths = ["lib"]
15
+
16
+ spec.add_dependency 'aws-sdk', '~> 1.0'
17
+ spec.add_dependency 'rack', '~> 1.0'
18
+ end
@@ -0,0 +1,34 @@
1
+ # Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ # http://aws.amazon.com/apache2.0/
8
+ #
9
+ # or in the "license" file accompanying this file. This file is
10
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
+ # ANY KIND, either express or implied. See the License for the specific
12
+ # language governing permissions and limitations under the License.
13
+
14
+
15
+ module AWS
16
+ module SessionStore
17
+ module DynamoDB; end
18
+ end
19
+ end
20
+
21
+ require 'aws/session_store/dynamo_db/configuration'
22
+ require 'aws/session_store/dynamo_db/invalid_id_error'
23
+ require 'aws/session_store/dynamo_db/missing_secret_key_error'
24
+ require 'aws/session_store/dynamo_db/lock_wait_timeout_error'
25
+ require 'aws/session_store/dynamo_db/errors/base_handler'
26
+ require 'aws/session_store/dynamo_db/errors/default_handler'
27
+ require 'aws/session_store/dynamo_db/garbage_collection'
28
+ require 'aws/session_store/dynamo_db/locking/base'
29
+ require 'aws/session_store/dynamo_db/locking/null'
30
+ require 'aws/session_store/dynamo_db/locking/pessimistic'
31
+ require 'aws/session_store/dynamo_db/rack_middleware'
32
+ require 'aws/session_store/dynamo_db/table'
33
+ require 'aws/session_store/dynamo_db/version'
34
+ require 'aws/session_store/dynamo_db/railtie' if defined?(Rails)
@@ -0,0 +1,298 @@
1
+ # Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License"). You
4
+ # may not use this file except in compliance with the License. A copy of
5
+ # the License is located at
6
+ #
7
+ # http://aws.amazon.com/apache2.0/
8
+ #
9
+ # or in the "license" file accompanying this file. This file is
10
+ # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11
+ # ANY KIND, either express or implied. See the License for the specific
12
+ # language governing permissions and limitations under the License.
13
+
14
+ require 'yaml'
15
+ require 'aws-sdk'
16
+
17
+ module AWS::SessionStore::DynamoDB
18
+ # This class provides a Configuration object for all DynamoDB transactions
19
+ # by pulling configuration options from Runtime, a YAML file, the ENV and
20
+ # default settings.
21
+ #
22
+ # == Environment Variables
23
+ # The Configuration object can load default values from your environment. An example
24
+ # of setting and environment variable is below:
25
+ #
26
+ # export DYNAMO_DB_SESSION_TABLE_NAME='Sessions'
27
+ #
28
+ # == Handling Errors
29
+ # There are two configurable options for error handling: :raise_errors and :error_handler.
30
+ #
31
+ # If you would like to use the Default Error Handler, you can decide to set :raise_errors
32
+ # to true or false depending on whether you want all errors, regadless of class, to be raised
33
+ # up the stack and essentially throw a 500.
34
+ #
35
+ # If you decide to use your own Error Handler. You may pass it in for the value of the key
36
+ # :error_handler as a cofniguration object. You must implement the BaseErrorHandler class.
37
+ # @see BaseHandler Interface for Error Handling for DynamoDB Session Store.
38
+ #
39
+ # == Locking Strategy
40
+ # By default, locking is not implemented for the session store. You must trigger the
41
+ # locking strategy through the configuration of the session store. Pessimistic locking,
42
+ # in this case, means that only one read can be made on a session at once. While the session
43
+ # is being read by the process with the lock, other processes may try to obtain a lock on
44
+ # the same session but will be blocked. See the accessors with lock in their name for
45
+ # how to configure the pessimistic locking strategy to your needs.
46
+ #
47
+ # == DynamoDB Specific Options
48
+ # You may configure the table name and table hash key value of your session table with
49
+ # the :table_name and :table_key options. You may also configure performance options for
50
+ # your table with the :consistent_read, :read_capacity, write_capacity. For more information
51
+ # about these configurations see CreateTable method for Amazon DynamoDB.
52
+ #
53
+ class Configuration
54
+
55
+ # Default configuration options
56
+ DEFAULTS = {
57
+ :table_name => "sessions",
58
+ :table_key => "session_id",
59
+ :consistent_read => true,
60
+ :read_capacity => 10,
61
+ :write_capacity => 5,
62
+ :raise_errors => false,
63
+ # :max_age => 7*3600*24,
64
+ # :max_stale => 3600*5,
65
+ :enable_locking => false,
66
+ :lock_expiry_time => 500,
67
+ :lock_retry_delay => 500,
68
+ :lock_max_wait_time => 1,
69
+ :secret_key => nil,
70
+ :api_version => '2012-08-10'
71
+ }
72
+
73
+ # @return [String] Session table name.
74
+ attr_reader :table_name
75
+
76
+ # @return [String] Session table hash key name.
77
+ attr_reader :table_key
78
+
79
+ # @return [true] If a strongly consistent read is used
80
+ # @return [false] If an eventually consistent read is used.
81
+ # See AWS DynamoDB documentation for table consistent_read for more
82
+ # information on this setting.
83
+ attr_reader :consistent_read
84
+
85
+ # @return [Integer] Maximum number of reads consumed per second before
86
+ # DynamoDB returns a ThrottlingException. See AWS DynamoDB documentation
87
+ # for table read_capacity for more information on this setting.
88
+ attr_reader :read_capacity
89
+
90
+ # @return [Integer] Maximum number of writes consumed per second before
91
+ # DynamoDB returns a ThrottlingException. See AWS DynamoDB documentation
92
+ # for table write_capacity for more information on this setting.
93
+ attr_reader :write_capacity
94
+
95
+ # @return [true] All errors are raised up the stack when default ErrorHandler
96
+ # is used.
97
+ # @return [false] Only specified errors are raised up the stack when default
98
+ # ErrorHandler is used.
99
+ attr_reader :raise_errors
100
+
101
+ # @return [DynamoDB Client] DynamoDB client.
102
+ attr_reader :dynamo_db_client
103
+
104
+ # @return [Error Handler] An error handling object that handles all exceptions
105
+ # thrown during execution of the AWS DynamoDB Session Store Rack Middleware.
106
+ # For more information see the Handling Errors Section.
107
+ attr_reader :error_handler
108
+
109
+ # @return [Integer] Maximum number of seconds earlier
110
+ # from the current time that a session was created.
111
+ attr_reader :max_age
112
+
113
+ # @return [Integer] Maximum number of seconds
114
+ # before the current time that the session was last accessed.
115
+ attr_reader :max_stale
116
+
117
+ # @return [String] The secret key for HMAC encryption.
118
+ attr_reader :secret_key
119
+
120
+ # @return [true] Pessimistic locking strategy will be implemented for
121
+ # all session accesses.
122
+ # @return [false] No locking strategy will be implemented for
123
+ # all session accesses.
124
+ attr_reader :enable_locking
125
+
126
+ # @return [Integer] Time in milleseconds after which lock will expire.
127
+ attr_reader :lock_expiry_time
128
+
129
+ # @return [Integer] Time in milleseconds to wait before retrying to obtain
130
+ # lock once an attempt to obtain lock has been made and has failed.
131
+ attr_reader :lock_retry_delay
132
+
133
+ # @return [Integer] Maximum time in seconds to wait to acquire lock
134
+ # before giving up.
135
+ attr_reader :lock_max_wait_time
136
+
137
+
138
+ # Provides configuration object that allows access to options defined
139
+ # during Runtime, in a YAML file, in the ENV and by default.
140
+ #
141
+ # @option options [String] :table_name ("Sessions") Name of the session
142
+ # table.
143
+ # @option options [String] :table_key ("id") The hash key of the sesison
144
+ # table.
145
+ # @option options [Boolean] :consistent_read (true) If true, a strongly
146
+ # consistent read is used. If false, an eventually consistent read is
147
+ # used.
148
+ # @option options [Integer] :read_capacity (10) The maximum number of
149
+ # strongly consistent reads consumed per second before
150
+ # DynamoDB raises a ThrottlingException. See AWS DynamoDB documentation
151
+ # for table read_capacity for more information on this setting.
152
+ # @option options [Integer] :write_capacity (5) The maximum number of writes
153
+ # consumed per second before DynamoDB returns a ThrottlingException.
154
+ # See AWS DynamoDB documentation for table write_capacity for more
155
+ # information on this setting.
156
+ # @option options [DynamoDB Client] :dynamo_db_client
157
+ # (AWS::DynamoDB::ClientV2) DynamoDB client used to perform database
158
+ # operations inside of middleware application.
159
+ # @option options [Boolean] :raise_errors (false) If true, all errors are
160
+ # raised up the stack when default ErrorHandler. If false, Only specified
161
+ # errors are raised up the stack when default ErrorHandler is used.
162
+ # @option options [Error Handler] :error_handler (DefaultErrorHandler)
163
+ # An error handling object that handles all exceptions thrown during
164
+ # execution of the AWS DynamoDB Session Store Rack Middleware.
165
+ # For more information see the Handling Errors Section.
166
+ # @option options [Integer] :max_age (nil) Maximum number of seconds earlier
167
+ # from the current time that a session was created.
168
+ # @option options [Integer] :max_stale (nil) Maximum number of seconds
169
+ # before current time that session was last accessed.
170
+ # @option options [String] :secret_key (nil) Secret key for HMAC encription.
171
+ # @option options [Integer] :enable_locking (false) If true, a pessimistic
172
+ # locking strategy will be implemented for all session accesses.
173
+ # If false, no locking strategy will be implemented for all session
174
+ # accesses.
175
+ # @option options [Integer] :lock_expiry_time (500) Time in milliseconds
176
+ # after which lock expires on session.
177
+ # @option options [Integer] :lock_retry_delay (500) Time in milleseconds to
178
+ # wait before retrying to obtain lock once an attempt to obtain lock
179
+ # has been made and has failed.
180
+ # @option options [Integer] :lock_max_wait_time (500) Maximum time in seconds
181
+ # to wait to acquire lock before giving up.
182
+ # @option options [String] :secret_key (SecureRandom.hex(64))
183
+ # Secret key for HMAC encription.
184
+ def initialize(options = {})
185
+ @options = default_options.merge(
186
+ env_options.merge(
187
+ file_options(options).merge(
188
+ symbolize_keys(options)
189
+ )
190
+ )
191
+ )
192
+ @options = client_error.merge(@options)
193
+ set_attributes(@options)
194
+ end
195
+
196
+ # @return [Hash] The merged configuration hash.
197
+ def to_hash
198
+ @options.dup
199
+ end
200
+
201
+ private
202
+
203
+ # @return [Hash] DDB client.
204
+ def gen_dynamo_db_client
205
+ client_opts = client_subset(@options)
206
+ client = AWS::DynamoDB::Client
207
+ dynamo_db_client = @options[:dynamo_db_client] || client.new(client_opts)
208
+ {:dynamo_db_client => dynamo_db_client}
209
+ end
210
+
211
+ # @return [Hash] Default Error Handler
212
+ def gen_error_handler
213
+ default_handler = AWS::SessionStore::DynamoDB::Errors::DefaultHandler
214
+ error_handler = @options[:error_handler] ||
215
+ default_handler.new(@options[:raise_errors])
216
+ {:error_handler => error_handler}
217
+ end
218
+
219
+ # @return [Hash] Client and error objects in hash.
220
+ def client_error
221
+ gen_error_handler.merge(gen_dynamo_db_client)
222
+ end
223
+
224
+ # @return [Hash] Default Session table options.
225
+ def default_options
226
+ DEFAULTS
227
+ end
228
+
229
+ # @return [Hash] Environment options that are useful for Session Handler.
230
+ def env_options
231
+ default_options.keys.inject({}) do |opts, opt_name|
232
+ env_var = "DYNAMO_DB_SESSION_#{opt_name.to_s.upcase}"
233
+ opts[opt_name] = ENV[env_var] if ENV.key?(env_var)
234
+ opts
235
+ end
236
+ end
237
+
238
+ # @return [Hash] File options.
239
+ def file_options(options = {})
240
+ file_path = config_file_path(options)
241
+ if file_path
242
+ load_from_file(file_path)
243
+ elsif rails_defined && File.exists?(rails_config_file_path)
244
+ load_from_file(rails_config_file_path)
245
+ else
246
+ {}
247
+ end
248
+ end
249
+
250
+ # @return [Boolean] Necessary Rails variables defined.
251
+ def rails_defined
252
+ defined?(Rails) && defined?(Rails.root) && defined?(Rails.env)
253
+ end
254
+
255
+ # Load options from YAML file depending on existence of Rails
256
+ # and possible development stage defined.
257
+ def load_from_file(file_path)
258
+ require "erb"
259
+ opts = YAML.load(ERB.new(File.read(file_path)).result) || {}
260
+ opts = opts[Rails.env] if rails_defined && opts.key?(Rails.env)
261
+ symbolize_keys(opts)
262
+ end
263
+
264
+ # @return [String] Configuration path found in environment or YAML file.
265
+ def config_file_path(options)
266
+ options[:config_file] || ENV["DYNAMO_DB_SESSION_CONFIG_FILE"]
267
+ end
268
+
269
+ # @return [String] Rails configuraton path to YAML file default.
270
+ def rails_config_file_path
271
+ File.join(Rails.root, "config", "sessionstore/dynamodb.yml")
272
+ end
273
+
274
+ # Set accessible attributes after merged options.
275
+ def set_attributes(options)
276
+ @options.keys.each do |opt_name|
277
+ instance_variable_set("@#{opt_name}", options[opt_name])
278
+ end
279
+ end
280
+
281
+ # @return [Hash] Hash with all symbolized keys.
282
+ def symbolize_keys(options)
283
+ options.inject({}) do |opts, (opt_name, opt_value)|
284
+ opts[opt_name.to_sym] = opt_value
285
+ opts
286
+ end
287
+ end
288
+
289
+ # @return [Hash] Client subset options hash.
290
+ def client_subset(options = {})
291
+ client_keys = [:aws_secret_key, :aws_region, :aws_access_key, :api_version]
292
+ options.inject({}) do |opts, (opt_name, opt_value)|
293
+ opts[opt_name.to_sym] = opt_value if client_keys.include?(opt_name.to_sym)
294
+ opts
295
+ end
296
+ end
297
+ end
298
+ end