# frozen_string_literal: truemoduleAws::SessionStore::DynamoDB::Locking# Handles session management.classBase# @param [Aws::SessionStore::DynamoDB::Configuration] cfgdefinitialize(cfg)@config=cfgend# Updates session in databasedefset_session_data(env,sid,session,options={})returnfalseifsession.empty?packed_session=pack_data(session)handle_error(env)dosave_opts=update_opts(env,sid,packed_session,options)@config.dynamo_db_client.update_item(save_opts)sidendend# Retrieves session data based on iddefget_session_data(env,sid)raiseNotImplementedErrorend# Deletes session based on iddefdelete_session(env,sid)handle_error(env)do@config.dynamo_db_client.delete_item(delete_opts(sid))endendprivate# Each database operation is placed in this rescue wrapper.# This wrapper will call the method, rescue any exceptions and then pass# exceptions to the configured error handler.defhandle_error(env=nil)yieldrescueAws::DynamoDB::Errors::ServiceError=>e@config.error_handler.handle_error(e,env)end# @return [Hash] Options for deleting session.defdelete_opts(sid)table_opts(sid)end# @return [Hash] Options for updating item in Session table.defupdate_opts(env,sid,session,options={})ifenv['dynamo_db.new_session']save_new_opts(env,sid,session)elsesave_exists_opts(env,sid,session,options)endend# @return [Hash] Options for saving a new session in database.defsave_new_opts(env,sid,session)attribute_opts=attr_updts(env,session,created_attr)merge_all(table_opts(sid),attribute_opts)end# @return [Hash] Options for saving an existing sesison in the database.defsave_exists_opts(env,sid,session,options={})add_attr=options[:add_attrs]||{}expected=options[:expect_attr]||{}attribute_opts=merge_all(attr_updts(env,session,add_attr),expected)merge_all(table_opts(sid),attribute_opts)end# Marshal the data.defpack_data(data)[Marshal.dump(data)].pack('m*')end# Unmarshal the data.defunpack_data(packed_data)Marshal.load(packed_data.unpack1('m*'))end# Table options for client.deftable_opts(sid){table_name: @config.table_name,key: {@config.table_key=>sid}}end# Attributes to update via client.defattr_updts(env,session,add_attrs={})data=data_unchanged?(env,session)?{}:data_attr(session){attribute_updates: merge_all(updated_attr,data,add_attrs,expire_attr),return_values: 'UPDATED_NEW'}end# Update client with current time attribute.defupdated_at{value: Time.now.to_f.to_s,action: 'PUT'}end# Attribute for creation of session.defcreated_attr{'created_at'=>updated_at}end# Update client with current time + max_stale.defexpire_atmax_stale=@config.max_stale||0{value: (Time.now+max_stale).to_i,action: 'PUT'}end# Attribute for TTL expiration of session.defexpire_attr{'expire_at'=>expire_at}end# Attribute for updating session.defupdated_attr{'updated_at'=>updated_at}enddefdata_attr(session){'data'=>{value: session,action: 'PUT'}}end# Determine if data has been manipulateddefdata_unchanged?(env,session)returnfalseunlessenv['rack.initial_data']env['rack.initial_data']==sessionend# Expected attributesdefexpected_attributes(sid){expected: {@config.table_key=>{value: sid,exists: true}}}end# Attributes to be retrieved via clientdefattr_opts{attributes_to_get: ['data'],consistent_read: @config.consistent_read}end# @return [Hash] merged hash of all hashes passed in.defmerge_all(*hashes)new_hash={}hashes.each{|hash|new_hash.merge!(hash)}new_hashendendend