Skip to content

Commit

Permalink
Updated the data objects sessions table to include ip and agent. No l…
Browse files Browse the repository at this point in the history
…onger insert user agent entries on each request cycle, but on session creates.
  • Loading branch information
nicholas committed Jul 31, 2010
1 parent 6f58bd4 commit c3841fa
Show file tree
Hide file tree
Showing 10 changed files with 79 additions and 32 deletions.
3 changes: 2 additions & 1 deletion lib/harbor/application.rb
Expand Up @@ -3,14 +3,15 @@

require "yaml"

require Pathname(__FILE__).dirname + "events"
require Pathname(__FILE__).dirname + "request"
require Pathname(__FILE__).dirname + "response"
require Pathname(__FILE__).dirname + "block_io"
require Pathname(__FILE__).dirname + "zipped_io"
require Pathname(__FILE__).dirname + "events"
require Pathname(__FILE__).dirname + "events" + "dispatch_request_event"
require Pathname(__FILE__).dirname + "events" + "not_found_event"
require Pathname(__FILE__).dirname + "events" + "application_exception_event"
require Pathname(__FILE__).dirname + "events" + "session_created_event_context"
require Pathname(__FILE__).dirname + "event_context"
require Pathname(__FILE__).dirname + "messages"

Expand Down
9 changes: 6 additions & 3 deletions lib/harbor/contrib/session/data_mapper.rb
Expand Up @@ -16,7 +16,7 @@ class Session
# A basic Session resource is defined for you.
##
class DataMapper < Harbor::Session::Abstract

class SessionHash < Hash
def initialize(instance)
super()
Expand All @@ -43,14 +43,17 @@ def instance
end
end

def self.load_session(cookie)
def self.load_session(delegate, cookie, request = nil)
session = if expire_after = Harbor::Session.options[:expire_after]
::Session.first(:id => cookie, :updated_at.gte => Time.now - expire_after)
else
::Session.get(cookie)
end

session ||= ::Session.create
unless session
session = ::Session.create
delegate.session_created(session.id, request.remote_ip, request.env["HTTP_USER_AGENT"])
end

SessionHash.new(session)
end
Expand Down
41 changes: 25 additions & 16 deletions lib/harbor/contrib/session/data_objects.rb
Expand Up @@ -15,16 +15,16 @@ class Session
##
class DataObjects < Harbor::Session::Abstract
class UnsupportedDatabaseError < StandardError; end

class SessionHash
class SessionHash
def initialize(raw)
@raw = raw
@data = nil
@dirty = false
end

def [](key)
if key == :session_id or key == :user_id
if [:session_id, :user_id, :remote_ip, :user_agent_raw].include?(key)
@raw[key]
else
load_data![key]
Expand All @@ -35,9 +35,8 @@ def []=(key, value)
raise ArgumentError.new("You cannot manually set the session_id for a session.") if key == :session_id

@dirty = true

if key == :user_id
@raw[:user_id] = value
if [:session_id, :user_id, :remote_ip, :user_agent_raw].include?(key)
@raw[key] = value
else
load_data![key] = value
end
Expand All @@ -57,14 +56,18 @@ def load_data!
@data = DataObjects.load(@raw[:data])
end

def clear
@data.clear
end

def to_hash
@data
end
end

def self.load_session(cookie)
def self.load_session(delegate, cookie, request = nil)
create_session_table unless session_table_exists?

if cookie
raw_session = if expire_after = Harbor::Session.options[:expire_after]
get_raw_session(cookie, Time.now - expire_after)
Expand All @@ -73,7 +76,7 @@ def self.load_session(cookie)
end
end

raw_session ||= create_session
raw_session ||= create_session(delegate, {}, request)

SessionHash.new(raw_session)
end
Expand Down Expand Up @@ -116,21 +119,25 @@ def self.create_session_table
@table_exists = true
end

def self.create_session(data = {})
def self.create_session(delegate, data = {}, request = nil)
session_id = `uuidgen`.chomp

user_id = data.delete(:user_id)
remote_ip = request ? request.remote_ip : nil
user_agent_raw = request ? request.env["HTTP_USER_AGENT"] : nil

data = self.dump(data)
now = Time.now

statement = "INSERT INTO sessions (id, data, user_id, created_at, updated_at) VALUES (?, ?, ?, ?, ?);"
execute(statement, session_id, data, user_id, now, now)
statement = "INSERT INTO sessions (id, data, user_id, remote_ip, user_agent_raw, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?);"
execute(statement, session_id, data, user_id, remote_ip, user_agent_raw, now, now)
delegate.session_created(session_id, remote_ip, user_agent_raw)

{:session_id => session_id, :data => data, :user_id => user_id}
{:session_id => session_id, :data => data, :user_id => user_id, :remote_ip => remote_ip, :user_agent_raw => user_agent_raw}
end

def self.get_raw_session(cookie, updated_at=nil)
query = "SELECT id, data, user_id FROM sessions WHERE id = ? "
query = "SELECT id, data, user_id, remote_ip, user_agent_raw FROM sessions WHERE id = ? "
params = [cookie]

