From 014ff4bda22a50dcda8e75cd789ece7edffc49af Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Sun, 13 Jul 2014 20:52:32 +0200 Subject: [PATCH] Rewrite of session backend. --- app/controllers/sessions/collection_base.rb | 18 +- app/controllers/sessions/collection_ticket.rb | 18 +- app/models/recent_view.rb | 2 +- lib/sessions.rb | 81 +---- lib/sessions/backend/activity_stream.rb | 85 +++-- lib/sessions/backend/collections.rb | 100 ++--- lib/sessions/backend/collections/base.rb | 137 +++++++ .../backend/collections/email_address.rb | 4 + lib/sessions/backend/collections/group.rb | 3 + .../backend/collections/organization.rb | 67 ++++ lib/sessions/backend/collections/role.rb | 3 + lib/sessions/backend/collections/signature.rb | 4 + .../collections/ticket_article_sender.rb | 3 + .../collections/ticket_article_type.rb | 3 + .../backend/collections/ticket_priority.rb | 3 + .../backend/collections/ticket_state.rb | 3 + lib/sessions/backend/recent_viewed.rb | 80 ++-- lib/sessions/backend/rss.rb | 80 ++-- lib/sessions/backend/ticket_create.rb | 99 +++-- lib/sessions/backend/ticket_overview_index.rb | 79 ++-- lib/sessions/backend/ticket_overview_list.rb | 180 +++++---- lib/sessions/cache_in.rb | 5 + lib/sessions/client.rb | 143 ++------ lib/sessions/worker.rb | 56 --- test/unit/session_basic_test.rb | 342 ++++++++++++++++++ test/unit/session_collections_test.rb | 147 ++++++++ ...ssion_test.rb => session_enhanced_test.rb} | 189 ++++++---- 27 files changed, 1290 insertions(+), 644 deletions(-) create mode 100644 lib/sessions/backend/collections/base.rb create mode 100644 lib/sessions/backend/collections/email_address.rb create mode 100644 lib/sessions/backend/collections/group.rb create mode 100644 lib/sessions/backend/collections/organization.rb create mode 100644 lib/sessions/backend/collections/role.rb create mode 100644 lib/sessions/backend/collections/signature.rb create mode 100644 lib/sessions/backend/collections/ticket_article_sender.rb create mode 100644 lib/sessions/backend/collections/ticket_article_type.rb create mode 100644 lib/sessions/backend/collections/ticket_priority.rb create mode 100644 lib/sessions/backend/collections/ticket_state.rb delete mode 100644 lib/sessions/worker.rb create mode 100644 test/unit/session_basic_test.rb create mode 100644 test/unit/session_collections_test.rb rename test/unit/{session_test.rb => session_enhanced_test.rb} (67%) diff --git a/app/controllers/sessions/collection_base.rb b/app/controllers/sessions/collection_base.rb index 80af0495f..b3abe18e1 100644 --- a/app/controllers/sessions/collection_base.rb +++ b/app/controllers/sessions/collection_base.rb @@ -19,16 +19,16 @@ module ExtraCollection def push( collections, user ) # all base stuff - collections[ Role.to_app_model ] = Role.all - collections[ Group.to_app_model ] = Group.all + #collections[ Role.to_app_model ] = Role.all + #collections[ Group.to_app_model ] = Group.all - if !user.is_role('Customer') - collections[ Organization.to_app_model ] = Organization.all - else - if user.organization_id - collections[ Organization.to_app_model ] = Organization.where( :id => user.organization_id ) - end - end + #if !user.is_role('Customer') + # collections[ Organization.to_app_model ] = Organization.all + #else + # if user.organization_id + # collections[ Organization.to_app_model ] = Organization.where( :id => user.organization_id ) + # end + #end end module_function :session, :push end diff --git a/app/controllers/sessions/collection_ticket.rb b/app/controllers/sessions/collection_ticket.rb index b05a02b3f..032b79a91 100644 --- a/app/controllers/sessions/collection_ticket.rb +++ b/app/controllers/sessions/collection_ticket.rb @@ -22,20 +22,20 @@ module ExtraCollection def push( collections, user ) # all ticket stuff - collections[ Ticket::StateType.to_app_model ] = Ticket::StateType.all - collections[ Ticket::State.to_app_model ] = Ticket::State.all - collections[ Ticket::Priority.to_app_model ] = Ticket::Priority.all - collections[ Ticket::Article::Type.to_app_model ] = Ticket::Article::Type.all - collections[ Ticket::Article::Sender.to_app_model ] = Ticket::Article::Sender.all + #collections[ Ticket::StateType.to_app_model ] = Ticket::StateType.all + #collections[ Ticket::State.to_app_model ] = Ticket::State.all + #collections[ Ticket::Priority.to_app_model ] = Ticket::Priority.all + #collections[ Ticket::Article::Type.to_app_model ] = Ticket::Article::Type.all + #collections[ Ticket::Article::Sender.to_app_model ] = Ticket::Article::Sender.all - if !user.is_role('Customer') + #if !user.is_role('Customer') # all signatures - collections[ Signature.to_app_model ] = Signature.all + # collections[ Signature.to_app_model ] = Signature.all # all email addresses - collections[ EmailAddress.to_app_model ] = EmailAddress.all - end + # collections[ EmailAddress.to_app_model ] = EmailAddress.all + #end end module_function :session, :push diff --git a/app/models/recent_view.rb b/app/models/recent_view.rb index fc0f07204..c3a37ed15 100644 --- a/app/models/recent_view.rb +++ b/app/models/recent_view.rb @@ -37,7 +37,7 @@ class RecentView < ApplicationModel data.delete( 'history_object_id' ) list.push data } - return list + list end def self.list_fulldata( user, limit = 10 ) diff --git a/lib/sessions.rb b/lib/sessions.rb index aa3ed41c7..80a422ed5 100644 --- a/lib/sessions.rb +++ b/lib/sessions.rb @@ -14,7 +14,6 @@ module Sessions @pid = @root + '/tmp/pids/sessionworker.pid' # create global vars for threads - @@user_threads = {} @@client_threads = {} =begin @@ -458,23 +457,6 @@ returns user = User.find( session_data[:user][:id] ) next if !user - # start user thread - start_user_thread = false - if !@@user_threads[user.id] - @@user_threads[user.id] = true - @@user_threads[user.id] = Thread.new { - thread_worker(user.id) - @@user_threads[user.id] = nil - puts "close user (#{user.id}) thread" - } - start_user_thread = true - end - - # wait with client thread unil user thread has done some little work - if start_user_thread - sleep 0.5 - end - # start client thread if !@@client_threads[client_id] @@client_threads[client_id] = true @@ -493,68 +475,6 @@ returns =begin -check if worker for user is running - - Sessions.thread_worker_exists?(user) - -returns - - thread - -=end - - def self.thread_worker_exists?(user) - @@user_threads[user.id] - end - -=begin - -start worker for user - - Sessions.thread_worker(user.id) - -returns - - thread - -=end - - def self.thread_worker(user_id, try_count = 0, try_run_time = Time.now) - puts "LOOP WORKER #{user_id} - #{try_count}" - begin - Sessions::Worker.new(user_id) - rescue => e - puts "thread_worker exited with error #{ e.inspect }" - sleep 10 - begin -# ActiveRecord::Base.remove_connection -# ActiveRecord::Base.connection_pool.reap - ActiveRecord::Base.connection_pool.release_connection - rescue => e - puts "Can't reconnect to database #{ e.inspect }" - end - - try_run_max = 10 - try_count += 1 - - # reset error counter if to old - if try_run_time + ( 60 * 5 ) < Time.now - try_count = 0 - end - try_run_time = Time.now - - # restart worker again - if try_run_max > try_count - thread_worker(user_id, try_count, try_run_time) - else - raise "STOP thread_worker for user #{user_id} after #{try_run_max} tries" - end - end - puts "/LOOP WORKER #{user_id} - #{try_count}" - end - -=begin - check if thread for client_id is running Sessions.thread_client_exists?(client_id) @@ -587,6 +507,7 @@ returns Sessions::Client.new(client_id) rescue => e puts "thread_client exited with error #{ e.inspect }" + puts e.backtrace.join("\n ") sleep 10 begin # ActiveRecord::Base.remove_connection diff --git a/lib/sessions/backend/activity_stream.rb b/lib/sessions/backend/activity_stream.rb index cb87d28c0..3a4fcb64a 100644 --- a/lib/sessions/backend/activity_stream.rb +++ b/lib/sessions/backend/activity_stream.rb @@ -1,38 +1,63 @@ -module Sessions::Backend::ActivityStream +class Sessions::Backend::ActivityStream - def self.worker( user, worker ) - cache_key = 'user_' + user.id.to_s + '_activity_stream' - if Sessions::CacheIn.expired(cache_key) - activity_stream = user.activity_stream( 20 ) - activity_stream_cache = Sessions::CacheIn.get( cache_key, { :re_expire => true } ) - worker.log 'notice', 'fetch activity_stream - ' + cache_key - if activity_stream != activity_stream_cache - worker.log 'notify', 'fetch activity_stream changed - ' + cache_key - - activity_stream_full = user.activity_stream( 20, true ) - Sessions::CacheIn.set( cache_key, activity_stream, { :expires_in => 0.75.minutes } ) - Sessions::CacheIn.set( cache_key + '_push', activity_stream_full ) - end - end + def initialize( user, client = nil, client_id = nil ) + @user = user + @client = client + @client_id = client_id + @last_change = nil end - def self.push( user, client ) - cache_key = 'user_' + user.id.to_s + '_activity_stream' + def load - activity_stream_time = Sessions::CacheIn.get_time( cache_key, { :ignore_expire => true } ) - if activity_stream_time && client.last_change['activity_stream'] != activity_stream_time - client.last_change['activity_stream'] = activity_stream_time - activity_stream = Sessions::CacheIn.get( cache_key, { :ignore_expire => true } ) - client.log 'notify', "push activity_stream for user #{user.id}" - - # send update to browser - r = Sessions::CacheIn.get( cache_key + '_push', { :ignore_expire => true } ) - client.send({ - :event => 'activity_stream_rebuild', - :collection => 'activity_stream', - :data => r, - }) + # get whole collection + activity_stream = @user.activity_stream( 25 ) + if activity_stream && !activity_stream.first + return end + + if activity_stream && activity_stream.first && activity_stream.first['created_at'] == @last_change + return + end + + # update last changed + if activity_stream && activity_stream.first + @last_change = activity_stream.first['created_at'] + end + + @user.activity_stream( 25, true ) + end + + def client_key + "as::load::#{ self.class.to_s }::#{ @user.id }::#{ @client_id }" + end + + def push + + # check timeout + timeout = Sessions::CacheIn.get( self.client_key ) + return if timeout + + # set new timeout + Sessions::CacheIn.set( self.client_key, true, { :expires_in => 0.5.minutes } ) + + data = self.load + + return if !data||data.empty? + + if !@client + return { + :event => 'activity_stream_rebuild', + :collection => 'activity_stream', + :data => data, + } + end + + @client.log 'notify', "push activity_stream #{ data.first.class.to_s } for user #{ @user.id }" + @client.send({ + :event => 'activity_stream_rebuild', + :collection => 'activity_stream', + :data => data, + }) end end \ No newline at end of file diff --git a/lib/sessions/backend/collections.rb b/lib/sessions/backend/collections.rb index d135a2afa..95b49ee85 100644 --- a/lib/sessions/backend/collections.rb +++ b/lib/sessions/backend/collections.rb @@ -1,71 +1,47 @@ -module Sessions::Backend::Collections - @@last_change = {} - - def self.worker( user, worker ) - - worker.log 'notice', "---user - fetch push_collection data" - - # get available collections - cache_key = 'user_' + user.id.to_s + '_push_collections' - collections = Sessions::CacheIn.get( cache_key ) - if !collections - collections = {} - push_collection = SessionHelper::push_collections(user) - push_collection.each { | key, value | - collections[ key ] = true - } - Sessions::CacheIn.set( cache_key, collections, { :expires_in => 2.minutes } ) - end - - # check all collections to push - push_collection = {} - collections.each { | key, v | - cache_key = 'user_' + user.id.to_s + '_push_collections_' + key.to_s - if Sessions::CacheIn.expired(cache_key) - if push_collection.empty? - push_collection = SessionHelper::push_collections(user) - end - push_collection_cache = Sessions::CacheIn.get( cache_key, { :re_expire => true } ) - worker.log 'notice', "---user - fetch push_collection data " + cache_key -# if !push_collection[key] || !push_collection_cache || push_collection[key] != push_collection_cache || !push_collection[ key ].zip( push_collection_cache ).all? { |x, y| x.attributes == y.attributes } - if !push_collection[key] || !push_collection_cache || push_collection[key] != push_collection_cache || !push_collection[ key ].zip( push_collection_cache ).all? { |x, y| return false if !x; return false if !y; x.attributes == y.attributes } - - worker.log 'notify', 'fetch push_collection changed - ' + cache_key - Sessions::CacheIn.set( cache_key, push_collection[key], { :expires_in => 1.minutes } ) - end - end - } +class Sessions::Backend::Collections + def initialize( user, client, client_id ) + @user = user + @client = client + @client_id = client_id + @backends = self.backend end - def self.push( user, client ) - - cache_key = 'user_' + user.id.to_s + '_push_collections' - if !client.last_change['push_collections'] - client.last_change['push_collections'] = {} - end - - collections = Sessions::CacheIn.get( cache_key ) || {} - collections.each { | key, v | - collection_cache_key = 'user_' + user.id.to_s + '_push_collections_' + key.to_s - collection_time = Sessions::CacheIn.get_time( collection_cache_key, { :ignore_expire => true } ) - if collection_time && client.last_change['push_collections'][ key ] != collection_time - - client.last_change['push_collections'][ key ] = collection_time - push_collections = Sessions::CacheIn.get( collection_cache_key, { :ignore_expire => true } ) - - client.log 'notify', "push push_collections #{key} for user #{user.id}" - - # send update to browser - data = {} - data[key] = push_collections - client.send({ - :event => 'resetCollection', - :data => data, - }) + def push + results = [] + @backends.each {|backend| + #puts "B: #{backend.inspect}" + result = backend.push + #puts "R: #{result.inspect}" + if result + results.push result end } + results + end + + def backend + + # auto population collections + backends = [] + + # load collections to deliver from external files + dir = File.expand_path('../../../../', __FILE__) + files = Dir.glob( "#{dir}/lib/sessions/backend/collections/*.rb" ) + for file in files + file.gsub!("#{dir}/lib/", '') + file.gsub!(/\.rb$/, '') + next if file.classify == 'Sessions::Backend::Collections::Base' + #puts "LOAD #{file.classify}---" + #next if file == '' + backend = file.classify.constantize.new(@user, @client, @client_id) + if backend + backends.push backend + end + end + + backends end end \ No newline at end of file diff --git a/lib/sessions/backend/collections/base.rb b/lib/sessions/backend/collections/base.rb new file mode 100644 index 000000000..94c59712b --- /dev/null +++ b/lib/sessions/backend/collections/base.rb @@ -0,0 +1,137 @@ +class Sessions::Backend::Collections::Base + class << self; attr_accessor :model, :is_role, :is_not_role end + + def initialize( user, client = nil, client_id = nil ) + @user = user + @client = client + @client_id = client_id + @last_change = nil + end + + def collection_key + "collections::load::#{ self.class.to_s }::#{ @user.id }" + end + + def load +#puts "-LOAD--------#{self.collection_key}" + # check timeout + cache = Sessions::CacheIn.get( self.collection_key ) + return cache if @last_change && cache +#puts "---REAL FETCH #{@user.id}" + # update last changed + last = self.class.model.constantize.select('updated_at').order('updated_at DESC').first + if last + @last_change = last.updated_at + end + + # if no entry exists, remember last check + if !@last_change + @last_change = Time.now + end + + # get whole collection + all = self.class.model.constantize.all + + # set new timeout + Sessions::CacheIn.set( self.collection_key, all, { :expires_in => 10.minutes } ) + + all + end + + def changed? + # if no data has been delivered till now + return true if !@last_change + + # check if update has been done + last = self.class.model.constantize.select('updated_at').order('updated_at DESC').first + return false if !last + return false if last.updated_at == @last_change + + # delete collection cache + Sessions::CacheIn.delete( self.collection_key ) + + # collection has changed + true + end + + def client_key + "collections::load::#{ self.class.to_s }::#{ @user.id }::#{ @client_id }" + end + + def push + + # check role based access + if self.class.is_role + access = nil + self.class.is_role.each {|role| + if @user.is_role(role) + access = true + end + } + return if !access + end + if self.class.is_not_role + self.class.is_not_role.each {|role| + return if @user.is_role(role) + } + end + + # check timeout + timeout = Sessions::CacheIn.get( self.client_key ) + return if timeout + + # set new timeout + Sessions::CacheIn.set( self.client_key, true, { :expires_in => 10.seconds } ) + + return if !self.changed? + data = self.load + + return if !data||data.empty? + + # collect assets + assets = {} + data.each {|item| + assets = item.assets(assets) + } + if !@client + return { + :collection => { + data.first.class.to_app_model => data, + }, + :assets => assets, + } + end + @client.log 'notify', "push assets for push_collection #{ data.first.class.to_s } for user #{ @user.id }" + @client.send({ + :data => assets, + :event => [ 'loadAssets' ], + }) + + @client.log 'notify', "push push_collection #{ data.first.class.to_s } for user #{ @user.id }" + @client.send({ + :event => 'resetCollection', + :data => { + data.first.class.to_app_model => data, + }, + }) + end + + def self.model_set(model) + @model = model + end + + def self.is_role_set(role) + if !@is_role + @is_role = [] + end + @is_role.push role + end + + def self.is_not_role_set(role) + if !@is_not_role + @is_not_role = [] + end + @is_not_role.push role + end + +end \ No newline at end of file diff --git a/lib/sessions/backend/collections/email_address.rb b/lib/sessions/backend/collections/email_address.rb new file mode 100644 index 000000000..de090e244 --- /dev/null +++ b/lib/sessions/backend/collections/email_address.rb @@ -0,0 +1,4 @@ +class Sessions::Backend::Collections::EmailAddress < Sessions::Backend::Collections::Base + model_set 'EmailAddress' + is_not_role_set 'Customer' +end \ No newline at end of file diff --git a/lib/sessions/backend/collections/group.rb b/lib/sessions/backend/collections/group.rb new file mode 100644 index 000000000..c8ed8f92f --- /dev/null +++ b/lib/sessions/backend/collections/group.rb @@ -0,0 +1,3 @@ +class Sessions::Backend::Collections::Group < Sessions::Backend::Collections::Base + model_set 'Group' +end \ No newline at end of file diff --git a/lib/sessions/backend/collections/organization.rb b/lib/sessions/backend/collections/organization.rb new file mode 100644 index 000000000..f3d1dbd97 --- /dev/null +++ b/lib/sessions/backend/collections/organization.rb @@ -0,0 +1,67 @@ +class Sessions::Backend::Collections::Organization < Sessions::Backend::Collections::Base + model_set 'Organization' + + def load + + # check timeout + cache = Sessions::CacheIn.get( self.collection_key ) + return cache if @last_change && cache + + # update last changed + if !@user.is_role('Customer') + last = self.class.model.constantize.select('updated_at').order('updated_at DESC').first + if last + @last_change = last.updated_at + end + else + if @user.organization_id + last = Organization.where( :id => @user.organization_id ).first + @last_change = last.updated_at + end + end + + # if no entry exists, remember last check + if !@last_change + @last_change = Time.now + end + + # get whole collection + all = [] + if !@user.is_role('Customer') + all = Organization.all + else + if @user.organization_id + all = Organization.where( :id => @user.organization_id ) + end + end + + # set new timeout + Sessions::CacheIn.set( self.collection_key, all, { :expires_in => 10.minutes } ) + + all + end + + def changed? + + # if no data has been delivered till now + return true if !@last_change + + # check if update has been done + if !@user.is_role('Customer') + last = self.class.model.constantize.select('updated_at').order('updated_at DESC').first + else + if @user.organization_id + last = Organization.where( :id => @user.organization_id ).first + end + end + return false if !last + return false if last.updated_at == @last_change + + # delete collection cache + Sessions::CacheIn.delete( self.collection_key ) + + # collection has changed + true + end + +end \ No newline at end of file diff --git a/lib/sessions/backend/collections/role.rb b/lib/sessions/backend/collections/role.rb new file mode 100644 index 000000000..80b825f8c --- /dev/null +++ b/lib/sessions/backend/collections/role.rb @@ -0,0 +1,3 @@ +class Sessions::Backend::Collections::Role < Sessions::Backend::Collections::Base + model_set 'Role' +end \ No newline at end of file diff --git a/lib/sessions/backend/collections/signature.rb b/lib/sessions/backend/collections/signature.rb new file mode 100644 index 000000000..60bea9ea1 --- /dev/null +++ b/lib/sessions/backend/collections/signature.rb @@ -0,0 +1,4 @@ +class Sessions::Backend::Collections::Signature < Sessions::Backend::Collections::Base + model_set 'Signature' + is_not_role_set 'Customer' +end \ No newline at end of file diff --git a/lib/sessions/backend/collections/ticket_article_sender.rb b/lib/sessions/backend/collections/ticket_article_sender.rb new file mode 100644 index 000000000..4b409f54a --- /dev/null +++ b/lib/sessions/backend/collections/ticket_article_sender.rb @@ -0,0 +1,3 @@ +class Sessions::Backend::Collections::TicketArticleSender < Sessions::Backend::Collections::Base + model_set 'Ticket::Article::Sender' +end \ No newline at end of file diff --git a/lib/sessions/backend/collections/ticket_article_type.rb b/lib/sessions/backend/collections/ticket_article_type.rb new file mode 100644 index 000000000..e9b59d127 --- /dev/null +++ b/lib/sessions/backend/collections/ticket_article_type.rb @@ -0,0 +1,3 @@ +class Sessions::Backend::Collections::TicketArticleType < Sessions::Backend::Collections::Base + model_set 'Ticket::Article::Type' +end \ No newline at end of file diff --git a/lib/sessions/backend/collections/ticket_priority.rb b/lib/sessions/backend/collections/ticket_priority.rb new file mode 100644 index 000000000..110808da3 --- /dev/null +++ b/lib/sessions/backend/collections/ticket_priority.rb @@ -0,0 +1,3 @@ +class Sessions::Backend::Collections::TicketPriority < Sessions::Backend::Collections::Base + model_set 'Ticket::Priority' +end \ No newline at end of file diff --git a/lib/sessions/backend/collections/ticket_state.rb b/lib/sessions/backend/collections/ticket_state.rb new file mode 100644 index 000000000..7426be23f --- /dev/null +++ b/lib/sessions/backend/collections/ticket_state.rb @@ -0,0 +1,3 @@ +class Sessions::Backend::Collections::TicketState < Sessions::Backend::Collections::Base + model_set 'Ticket::State' +end \ No newline at end of file diff --git a/lib/sessions/backend/recent_viewed.rb b/lib/sessions/backend/recent_viewed.rb index 73f9987a3..f04cb4c44 100644 --- a/lib/sessions/backend/recent_viewed.rb +++ b/lib/sessions/backend/recent_viewed.rb @@ -1,37 +1,59 @@ -module Sessions::Backend::RecentViewed - - def self.worker( user, worker ) - cache_key = 'user_' + user.id.to_s + '_recent_viewed' - if Sessions::CacheIn.expired(cache_key) - recent_viewed = RecentView.list_fulldata( user, 10 ) - recent_viewed_cache = Sessions::CacheIn.get( cache_key, { :re_expire => true } ) - worker.log 'notice', 'fetch recent_viewed - ' + cache_key - if recent_viewed != recent_viewed_cache - worker.log 'notify', 'fetch recent_viewed changed - ' + cache_key - - recent_viewed_full = RecentView.list_fulldata( user, 10 ) - Sessions::CacheIn.set( cache_key, recent_viewed, { :expires_in => 5.seconds } ) - Sessions::CacheIn.set( cache_key + '_push', recent_viewed_full ) - end - end +class Sessions::Backend::RecentViewed + def initialize( user, client = nil, client_id = nil ) + @user = user + @client = client + @client_id = client_id + @last_change = nil end - def self.push( user, client ) - cache_key = 'user_' + user.id.to_s + '_recent_viewed' - recent_viewed_time = Sessions::CacheIn.get_time( cache_key, { :ignore_expire => true } ) - if recent_viewed_time && client.last_change['recent_viewed'] != recent_viewed_time - client.last_change['recent_viewed'] = recent_viewed_time - recent_viewed = Sessions::CacheIn.get( cache_key, { :ignore_expire => true } ) - client.log 'notify', "push recent_viewed for user #{user.id}" + def load - # send update to browser - r = Sessions::CacheIn.get( cache_key + '_push', { :ignore_expire => true } ) - client.send({ + # get whole collection + recent_viewed = RecentView.list( @user, 10 ) + + # no data exists + return if !recent_viewed + return if recent_viewed.empty? + + # no change exists + return if @last_change == recent_viewed + + # remember last state + @last_change = recent_viewed + + RecentView.list_fulldata( @user, 10 ) + end + + def client_key + "as::load::#{ self.class.to_s }::#{ @user.id }::#{ @client_id }" + end + + def push + + # check timeout + timeout = Sessions::CacheIn.get( self.client_key ) + return if timeout + + # set new timeout + Sessions::CacheIn.set( self.client_key, true, { :expires_in => 15.seconds } ) + + data = self.load + + return if !data||data.empty? + + if !@client + return { :event => 'update_recent_viewed', - :data => r, - }) + :data => data, + } end + + @client.log 'notify', "push recent_viewed for user #{ @user.id }" + @client.send({ + :event => 'update_recent_viewed', + :data => data, + }) end -end +end \ No newline at end of file diff --git a/lib/sessions/backend/rss.rb b/lib/sessions/backend/rss.rb index d2d44744d..a24a64f24 100644 --- a/lib/sessions/backend/rss.rb +++ b/lib/sessions/backend/rss.rb @@ -1,41 +1,63 @@ require 'rss' -module Sessions::Backend::Rss - def self.worker( user, worker ) - cache_key = 'user_' + user.id.to_s + '_rss' - if Sessions::CacheIn.expired(cache_key) - url = 'http://www.heise.de/newsticker/heise-atom.xml' - rss_items = Rss.fetch( url, 8 ) - rss_items_cache = Sessions::CacheIn.get( cache_key, { :re_expire => true } ) - worker.log 'notice', 'fetch rss - ' + cache_key - if rss_items != rss_items_cache - worker.log 'notify', 'fetch rss changed - ' + cache_key - Sessions::CacheIn.set( cache_key, rss_items, { :expires_in => 2.minutes } ) - Sessions::CacheIn.set( cache_key + '_push', { - head: 'Heise ATOM', - items: rss_items, - }) - end - end +class Sessions::Backend::Rss + + def initialize( user, client, client_id ) + @user = user + @client = client + @client_id = client_id end - def self.push( user, client ) - cache_key = 'user_' + user.id.to_s + '_rss' + def collection_key + "rss::load::#{ self.class.to_s }::#{ @user.id }" + end - rss_items_time = Sessions::CacheIn.get_time( cache_key, { :ignore_expire => true } ) - if rss_items_time && client.last_change['rss'] != rss_items_time - client.last_change['rss'] = rss_items_time - rss_items = Sessions::CacheIn.get( cache_key, { :ignore_expire => true } ) - client.log 'notify', "push rss for user #{user.id}" + def load - # send update to browser - r = Sessions::CacheIn.get( cache_key + '_push', { :ignore_expire => true } ) - client.send({ + # check timeout + cache = Sessions::CacheIn.get( self.collection_key ) + return cache if cache + + url = 'http://www.heise.de/newsticker/heise-atom.xml' + rss_items = Rss.fetch( url, 8 ) + + # set new timeout + Sessions::CacheIn.set( self.collection_key, rss_items, { :expires_in => 1.hours } ) + + rss_items + end + + def client_key + "rss::load::#{ self.class.to_s }::#{ @user.id }::#{ @client_id }" + end + + def push + + # check timeout + timeout = Sessions::CacheIn.get( self.client_key ) + return if timeout + + # set new timeout + Sessions::CacheIn.set( self.client_key, true, { :expires_in => 5.minutes } ) + + data = self.load + + return if !data||data.empty? + + if !@client + return { :event => 'rss_rebuild', :collection => 'dashboard_rss', - :data => r, - }) + :data => data, + } end + + @client.log 'notify', "push rss for user #{@user.id}" + @client.send({ + :event => 'rss_rebuild', + :collection => 'dashboard_rss', + :data => data, + }) end end \ No newline at end of file diff --git a/lib/sessions/backend/ticket_create.rb b/lib/sessions/backend/ticket_create.rb index 0714bed67..fb080b5de 100644 --- a/lib/sessions/backend/ticket_create.rb +++ b/lib/sessions/backend/ticket_create.rb @@ -1,47 +1,70 @@ -module Sessions::Backend::TicketCreate - - def self.worker( user, worker ) - cache_key = 'user_' + user.id.to_s + '_ticket_create_attributes' - - if Sessions::CacheIn.expired(cache_key) - ticket_create_attributes = Ticket::ScreenOptions.attributes_to_change( - :current_user_id => user.id, - ) - ticket_create_attributes_cache = Sessions::CacheIn.get( cache_key, { :re_expire => true } ) - worker.log 'notice', 'fetch ticket_create_attributes - ' + cache_key - if ticket_create_attributes != ticket_create_attributes_cache - worker.log 'notify', 'fetch ticket_create_attributes changed - ' + cache_key - Sessions::CacheIn.set( cache_key, ticket_create_attributes, { :expires_in => 2.minutes } ) - end - end - +class Sessions::Backend::TicketCreate + def initialize( user, client = nil, client_id = nil ) + @user = user + @client = client + @client_id = client_id + @last_change = nil end - def self.push( user, client ) - cache_key = 'user_' + user.id.to_s + '_ticket_create_attributes' + def load - ticket_create_attributes_time = Sessions::CacheIn.get_time( cache_key, { :ignore_expire => true } ) - if ticket_create_attributes_time && client.last_change['ticket_create_attributes'] != ticket_create_attributes_time - client.last_change['ticket_create_attributes'] = ticket_create_attributes_time - create_attributes = Sessions::CacheIn.get( cache_key, { :ignore_expire => true } ) - users = {} - create_attributes[:owner_id].each {|user_id| - if !users[user_id] - users[user_id] = User.user_data_full(user_id) - end - } - data = { - :users => users, - :edit_form => create_attributes, - } - client.log 'notify', "push ticket_create_attributes for user #{user.id}" + # get whole collection + ticket_create_attributes = Ticket::ScreenOptions.attributes_to_change( + :current_user_id => @user.id, + ) - # send update to browser - client.send({ + # no data exists + return if !ticket_create_attributes + + # no change exists + return if @last_change == ticket_create_attributes + + # remember last state + @last_change = ticket_create_attributes + + ticket_create_attributes + end + + def client_key + "as::load::#{ self.class.to_s }::#{ @user.id }::#{ @client_id }" + end + + def push + + # check timeout + timeout = Sessions::CacheIn.get( self.client_key ) + return if timeout + + # set new timeout + Sessions::CacheIn.set( self.client_key, true, { :expires_in => 25.seconds } ) + + create_attributes = self.load + + return if !create_attributes + + users = {} + create_attributes[:owner_id].each {|user_id| + if !users[user_id] + users[user_id] = User.user_data_full(user_id) + end + } + data = { + :users => users, + :edit_form => create_attributes, + } + + if !@client + return { :collection => 'ticket_create_attributes', - :data => data, - }) + :data => create_attributes, + } end + + @client.log 'notify', "push ticket_create for user #{ @user.id }" + @client.send({ + :collection => 'ticket_create_attributes', + :data => create_attributes, + }) end end \ No newline at end of file diff --git a/lib/sessions/backend/ticket_overview_index.rb b/lib/sessions/backend/ticket_overview_index.rb index 6e8fef17f..67e89c8ad 100644 --- a/lib/sessions/backend/ticket_overview_index.rb +++ b/lib/sessions/backend/ticket_overview_index.rb @@ -1,38 +1,59 @@ -module Sessions::Backend::TicketOverviewIndex - - def self.worker( user, worker ) - cache_key = 'user_' + user.id.to_s + '_overview' - if Sessions::CacheIn.expired(cache_key) - overview = Ticket::Overviews.list( - :current_user => user, - ) - overview_cache = Sessions::CacheIn.get( cache_key, { :re_expire => true } ) - worker.log 'notice', 'fetch overview - ' + cache_key - if overview != overview_cache - worker.log 'notify', 'fetch overview changed - ' + cache_key -# puts overview.inspect -# puts '------' -# puts overview_cache.inspect - Sessions::CacheIn.set( cache_key, overview, { :expires_in => 4.seconds } ) - end - end +class Sessions::Backend::TicketOverviewIndex + def initialize( user, client = nil, client_id = nil ) + @user = user + @client = client + @client_id = client_id + @last_change = nil end - def self.push( user, client ) - cache_key = 'user_' + user.id.to_s + '_overview' - overview_time = Sessions::CacheIn.get_time( cache_key, { :ignore_expire => true } ) - if overview_time && client.last_change['overview'] != overview_time - client.last_change['overview'] = overview_time - overview = Sessions::CacheIn.get( cache_key, { :ignore_expire => true } ) + def load - client.log 'notify', "push overview for user #{user.id}" + # get whole collection + overview = Ticket::Overviews.list( + :current_user => @user, + ) - # send update to browser - client.send({ + # no data exists + return if !overview + + # no change exists + return if @last_change == overview + + # remember last state + @last_change = overview + + overview + end + + def client_key + "as::load::#{ self.class.to_s }::#{ @user.id }::#{ @client_id }" + end + + def push + + # check timeout + timeout = Sessions::CacheIn.get( self.client_key ) + return if timeout + + # set new timeout + Sessions::CacheIn.set( self.client_key, true, { :expires_in => 5.seconds } ) + + data = self.load + + return if !data + + if !@client + return { :event => 'navupdate_ticket_overview', - :data => overview, - }) + :data => data, + } end + + @client.log 'notify', "push overview_index for user #{ @user.id }" + @client.send({ + :event => 'navupdate_ticket_overview', + :data => data, + }) end end \ No newline at end of file diff --git a/lib/sessions/backend/ticket_overview_list.rb b/lib/sessions/backend/ticket_overview_list.rb index 67680699f..3432fced9 100644 --- a/lib/sessions/backend/ticket_overview_list.rb +++ b/lib/sessions/backend/ticket_overview_list.rb @@ -1,93 +1,113 @@ -module Sessions::Backend::TicketOverviewList - - def self.worker( user, worker ) - overviews = Ticket::Overviews.all( - :current_user => user, - ) - overviews.each { |overview| - cache_key = 'user_' + user.id.to_s + '_overview_data_' + overview.link - if Sessions::CacheIn.expired(cache_key) - overview_data = Ticket::Overviews.list( - :view => overview.link, - :current_user => user, - :array => true, - ) - overview_data_cache = Sessions::CacheIn.get( cache_key, { :re_expire => true } ) - worker.log 'notice', 'fetch overview_data - ' + cache_key - if overview_data != overview_data_cache - worker.log 'notify', 'fetch overview_data changed - ' + cache_key - Sessions::CacheIn.set( cache_key, overview_data, { :expires_in => 5.seconds } ) - end - end - } +class Sessions::Backend::TicketOverviewList + def initialize( user, client = nil, client_id = nil ) + @user = user + @client = client + @client_id = client_id + @last_change = nil end - def self.push( user, client ) + def load + + # get whole collection overviews = Ticket::Overviews.all( - :current_user => user, + :current_user => @user, ) + + # no data exists + return if !overviews + + # no change exists + return if @last_change == overviews + + # remember last state + @last_change = overviews + + overviews + end + + def client_key + "as::load::#{ self.class.to_s }::#{ @user.id }::#{ @client_id }" + end + + def push + + # check timeout + timeout = Sessions::CacheIn.get( self.client_key ) + return if timeout + + # set new timeout + Sessions::CacheIn.set( self.client_key, true, { :expires_in => 5.seconds } ) + + overviews = self.load + + return if !overviews + + # push overviews overviews.each { |overview| - cache_key = 'user_' + user.id.to_s + '_overview_data_' + overview.link - if !client.last_change['overview_list'] - client.last_change['overview_list'] = {} + overview_data = Ticket::Overviews.list( + :view => overview.link, + :current_user => @user, + :array => true, + ) + + assets = {} + overview_data[:ticket_ids].each {|ticket_id| + ticket = Ticket.find( ticket_id ) + assets = ticket.assets(assets) + } + + # get groups + group_ids = [] + Group.where( :active => true ).each { |group| + group_ids.push group.id + } + agents = {} + Ticket::ScreenOptions.agents.each { |user| + agents[ user.id ] = 1 + } + users = {} + groups_users = {} + groups_users[''] = [] + group_ids.each {|group_id| + groups_users[ group_id ] = [] + Group.find(group_id).users.each {|user| + next if !agents[ user.id ] + groups_users[ group_id ].push user.id + if !users[user.id] + users[user.id] = User.find(user.id) + assets = users[user.id].assets(assets) + end + } + } + + if !@client + return { + :event => 'navupdate_ticket_overview', + :data => overview, + } end - overview_data_time = Sessions::CacheIn.get_time( cache_key, { :ignore_expire => true } ) - if overview_data_time && client.last_change['overview_list'][overview.link] != overview_data_time - client.last_change['overview_list'][overview.link] = overview_data_time - overview_data = Sessions::CacheIn.get( cache_key, { :ignore_expire => true } ) - client.log 'notify', "push overview_data #{overview.link} for user #{user.id}" - users = {} - tickets = {} - overview_data[:ticket_ids].each {|ticket_id| - client.ticket( ticket_id, tickets, users ) - } + @client.log 'notify', "push overview_list for user #{ @user.id }" - # get groups - group_ids = [] - Group.where( :active => true ).each { |group| - group_ids.push group.id - } - agents = {} - Ticket::ScreenOptions.agents.each { |user| - agents[ user.id ] = 1 - } - groups_users = {} - groups_users[''] = [] - group_ids.each {|group_id| - groups_users[ group_id ] = [] - Group.find(group_id).users.each {|user| - next if !agents[ user.id ] - groups_users[ group_id ].push user.id - if !users[user.id] - users[user.id] = User.user_data_full(user.id) - end - } - } - - # send update to browser - client.send({ - :data => { - User.to_app_model => users, - Ticket.to_app_model => tickets, + # send update to browser + @client.send({ + :data => assets, + :event => [ 'loadAssets' ] + }) + @client.send({ + :data => { + :overview => overview_data[:overview], + :ticket_ids => overview_data[:ticket_ids], + :tickets_count => overview_data[:tickets_count], + :bulk => { + :group_id__owner_id => groups_users, + :owner_id => [], }, - :event => [ 'loadAssets' ] - }) - client.send({ - :data => { - :overview => overview_data[:overview], - :ticket_ids => overview_data[:ticket_ids], - :tickets_count => overview_data[:tickets_count], - :bulk => { - :group_id__owner_id => groups_users, - :owner_id => [], - }, - }, - :event => [ 'ticket_overview_rebuild' ], - :collection => 'ticket_overview_' + overview.link.to_s, - }) - end + }, + :event => [ 'ticket_overview_rebuild' ], + :collection => 'ticket_overview_' + overview.link.to_s, + }) } end diff --git a/lib/sessions/cache_in.rb b/lib/sessions/cache_in.rb index 70a65f926..e0b6dcc61 100644 --- a/lib/sessions/cache_in.rb +++ b/lib/sessions/cache_in.rb @@ -4,6 +4,11 @@ module Sessions::CacheIn @@expires_in = {} @@expires_in_ttl = {} + def self.delete( key ) + @@data.delete( key ) + @@data_time.delete( key ) + end + def self.set( key, value, params = {} ) # puts 'CacheIn.set:' + key + '-' + value.inspect if params[:expires_in] diff --git a/lib/sessions/client.rb b/lib/sessions/client.rb index 7f303ab32..985defea0 100644 --- a/lib/sessions/client.rb +++ b/lib/sessions/client.rb @@ -1,13 +1,7 @@ class Sessions::Client - attr_accessor :last_change - def initialize( client_id ) @client_id = client_id - @cache_key = '' - @data = {} - @pushed = {} - @last_change = {} self.log 'notify', "---client start ws connection---" self.fetch self.log 'notify', "---client exiting ws connection---" @@ -15,6 +9,18 @@ class Sessions::Client def fetch + backends = [ + 'Sessions::Backend::TicketOverviewIndex', + 'Sessions::Backend::TicketOverviewList', + 'Sessions::Backend::Collections', + 'Sessions::Backend::Rss', + 'Sessions::Backend::ActivityStream', + 'Sessions::Backend::RecentViewed', + 'Sessions::Backend::TicketCreate', + ] + + backend_pool = [] + user_id_last_run = nil loop_count = 0 while true @@ -26,83 +32,22 @@ class Sessions::Client user = User.lookup( :id => session_data[:user][:id] ) return if !user - # set cache key - @cache_key = 'user_' + user.id.to_s + # init new backends + if user_id_last_run != user.id + backend_pool = [] + backends.each {|backend| + item = backend.constantize.new(user, self, @client_id) + backend_pool.push item + } + end loop_count += 1 self.log 'notice', "---client - looking for data of user #{user.id}" - # remember last run - Sessions::CacheIn.set( 'last_run_' + user.id.to_s , true, { :expires_in => 20.seconds } ) - - # verify already pushed data, send update if needed - if !Sessions::CacheIn.get( 'pushed_users' + @client_id.to_s ) - Sessions::CacheIn.set( 'pushed_users' + @client_id.to_s , true, { :expires_in => 60.seconds } ) - if @pushed[:users] - users = {} - @pushed[:users].each {|user_id, user_o| - self.user( user_id, users ) - } - if !users.empty? - users.each {|user_id, user_data| - self.log 'notify', "push update of already pushed user id #{user_id}" - } - # send update to browser - self.send({ - :data => { - User.to_app_model => users, - }, - :event => [ 'loadAssets' ], - }); - end - end - end - - # verify already pushed data, send update if needed - if !Sessions::CacheIn.get( 'pushed_tickets' + @client_id.to_s ) - Sessions::CacheIn.set( 'pushed_tickets' + @client_id.to_s , true, { :expires_in => 60.seconds } ) - if @pushed[:tickets] - tickets = {} - users = {} - @pushed[:tickets].each {|ticket_id, ticket_data| - self.ticket( ticket_id, tickets, users ) - } - if !tickets.empty? - tickets.each {|id, ticket| - self.log 'notify', "push update of already pushed ticket id #{id}" - } - # send update to browser - self.send({ - :data => { - Ticket.to_app_model => tickets, - User.to_app_model => users, - }, - :event => [ 'loadAssets' ], - }); - end - end - end - - # overview - Sessions::Backend::TicketOverviewIndex.push( user, self ) - - # overview_data - Sessions::Backend::TicketOverviewList.push( user, self ) - - # ticket_create_attributes - Sessions::Backend::TicketCreate.push( user, self ) - - # recent viewed - Sessions::Backend::RecentViewed.push( user, self ) - - # activity stream - Sessions::Backend::ActivityStream.push( user, self ) - - # rss - Sessions::Backend::Rss.push( user, self ) - - # push_collections - Sessions::Backend::Collections.push( user, self ) + # push messages from backends + backend_pool.each {|pool| + pool.push + } self.log 'notice', "---/client-" @@ -115,44 +60,6 @@ class Sessions::Client end end - # add ticket if needed - def ticket( ticket_id, tickets, users ) - if !@pushed[:tickets] - @pushed[:tickets] = {} - end - ticket = Ticket.lookup( :id => ticket_id ) - if @pushed[:tickets][ticket_id] != ticket['updated_at'] - @pushed[:tickets][ticket_id] = ticket['updated_at'] - tickets[ticket_id] = ticket - end - - # add users if needed - self.user( ticket['owner_id'], users ) - self.user( ticket['customer_id'], users ) - self.user( ticket['created_by_id'], users ) - if ticket['updated_by_id'] - self.user( ticket['updated_by_id'], users ) - end - end - - # add user if needed - def user( user_id, users ) - if !@pushed[:users] - @pushed[:users] = {} - end - - # get user - user = User.user_data_full( user_id ) - - # user is already on client and not changed - return if @pushed[:users][ user_id ] == user['updated_at'] - @pushed[:users][user_id] = user['updated_at'] - - # user not on client or different - self.log 'notice', 'push user ... ' + user['login'] - users[ user_id ] = user - end - # send update to browser def send( data ) Sessions.send( @client_id, data ) @@ -162,4 +69,4 @@ class Sessions::Client return if level == 'notice' puts "#{Time.now}:client(#{ @client_id }) #{ data }" end -end +end \ No newline at end of file diff --git a/lib/sessions/worker.rb b/lib/sessions/worker.rb deleted file mode 100644 index a8cb81042..000000000 --- a/lib/sessions/worker.rb +++ /dev/null @@ -1,56 +0,0 @@ -class Sessions::Worker - def initialize( user_id ) - @user_id = user_id - - self.log 'notify', "---user started user state" - - Sessions::CacheIn.set( 'last_run_' + user_id.to_s , true, { :expires_in => 20.seconds } ) - - self.fetch( user_id ) - end - - def fetch(user_id) - - while true - user = User.lookup( :id => user_id ) - return if !user - - # check if user is still with min one open connection - if !Sessions::CacheIn.get( 'last_run_' + user.id.to_s ) - self.log 'notify', "---user - closeing thread - no open user connection" - return - end - - self.log 'notice', "---user - fetch user data" - - # overview - Sessions::Backend::TicketOverviewIndex.worker( user, self ) - - # overview lists - Sessions::Backend::TicketOverviewList.worker( user, self ) - - # create_attributes - Sessions::Backend::TicketCreate.worker( user, self ) - - # recent viewed - Sessions::Backend::RecentViewed.worker( user, self ) - - # activity steam - Sessions::Backend::ActivityStream.worker( user, self ) - - # rss - Sessions::Backend::Rss.worker( user, self ) - - # auto population of default collections - Sessions::Backend::Collections.worker( user, self ) - - self.log 'notice', "---/user-" - sleep 1 - end - end - - def log( level, data ) - return if level == 'notice' - puts "#{Time.now}:user_id(#{ @user_id }) #{ data }" - end -end \ No newline at end of file diff --git a/test/unit/session_basic_test.rb b/test/unit/session_basic_test.rb new file mode 100644 index 000000000..af6cd0360 --- /dev/null +++ b/test/unit/session_basic_test.rb @@ -0,0 +1,342 @@ +# encoding: utf-8 +require 'test_helper' + +class SessionBasicTest < ActiveSupport::TestCase + test 'a cache' do + Sessions::CacheIn.set( 'last_run_test' , true, { :expires_in => 2.seconds } ) + result = Sessions::CacheIn.get( 'last_run_test' ) + assert_equal( true, result, "check 1" ) + + # should not be expired + result = Sessions::CacheIn.expired( 'last_run_test' ) + assert_equal( false, result, "check 1 - expired" ) + + # should be expired + sleep 3 + result = Sessions::CacheIn.expired( 'last_run_test' ) + assert_equal( true, result, "check 1 - expired" ) + + # renew expire + result = Sessions::CacheIn.get( 'last_run_test', :re_expire => true ) + assert_equal( true, result, "check 1 - re_expire" ) + + # should not be expired + result = Sessions::CacheIn.expired( 'last_run_test' ) + assert_equal( false, result, "check 1 - expired" ) + + # ignore expired + sleep 3 + result = Sessions::CacheIn.get( 'last_run_test', :ignore_expire => true ) + assert_equal( true, result, "check 1 - ignore_expire" ) + + # should be expired + result = Sessions::CacheIn.expired( 'last_run_test' ) + assert_equal( true, result, "check 2" ) + + result = Sessions::CacheIn.get( 'last_run_test' ) + assert_equal( nil, result, "check 2" ) + + # check delete cache + Sessions::CacheIn.set( 'last_run_delete' , true, { :expires_in => 5.seconds } ) + result = Sessions::CacheIn.get( 'last_run_delete' ) + assert_equal( true, result, "check 1" ) + Sessions::CacheIn.delete( 'last_run_delete' ) + result = Sessions::CacheIn.get( 'last_run_delete' ) + assert_equal( nil, nil, "check delete" ) + end + + test 'b collections group' do + require 'sessions/backend/collections/group.rb' + user = User.lookup(:id => 1) + collection_client1 = Sessions::Backend::Collections::Group.new(user, false, '123-1') + collection_client2 = Sessions::Backend::Collections::Group.new(user, false, '234-2') + + # get whole collections + result1 = collection_client1.push + assert( !result1.empty?, "check collections" ) + sleep 1 + result2 = collection_client2.push + assert( !result2.empty?, "check collections" ) + assert_equal( result1, result2, "check collections" ) + + # next check should be empty + result1 = collection_client1.push + assert( !result1, "check collections - recall" ) + sleep 1 + result2 = collection_client2.push + assert( !result2, "check collections - recall" ) + + # change collection + group = Group.first + group.touch + sleep 16 + + # get whole collections + result1 = collection_client1.push + assert( !result1.empty?, "check collections - after touch" ) + sleep 1 + result2 = collection_client2.push + assert( !result2.empty?, "check collections - after touch" ) + assert_equal( result1, result2, "check collections" ) + + # check again after touch + result1 = collection_client1.push + assert( !result1, "check collections - after touch - recall" ) + sleep 1 + result2 = collection_client2.push + assert( !result2, "check collections - after touch - recall" ) + assert_equal( result1, result2, "check collections" ) + + # change collection + group = Group.create( :name => 'SomeGroup::' + rand(999999).to_s, :active => true, :created_by_id => 1, :updated_by_id => 1 ) + sleep 12 + + # get whole collections + result1 = collection_client1.push + assert( !result1.empty?, "check collections - after create" ) + sleep 1 + result2 = collection_client2.push + assert( !result2.empty?, "check collections - after create" ) + assert_equal( result1, result2, "check collections" ) + + # check again after create + sleep 14 + result1 = collection_client1.push + assert( !result1, "check collections - after create - recall" ) + sleep 1 + result2 = collection_client2.push + assert( !result2, "check collections - after create - recall" ) + assert_equal( result1, result2, "check collections" ) + + # change collection + group.destroy + sleep 14 + + # get whole collections + result1 = collection_client1.push + assert( !result1.empty?, "check collections - after destroy" ) + sleep 1 + result2 = collection_client2.push + assert( !result2.empty?, "check collections - after destroy" ) + assert_equal( result1, result2, "check collections" ) + + # check again after destroy + sleep 12 + result1 = collection_client1.push + assert( !result1, "check collections - after destroy - recall" ) + sleep 1 + result2 = collection_client2.push + assert( !result2, "check collections - after destroy - recall" ) + assert_equal( result1, result2, "check collections" ) + end + + user = User.lookup(:id => 1) + roles = Role.where( :name => [ 'Agent', 'Admin'] ) + user.roles = roles + user.save + + test 'b collections organization' do + require 'sessions/backend/collections/organization.rb' + Organization.destroy_all + user = User.lookup(:id => 1) + + collection_client1 = Sessions::Backend::Collections::Organization.new(user, false, '123-1') + collection_client2 = Sessions::Backend::Collections::Organization.new(user, false, '234-2') + + # get whole collections - should be nil, no org exists! + result1 = collection_client1.push + assert( !result1, "check collections" ) + sleep 1 + result2 = collection_client2.push + assert( !result2, "check collections" ) + assert_equal( result1, result2, "check collections" ) + + # next check - should still be nil, no org exists! + result1 = collection_client1.push + assert( !result1, "check collections - recall" ) + sleep 1 + result2 = collection_client2.push + assert( !result2, "check collections - recall" ) + + # change collection + org = Organization.create( :name => 'SomeOrg::' + rand(999999).to_s, :active => true, :created_by_id => 1, :updated_by_id => 1 ) + sleep 16 + + # get whole collections + result1 = collection_client1.push + assert( !result1.empty?, "check collections - after create" ) + sleep 1 + result2 = collection_client2.push + assert( !result2.empty?, "check collections - after create" ) + assert_equal( result1, result2, "check collections" ) + + sleep 16 + + # next check should be empty + result1 = collection_client1.push + assert( !result1, "check collections - after create recall" ) + result2 = collection_client2.push + assert( !result2, "check collections - after create recall" ) + + organization = Organization.first + organization.touch + sleep 16 + + # get whole collections + result1 = collection_client1.push + assert( !result1.empty?, "check collections - after touch" ) + result2 = collection_client2.push + assert( !result1.empty?, "check collections - after touch" ) + assert_equal( result1, result2, "check collections" ) + + end + + test 'b rss' do + user = User.lookup(:id => 1) + collection_client1 = Sessions::Backend::Rss.new(user, false, '123-1') + + # get whole collections + result1 = collection_client1.push + #puts "RSS1: #{result1.inspect}" + assert( !result1.empty?, "check rss" ) + sleep 1 + + # next check should be empty + result1 = collection_client1.push + #puts "R1: #{result1.inspect}" + assert( !result1, "check rss - recall" ) + end + + test 'b activity stream' do + + # create users + roles = Role.where( :name => [ 'Agent', 'Admin'] ) + groups = Group.all + + UserInfo.current_user_id = 1 + agent1 = User.create_or_update( + :login => 'activity-stream-agent-1', + :firstname => 'Session', + :lastname => 'activity stream ' + rand(99999).to_s, + :email => 'activity-stream-agent1@example.com', + :password => 'agentpw', + :active => true, + :roles => roles, + :groups => groups, + ) + agent1.roles = roles + agent1.save + + as_client1 = Sessions::Backend::ActivityStream.new(agent1, false, '123-1') + + # get as stream + result1 = as_client1.push + assert( result1, "check as" ) + sleep 1 + + # next check should be empty + result1 = as_client1.push + assert( !result1, "check as - recall" ) + + # next check should be empty + sleep 60 + result1 = as_client1.push + assert( !result1, "check as - recall 2" ) + + agent1.update_attribute( :email, 'activity-stream-agent11@example.com' ) + ticket = Ticket.create(:title => '12323', :updated_by_id => 1, :created_by_id => 1, :group_id => 1, :priority_id => 1, :state_id => 1, :customer_id => 1) + + sleep 32 + + # get as stream + result1 = as_client1.push + assert( result1, "check as - recall 3" ) + end + + test 'b recent_viewed' do + + user = User.lookup(:id => 1) + ticket = Ticket.find(1) + RecentView.log( ticket, user ) + recent_viewed_client1 = Sessions::Backend::RecentViewed.new(user, false, '123-1') + + # get as stream + result1 = recent_viewed_client1.push + assert( result1, "check recent_viewed" ) + sleep 1 + + # next check should be empty + result1 = recent_viewed_client1.push + assert( !result1, "check recent_viewed - recall" ) + + # next check should be empty + sleep 20 + result1 = recent_viewed_client1.push + assert( !result1, "check recent_viewed - recall 2" ) + + RecentView.log( ticket, user ) + + sleep 20 + + # get as stream + result1 = recent_viewed_client1.push + assert( result1, "check recent_viewed - recall 3" ) + end + + test 'b ticket_create' do + + user = User.lookup(:id => 1) + ticket_create_client1 = Sessions::Backend::TicketCreate.new(user, false, '123-1') + + # get as stream + result1 = ticket_create_client1.push + assert( result1, "check ticket_create" ) + sleep 1 + + # next check should be empty + result1 = ticket_create_client1.push + assert( !result1, "check ticket_create - recall" ) + + # next check should be empty + sleep 10 + result1 = ticket_create_client1.push + assert( !result1, "check ticket_create - recall 2" ) + + Group.create( :name => 'SomeTicketCreateGroup::' + rand(999999).to_s, :active => true, :created_by_id => 1, :updated_by_id => 1 ) + + sleep 26 + + # get as stream + result1 = ticket_create_client1.push + assert( result1, "check ticket_create - recall 3" ) + end + + test 'b ticket_overview_index' do + + user = User.lookup(:id => 1) + ticket_overview_index_client1 = Sessions::Backend::TicketOverviewIndex.new(user, false, '123-1') + + # get as stream + result1 = ticket_overview_index_client1.push + assert( result1, "check ticket_overview_index" ) + sleep 1 + + # next check should be empty + result1 = ticket_overview_index_client1.push + assert( !result1, "check ticket_overview_index - recall" ) + + # next check should be empty + sleep 10 + result1 = ticket_overview_index_client1.push + assert( !result1, "check ticket_overview_index - recall 2" ) + + ticket = Ticket.create( :title => '12323', :updated_by_id => 1, :created_by_id => 1, :group_id => 1, :priority_id => 1, :state_id => 1, :customer_id => 1) + + sleep 10 + + # get as stream + result1 = ticket_overview_index_client1.push + assert( result1, "check ticket_overview_index - recall 3" ) + end + +end \ No newline at end of file diff --git a/test/unit/session_collections_test.rb b/test/unit/session_collections_test.rb new file mode 100644 index 000000000..a5981c14c --- /dev/null +++ b/test/unit/session_collections_test.rb @@ -0,0 +1,147 @@ +# encoding: utf-8 +require 'test_helper' + +class SessionCollectionsTest < ActiveSupport::TestCase + + test 'c collections' do + + UserInfo.current_user_id = 1 + + # create users + roles = Role.where( :name => [ 'Agent', 'Admin'] ) + groups = Group.all + + agent1 = User.create_or_update( + :login => 'session-collections-agent-1', + :firstname => 'Session', + :lastname => 'collections 1', + :email => 'session-collections-agent-1@example.com', + :password => 'agentpw', + :active => true, + :roles => roles, + :groups => groups, + ) + agent1.roles = roles + agent1.save + + roles = Role.where( :name => [ 'Agent' ] ) + groups = Group.all + + agent2 = User.create_or_update( + :login => 'session-collections-agent-2', + :firstname => 'Session', + :lastname => 'collections 2', + :email => 'session-collections-agent-2@example.com', + :password => 'agentpw', + :active => true, + :roles => roles, + :groups => groups, + ) + agent2.roles = roles + agent2.save + + roles = Role.where( :name => [ 'Customer'] ) + customer1 = User.create_or_update( + :login => 'session-collections-customer-1', + :firstname => 'Session', + :lastname => 'collections 2', + :email => 'session-collections-customer-1@example.com', + :password => 'customerpw', + :active => true, + :roles => roles, + ) + customer1.roles = roles + customer1.save + + collection_client1 = Sessions::Backend::Collections.new(agent1, nil, 'aaa-1') + collection_client2 = Sessions::Backend::Collections.new(agent2, nil, 'bbb-2') + collection_client3 = Sessions::Backend::Collections.new(customer1, nil, 'bbb-2') + + # get whole collections + result1 = collection_client1.push + assert( result1, "check collections" ) + assert( check_if_collection_exists(result1, :Group), "check collections - after init" ) + assert( check_if_collection_exists(result1, :Role), "check collections - after init" ) + assert( check_if_collection_exists(result1, :Signature), "check collections - after init" ) + assert( check_if_collection_exists(result1, :EmailAddress), "check collections - after init" ) + sleep 1 + result2 = collection_client2.push + assert( result2, "check collections" ) + assert( check_if_collection_exists(result2, :Group), "check collections - after init" ) + assert( check_if_collection_exists(result2, :Role), "check collections - after init" ) + assert( check_if_collection_exists(result2, :Signature), "check collections - after init" ) + assert( check_if_collection_exists(result2, :EmailAddress), "check collections - after init" ) + assert_equal( result1, result2, "check collections" ) + + result3 = collection_client3.push + assert( result3, "check collections" ) + assert( check_if_collection_exists(result3, :Group), "check collections - after init" ) + assert( check_if_collection_exists(result3, :Role), "check collections - after init" ) + assert( !check_if_collection_exists(result3, :Signature), "check collections - after init" ) + assert( !check_if_collection_exists(result3, :EmailAddress), "check collections - after init" ) + + # next check should be empty + result1 = collection_client1.push + assert( result1.empty?, "check collections - recall" ) + sleep 1 + result2 = collection_client2.push + assert( result2.empty?, "check collections - recall" ) + sleep 0.2 + result3 = collection_client3.push + assert( result3.empty?, "check collections - recall" ) + + # change collection + group = Group.first + group.touch + sleep 16 + + # get whole collections + result1 = collection_client1.push + assert( result1, "check collections - after touch" ) + assert( check_if_collection_exists(result1, :Group), "check collections - after touch" ) + sleep 1 + result2 = collection_client2.push + assert( result2, "check collections - after touch" ) + assert( check_if_collection_exists(result2, :Group), "check collections - after touch" ) + sleep 0.2 + result3 = collection_client3.push + assert( result3, "check collections - after touch" ) + assert( check_if_collection_exists(result3, :Group), "check collections - after touch" ) + + # change collection + org = Organization.create( :name => 'SomeOrg::' + rand(999999).to_s, :active => true ) + sleep 16 + + # get whole collections + result1 = collection_client1.push + assert( result1, "check collections - after create" ) + assert( check_if_collection_exists(result1, :Organization), "check collections - after create" ) + sleep 0.5 + result2 = collection_client2.push + assert( result2, "check collections - after create" ) + assert( check_if_collection_exists(result2, :Organization), "check collections - after create" ) + sleep 0.5 + result3 = collection_client3.push + assert( result3, "check collections - after create" ) + assert( !check_if_collection_exists(result3, :Organization), "check collections - after create" ) + + # next check should be empty + sleep 16 + result1 = collection_client1.push + assert( result1.empty?, "check collections - recall" ) + sleep 1 + result2 = collection_client2.push + assert( result2.empty?, "check collections - recall" ) + sleep 0.2 + result3 = collection_client3.push + assert( result3.empty?, "check collections - recall" ) + end + + def check_if_collection_exists(results, collection) + results.each {|result| + return true if result && result[:collection] && result[:collection][collection] + } + nil + end + +end \ No newline at end of file diff --git a/test/unit/session_test.rb b/test/unit/session_enhanced_test.rb similarity index 67% rename from test/unit/session_test.rb rename to test/unit/session_enhanced_test.rb index ebcbbc2c1..431696e31 100644 --- a/test/unit/session_test.rb +++ b/test/unit/session_enhanced_test.rb @@ -1,70 +1,8 @@ # encoding: utf-8 require 'test_helper' -class SessionTest < ActiveSupport::TestCase - test 'a cache' do - Sessions::CacheIn.set( 'last_run_test' , true, { :expires_in => 2.seconds } ) - result = Sessions::CacheIn.get( 'last_run_test' ) - assert_equal( true, result, "check 1" ) - - # should not be expired - result = Sessions::CacheIn.expired( 'last_run_test' ) - assert_equal( false, result, "check 1 - expired" ) - - # should be expired - sleep 3 - result = Sessions::CacheIn.expired( 'last_run_test' ) - assert_equal( true, result, "check 1 - expired" ) - - # renew expire - result = Sessions::CacheIn.get( 'last_run_test', :re_expire => true ) - assert_equal( true, result, "check 1 - re_expire" ) - - # should not be expired - result = Sessions::CacheIn.expired( 'last_run_test' ) - assert_equal( false, result, "check 1 - expired" ) - - # ignore expired - sleep 3 - result = Sessions::CacheIn.get( 'last_run_test', :ignore_expire => true ) - assert_equal( true, result, "check 1 - ignore_expire" ) - - # should be expired - result = Sessions::CacheIn.expired( 'last_run_test' ) - assert_equal( true, result, "check 2" ) - - result = Sessions::CacheIn.get( 'last_run_test' ) - assert_equal( nil, result, "check 2" ) - end - - - test 'worker' do - # create users - roles = Role.where( :name => [ 'Agent'] ) - groups = Group.all - - UserInfo.current_user_id = 1 - agent1 = User.create_or_update( - :login => 'session-agent-1', - :firstname => 'Session', - :lastname => 'Agent 1', - :email => 'session-agent1@example.com', - :password => 'agentpw', - :active => true, - :roles => roles, - :groups => groups, - ) - - worker = Thread.new { - Sessions.thread_worker(agent1.id) - } - - #Sessions::Backend::TicketOverviewIndex.worker() - - worker.exit - end - - test 'z full' do +class SessionEnhancedTest < ActiveSupport::TestCase + test 'a check clients and send messages' do # create users roles = Role.where( :name => [ 'Agent'] ) @@ -194,11 +132,6 @@ class SessionTest < ActiveSupport::TestCase sleep 5 #jobs.join - # check worker threads - assert( Sessions.thread_worker_exists?(agent1), "check if worker is running" ) - assert( Sessions.thread_worker_exists?(agent2), "check if worker is running" ) - assert( Sessions.thread_worker_exists?(agent3), "check if worker is running" ) - # check client threads assert( Sessions.thread_client_exists?(client_id1), "check if client is running" ) assert( Sessions.thread_client_exists?(client_id2), "check if client is running" ) @@ -220,13 +153,121 @@ class SessionTest < ActiveSupport::TestCase assert( !Sessions.thread_client_exists?(client_id2), "check if client is running" ) assert( !Sessions.thread_client_exists?(client_id3), "check if client is running" ) - # check worker threads - assert( !Sessions.thread_worker_exists?(agent1), "check if worker is running" ) - assert( !Sessions.thread_worker_exists?(agent2), "check if worker is running" ) - assert( !Sessions.thread_worker_exists?(agent3), "check if worker is running" ) - # exit jobs jobs.exit end + + test 'b check client and backends' do + # create users + roles = Role.where( :name => [ 'Agent'] ) + groups = Group.all + + UserInfo.current_user_id = 1 + agent1 = User.create_or_update( + :login => 'session-agent-1', + :firstname => 'Session', + :lastname => 'Agent 1', + :email => 'session-agent1@example.com', + :password => 'agentpw', + :active => true, + :roles => roles, + :groups => groups, + ) + agent2 = User.create_or_update( + :login => 'session-agent-2', + :firstname => 'Session', + :lastname => 'Agent 2', + :email => 'session-agent2@example.com', + :password => 'agentpw', + :active => true, + :roles => roles, + :groups => groups, + ) + + # create sessions + client_id1_0 = '1234-1' + client_id1_1 = '1234-2' + client_id2 = '123456' + Sessions.destory(client_id1_0) + Sessions.destory(client_id1_1) + Sessions.destory(client_id2) + + # start jobs + jobs = Thread.new { + Sessions.jobs + } + sleep 5 + Sessions.create( client_id1_0, agent1.attributes, { :type => 'websocket' } ) + sleep 5.5 + Sessions.create( client_id1_1, agent1.attributes, { :type => 'websocket' } ) + sleep 1.2 + Sessions.create( client_id2, agent2.attributes, { :type => 'ajax' } ) + + # check if session exists + assert( Sessions.session_exists?(client_id1_0), "check if session exists" ) + assert( Sessions.session_exists?(client_id1_1), "check if session exists" ) + assert( Sessions.session_exists?(client_id2), "check if session exists" ) + sleep 19 + + # check collections + collections = { + 'Group' => true, + 'Organization' => true, + 'User' => nil, + } + check_if_collection_reset_message_exists(client_id1_0, collections, 'init') + check_if_collection_reset_message_exists(client_id1_1, collections, 'init') + check_if_collection_reset_message_exists(client_id2, collections, 'init') + + # change collection + group = Group.first + group.touch + + sleep 20 + + # check collections + collections = { + 'Group' => true, + 'Organization' => nil, + 'User' => nil, + } + check_if_collection_reset_message_exists(client_id1_0, collections, 'update') + check_if_collection_reset_message_exists(client_id1_1, collections, 'update') + check_if_collection_reset_message_exists(client_id2, collections, 'update') + + # check if session still exists after idle cleanup + sleep 62 + client_ids = Sessions.destory_idle_sessions(1) + + # check client sessions + assert( !Sessions.session_exists?(client_id1_0), "check if session is removed" ) + assert( !Sessions.session_exists?(client_id1_1), "check if session is removed" ) + assert( !Sessions.session_exists?(client_id2), "check if session is removed" ) + + end + + def check_if_collection_reset_message_exists(client_id, collections_orig, type) + messages = Sessions.queue(client_id) + puts "cid: #{client_id}" + #puts "m: #{messages.inspect}" + collections_result = {} + messages.each {|message| + #puts "" + #puts "message: #{message.inspect}" + if message['event'] == 'resetCollection' + puts "rc: " + if message['data'] + message['data'].each {|key, value| + puts "rc: #{key}" + collections_result[key] = true + } + end + end + } + puts "c: #{collections_result.inspect}" + collections_orig.each {|key, value| + assert_equal( collections_orig[key], collections_result[key], "collection message for #{key} #{type}-check" ) + } + end end