Fixed race condition in Sessions.create().

This commit is contained in:
Martin Edenhofer 2015-05-03 11:22:48 +02:00
parent d8d506ea44
commit 6d5a02fd80

View file

@ -10,8 +10,7 @@ module Sessions
end end
# get working directories # get working directories
@path = @root + '/tmp/websocket' @path = "#{@root}/tmp/websocket"
@pid = @root + '/tmp/pids/sessionworker.pid'
# create global vars for threads # create global vars for threads
@@client_threads = {} @@client_threads = {}
@ -29,18 +28,27 @@ returns
=end =end
def self.create( client_id, session, meta ) def self.create( client_id, session, meta )
path = @path + '/' + client_id.to_s path = "#{@path}/#{client_id}"
FileUtils.mkpath path path_tmp = "#{@path}/tmp/#{client_id}"
session_file = "#{path_tmp}/session"
# collect session data
meta[:last_ping] = Time.new.to_i.to_s meta[:last_ping] = Time.new.to_i.to_s
data = { data = {
user: session, user: session,
meta: meta, meta: meta,
} }
content = data.to_s content = data.to_json
File.open( path + '/session', 'wb' ) { |file|
# store session data in session file
FileUtils.mkpath path_tmp
File.open( session_file, 'wb' ) { |file|
file.write content file.write content
} }
# move to destination directory
FileUtils.mv( path_tmp, path )
# send update to browser # send update to browser
if session && session['id'] if session && session['id']
self.send( self.send(
@ -66,7 +74,7 @@ returns
=end =end
def self.sessions def self.sessions
path = @path + '/' path = "#{@path}/"
# just make sure that spool path exists # just make sure that spool path exists
if !File::exist?( path ) if !File::exist?( path )
@ -75,7 +83,10 @@ returns
data = [] data = []
Dir.foreach( path ) do |entry| Dir.foreach( path ) do |entry|
next if entry == '.' || entry == '..' || entry == 'spool' next if entry == '.'
next if entry == '..'
next if entry == 'tmp'
next if entry == 'spool'
data.push entry.to_s data.push entry.to_s
end end
data data
@ -153,7 +164,7 @@ returns
=end =end
def self.destory( client_id ) def self.destory( client_id )
path = @path + '/' + client_id.to_s path = "#{@path}/#{client_id}"
FileUtils.rm_rf path FileUtils.rm_rf path
end end
@ -171,7 +182,7 @@ returns
def self.destory_idle_sessions(idle_time_in_sec = 240) def self.destory_idle_sessions(idle_time_in_sec = 240)
list_of_closed_sessions = [] list_of_closed_sessions = []
clients = Sessions.list clients = Sessions.list
clients.each { |client_id, client| clients.each { |client_id, client|
if !client[:meta] || !client[:meta][:last_ping] || ( client[:meta][:last_ping].to_i + idle_time_in_sec ) < Time.now.to_i if !client[:meta] || !client[:meta][:last_ping] || ( client[:meta][:last_ping].to_i + idle_time_in_sec ) < Time.now.to_i
list_of_closed_sessions.push client_id list_of_closed_sessions.push client_id
@ -196,10 +207,11 @@ returns
def self.touch( client_id ) def self.touch( client_id )
data = self.get(client_id) data = self.get(client_id)
return false if !data return false if !data
path = @path + '/' + client_id.to_s path = "#{@path}/#{client_id}"
data[:meta][:last_ping] = Time.new.to_i.to_s data[:meta][:last_ping] = Time.new.to_i.to_s
content = data.to_json
File.open( path + '/session', 'wb' ) { |file| File.open( path + '/session', 'wb' ) { |file|
file.write data.to_json file.write content
} }
true true
end end
@ -225,12 +237,12 @@ returns
=end =end
def self.get( client_id ) def self.get( client_id )
session_dir = @path + '/' + client_id.to_s session_dir = "#{@path}/#{client_id}"
session_file = session_dir + '/session' session_file = "#{session_dir}/session"
data = nil data = nil
if !File.exist? session_file if !File.exist? session_file
self.destory(client_id) self.destory(client_id)
puts "ERROR: missing session file for '#{client_id.to_s}', remove session." puts "ERROR: missing session file for '#{client_id}', remove session."
return return
end end
begin begin
@ -266,14 +278,14 @@ returns
=end =end
def self.send( client_id, data ) def self.send( client_id, data )
path = @path + '/' + client_id.to_s + '/' path = "#{@path}/#{client_id}/"
filename = 'send-' + Time.new().to_f.to_s# + '-' + rand(99999999).to_s filename = "send-#{ Time.new().to_f }"
check = true check = true
count = 0 count = 0
while check while check
if File::exist?( path + filename ) if File::exist?( path + filename )
count += 1 count += 1
filename = filename + '-' + count filename = "#{filename}-#{count}"
else else
check = false check = false
end end
@ -361,15 +373,16 @@ returns
=end =end
def self.queue( client_id ) def self.queue( client_id )
path = @path + '/' + client_id.to_s + '/' path = "#{@path}/#{client_id}/"
data = [] data = []
files = [] files = []
Dir.foreach( path ) {|entry| Dir.foreach( path ) {|entry|
next if entry == '.' || entry == '..' next if entry == '.'
next if entry == '..'
files.push entry files.push entry
} }
files.sort.each {|entry| files.sort.each {|entry|
filename = path + '/' + entry filename = "#{path}/#{entry}"
if /^send/.match( entry ) if /^send/.match( entry )
data.push Sessions.queue_file_read( path, entry ) data.push Sessions.queue_file_read( path, entry )
end end
@ -378,10 +391,9 @@ returns
end end
def self.queue_file_read( path, filename ) def self.queue_file_read( path, filename )
file_old = path + filename file_old = "#{path}#{filename}"
file_new = path + 'a-' + filename file_new = "#{path}a-#{filename}"
FileUtils.mv( file_old, file_new ) FileUtils.mv( file_old, file_new )
data = nil
all = '' all = ''
File.open( file_new, 'rb' ) { |file| File.open( file_new, 'rb' ) { |file|
all = file.read all = file.read
@ -390,15 +402,17 @@ returns
JSON.parse( all ) JSON.parse( all )
end end
def self.spool_cleanup def self.cleanup
path = @path + '/spool/' path = "#{@path}/spool/"
FileUtils.rm_rf path
path = "#{@path}/tmp/"
FileUtils.rm_rf path FileUtils.rm_rf path
end end
def self.spool_create( msg ) def self.spool_create( msg )
path = @path + '/spool/' path = "#{@path}/spool/"
FileUtils.mkpath path FileUtils.mkpath path
file = Time.new.to_f.to_s + '-' + rand(99_999).to_s file = "#{Time.new.to_f}-#{rand(99_999)}"
File.open( path + '/' + file, 'wb' ) { |file| File.open( path + '/' + file, 'wb' ) { |file|
data = { data = {
msg: msg, msg: msg,
@ -409,20 +423,21 @@ returns
end end
def self.spool_list( timestamp, current_user_id ) def self.spool_list( timestamp, current_user_id )
path = @path + '/spool/' path = "#{@path}/spool/"
FileUtils.mkpath path FileUtils.mkpath path
data = [] data = []
to_delete = [] to_delete = []
files = [] files = []
Dir.foreach( path ) {|entry| Dir.foreach( path ) {|entry|
next if entry == '.' || entry == '..' next if entry == '.'
next if entry == '..'
files.push entry files.push entry
} }
files.sort.each {|entry| files.sort.each {|entry|
filename = path + '/' + entry filename = "#{path}/#{entry}"
next if !File::exist?( filename ) next if !File::exist?( filename )
File.open( filename, 'rb' ) { |file| File.open( filename, 'rb' ) { |file|
all = file.read all = file.read
spool = JSON.parse( all ) spool = JSON.parse( all )
begin begin
message_parsed = JSON.parse( spool['msg'] ) message_parsed = JSON.parse( spool['msg'] )
@ -433,7 +448,7 @@ returns
# ignore message older then 48h # ignore message older then 48h
if spool['timestamp'] + (2 * 86_400) < Time.now.to_i if spool['timestamp'] + (2 * 86_400) < Time.now.to_i
to_delete.push path + '/' + entry to_delete.push "#{path}/#{entry}"
next next
end end