if updated_at
Expand All @@ -148,6 +155,8 @@ def self.get_raw_session(cookie, updated_at=nil)
raw[:session_id] = reader.values[0]
raw[:data] = reader.values[1]
raw[:user_id] = reader.values[2]
raw[:remote_ip] = reader.values[3]
raw[:user_agent_raw] = reader.values[4]
else
raw = nil
end
Expand Down Expand Up @@ -193,9 +202,9 @@ def self.with_connection
def self.create_session_table_sql
case scheme
when :sqlite3
"CREATE TABLE sessions (id VARCHAR(50) NOT NULL, user_id INTEGER, data TEXT, created_at DATETIME, updated_at DATETIME, PRIMARY KEY(id))"
"CREATE TABLE sessions (id VARCHAR(50) NOT NULL, user_id INTEGER, remote_ip INET, user_agent_raw TEXT, data TEXT, created_at DATETIME, updated_at DATETIME, PRIMARY KEY(id))"
when :postgres
"CREATE TABLE sessions (id VARCHAR(50) NOT NULL, user_id INTEGER, data TEXT, created_at TIMESTAMP, updated_at TIMESTAMP, PRIMARY KEY(id))"
"CREATE TABLE sessions (id VARCHAR(50) NOT NULL, user_id INTEGER, remote_ip INET, user_agent_raw TEXT, data TEXT, created_at TIMESTAMP, updated_at TIMESTAMP, PRIMARY KEY(id))"
else
raise UnsupportedDatabaseError.new("Only SQLite3 and PostgreSQL are supported at the moment")
end
Expand Down
11 changes: 9 additions & 2 deletions lib/harbor/contrib/stats.rb
Expand Up @@ -19,6 +19,14 @@ def self.orm
end
end

Harbor::Session.register_event_handler(:session_created) do |event|
if orm = Harbor::Contrib::Stats.orm
orm::UserAgent.create(event.session_id, event.remote_ip, event.user_agent)
else
warn "Harbor::Contrib::Stats::orm must be set to generate statistics."
end
end

Harbor::Application.register_event_handler(:request_complete) do |event|
request = event.request
response = event.response
Expand All @@ -28,9 +36,8 @@ def self.orm

# We only record a PageView if we get a 200 and it's an actual page rendering, not providing an image or downloading a file
orm::PageView.create(session.id, request.uri, request.referrer) if %w(text/html text/xml text/json).include?(response.content_type) && response.status == 200
orm::UserAgent.create(session.id, request.remote_ip, request.env["HTTP_USER_AGENT"])
end
else
warn "Harbor::Contrib::Stats::orm must be set to generate statistics."
end
end
end
15 changes: 15 additions & 0 deletions lib/harbor/events/session_created_event_context.rb
@@ -0,0 +1,15 @@
module Harbor
module Events
class SessionCreatedEventContext

attr_reader :session_id, :remote_ip, :user_agent

def initialize(session_id, remote_ip, user_agent)
@session_id = session_id
@remote_ip = remote_ip
@user_agent = user_agent
end

end
end
end
8 changes: 7 additions & 1 deletion lib/harbor/session.rb
Expand Up @@ -4,6 +4,8 @@
module Harbor

class Session
include Harbor::Events

DEFAULT_OPTIONS = {
:key => "harbor.session",
:domain => nil,
Expand Down Expand Up @@ -36,9 +38,13 @@ def initialize(request, key = nil)
@cookie = request.cookies[key] || request.cookies[@options[:key]]
@store = self.class.options[:store]
@request = request
@data ||= @store.load_session(@cookie)
@data ||= @store.load_session(self, @cookie, @request)
end

def session_created(session_id, remote_ip, user_agent_raw)
raise_event2(:session_created, Harbor::Events::SessionCreatedEventContext.new(session_id, remote_ip, user_agent_raw))
end

def key
@options[:key]
end
Expand Down
2 changes: 1 addition & 1 deletion lib/harbor/session/abstract.rb
Expand Up @@ -10,7 +10,7 @@ class Abstract
# Receives the raw cookie data, and should return a hash
# of the data for the session.
##
def self.load_session(cookie)
def self.load_session(delegate, cookie, request = nil)
Marshal.load(cookie.unpack("m*")[0]) rescue {}
end

Expand Down
9 changes: 7 additions & 2 deletions lib/harbor/session/cookie.rb
Expand Up @@ -6,9 +6,14 @@ class Session
# session_id's.
##
class Cookie < Abstract
def self.load_session(cookie)
def self.load_session(delegate, cookie, request = nil)
cookie = super
cookie[:session_id] ||= `uuidgen`.chomp

unless cookie[:session_id]
cookie[:session_id] = `uuidgen`.chomp
delegate.session_created(cookie[:session_id], request.remote_ip, request.env["HTTP_USER_AGENT"])
end

cookie
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/harbor/version.rb
@@ -1,3 +1,3 @@
module Harbor
VERSION = "0.18.37"
VERSION = "0.18.38"
end
11 changes: 6 additions & 5 deletions test/contrib/session/data_objects_test.rb
Expand Up @@ -29,7 +29,7 @@ def setup
end
end

def teardown
def teardown
Harbor::Session.configure do |session|
session[:store] = Harbor::Session::Cookie
session.delete(:connection_uri)
Expand Down Expand Up @@ -163,7 +163,7 @@ def test_data_is_lazy_parsed
def assert_session_valid_and_save(time_elapsed, request, value, new_value)
Time.warp(time_elapsed) do
request_session = Harbor::Session.new(request)

assert_equal 1, session_records_count
assert_equal value, request_session[:value]

Expand All @@ -187,15 +187,16 @@ def get_raw_session(cookie, updated_at=nil)
end

def create_session(data = {})
Harbor::Contrib::Session::DataObjects.create_session(data)
@_session = Harbor::Session.new(CookieRequest.new)
Harbor::Contrib::Session::DataObjects.create_session(@_session, data)
end

def session_records_count
count = 0

Harbor::Contrib::Session::DataObjects.with_connection do |connection|
cmd = connection.create_command("SELECT COUNT(id) FROM sessions;")
reader = cmd.execute_reader
cmd = connection.create_command("SELECT COUNT(id) FROM sessions WHERE id NOT IN (?);")
reader = cmd.execute_reader(@_session ? @_session.id : '')
if reader.next! then count = reader.values[0] end
reader.close
end
Expand Down

0 comments on commit c3841fa

Please sign in to comment.