class Stealth::Session

Constants

SLUG_SEPARATOR

Attributes

flow[R]
previous[R]
session[RW]
state[R]
user_id[R]

Public Class Methods

canonical_session_slug(flow:, state:) click to toggle source
# File lib/stealth/session.rb, line 117
def self.canonical_session_slug(flow:, state:)
  [flow, state].join(SLUG_SEPARATOR)
end
flow_and_state_from_session_slug(slug:) click to toggle source
# File lib/stealth/session.rb, line 27
def self.flow_and_state_from_session_slug(slug:)
  {
    flow: slug&.split(SLUG_SEPARATOR)&.first,
    state: slug&.split(SLUG_SEPARATOR)&.last
  }
end
is_a_session_string?(string) click to toggle source
# File lib/stealth/session.rb, line 112
def self.is_a_session_string?(string)
  session_regex = /(.+)(#{SLUG_SEPARATOR})(.+)/
  !!string.match(session_regex)
end
new(user_id: nil, previous: false) click to toggle source
# File lib/stealth/session.rb, line 12
def initialize(user_id: nil, previous: false)
  @user_id = user_id
  @previous = previous

  if user_id.present?
    unless defined?($redis) && $redis.present?
      raise(Stealth::Errors::RedisNotConfigured, "Please make sure REDIS_URL is configured before using sessions")
    end

    get
  end

  self
end

Public Instance Methods

+(steps) click to toggle source
# File lib/stealth/session.rb, line 91
def +(steps)
  return nil if flow.blank?
  return self if steps.zero?

  new_state = self.state + steps
  new_session = Stealth::Session.new(user_id: self.user_id)
  new_session.session = self.class.canonical_session_slug(flow: self.flow_string, state: new_state)

  new_session
end
-(steps) click to toggle source
# File lib/stealth/session.rb, line 102
def -(steps)
  return nil if flow.blank?

  if steps < 0
    return self + steps.abs
  else
    return self + (-steps)
  end
end
blank?() click to toggle source
# File lib/stealth/session.rb, line 83
def blank?
  !present?
end
flow_string() click to toggle source
# File lib/stealth/session.rb, line 44
def flow_string
  session&.split(SLUG_SEPARATOR)&.first
end
get() click to toggle source
# File lib/stealth/session.rb, line 52
def get
  prev_key = previous_session_key(user_id: user_id)

  @session ||= begin
    if sessions_expire?
      previous? ? getex(prev_key) : getex(user_id)
    else
      previous? ? $redis.get(prev_key) : $redis.get(user_id)
    end
  end
end
present?() click to toggle source
# File lib/stealth/session.rb, line 79
def present?
  session.present?
end
previous?() click to toggle source
# File lib/stealth/session.rb, line 87
def previous?
  @previous
end
set(flow:, state:) click to toggle source
# File lib/stealth/session.rb, line 64
def set(flow:, state:)
  store_current_to_previous(flow: flow, state: state)

  @flow = nil
  @session = self.class.canonical_session_slug(flow: flow, state: state)

  Stealth::Logger.l(topic: "session", message: "User #{user_id}: setting session to #{flow}->#{state}")

  if sessions_expire?
    $redis.setex(user_id, Stealth.config.session_ttl, session)
  else
    $redis.set(user_id, session)
  end
end
state_string() click to toggle source
# File lib/stealth/session.rb, line 48
def state_string
  session&.split(SLUG_SEPARATOR)&.last
end

Private Instance Methods

getex(key) click to toggle source
# File lib/stealth/session.rb, line 143
def getex(key)
  $redis.multi do
    $redis.expire(key, Stealth.config.session_ttl)
    $redis.get(key)
  end.last
end
previous_session_key(user_id:) click to toggle source
# File lib/stealth/session.rb, line 123
def previous_session_key(user_id:)
  [user_id, 'previous'].join('-')
end
sessions_expire?() click to toggle source
# File lib/stealth/session.rb, line 139
def sessions_expire?
  Stealth.config.session_ttl > 0
end
store_current_to_previous(flow:, state:) click to toggle source
# File lib/stealth/session.rb, line 127
def store_current_to_previous(flow:, state:)
  new_session = self.class.canonical_session_slug(flow: flow, state: state)

  # Prevent previous_session from becoming current_session
  if new_session == session
    Stealth::Logger.l(topic: "previous_session", message: "User #{user_id}: skipping setting to #{session} because it is the same as current_session")
  else
    Stealth::Logger.l(topic: "previous_session", message: "User #{user_id}: setting to #{session}")
    $redis.set(previous_session_key(user_id: user_id), session)
  end
end