sbsm 1.3.4 → 1.3.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8b27b0cd01f696045f8dcd2a676f8803b9f25ae7
4
- data.tar.gz: aa44fd845938ef1024d628ee414e39825d55fcb2
3
+ metadata.gz: 098df1b1f3f9be3383dc1adbc44087a8662ac7e7
4
+ data.tar.gz: 3836d50af930294d0fa5bdacec1bcc04085880a4
5
5
  SHA512:
6
- metadata.gz: 5a5ff8f1920bf41c325356a5e7277d0aa67f0b686296d170b2b1a0040a62462992e5668f2b815a9e2cb2b18b8840f73ea496737df63b063ce432ae77d1e49aec
7
- data.tar.gz: 5c208b5d7943f1e342d2eee87b40a03642f5811e8a5b85721081beb8c28a2425fbbb9049259a02b87b4506a082aaa2d29cbcc3bb359c75c1120a5850fa310763
6
+ metadata.gz: cefada511b938ff19624f587ccc16feca6a33ac34b8875f24d9881c9504bd7e6a87df46bef3492d18b3ed9bb2d409d68c7230f83d5d9f38e060ce20888bdd3af
7
+ data.tar.gz: ccf6801e741324e0fc11df4f53a103e43085996a1793d6ad9a5207843440621c1f4fd778aeb3146ca1f2d81e92e2b55cdc9699db0132d2ab95a69e8206efae35
@@ -1,3 +1,8 @@
1
+ === 1.3.5 /14.12.2016
2
+ * Refactored sbsm to work without DRb
3
+ * Added test/config.ru to be able to run tests via wrk
4
+ * The interface to Session.new changed and must be adapted by client where the SBSM::Session class is overridden.
5
+
1
6
  === 1.3.4 /12.12.2016
2
7
  * As we quite often got errors about recycled objects, I added a GC.start in the call method of sbsm/app
3
8
  It introduces a delay of 12 to 30 ms. Therefore we should look for a better solution later
@@ -26,50 +26,59 @@
26
26
  require 'cgi'
27
27
  require 'cgi/session'
28
28
  require 'sbsm/cgi'
29
- require 'cgi/drbsession'
30
- require 'sbsm/drbserver'
29
+ require 'sbsm/session_store'
30
+ require 'sbsm/trans_handler'
31
+ require 'sbsm/validator'
31
32
  require 'mimemagic'
32
33
 
33
34
  module SBSM
34
35
  ###
35
36
  # App a base class for Webrick server
36
- class App < SBSM::DRbServer
37
- include DRbUndumped
38
- attr_reader :sbsm, :my_self, :trans_handler, :validator, :drb_uri
37
+ class App
39
38
 
40
- OPTIONS = [ :app, :config_file, :trans_handler, :validator, :persistence_layer, :server_uri, :session, :unknown_user, :proxy ]
39
+ OPTIONS = [ :app, :config_file, :trans_handler, :validator, :persistence_layer, :server_uri, :unknown_user]
41
40
  OPTIONS.each{ |opt| eval "attr_reader :#{opt}" }
42
41
 
43
42
  # Base class for a SBSM based WebRick HTTP server
44
- # * offers a start_server() method to launch a DRB server for handling the DRB-requests
45
43
  # * offer a call(env) method form handling the WebRick requests
46
44
  # This is all what is needed to be compatible with WebRick
47
45
  #
48
- # === arguments
46
+ # === optional arguments
49
47
  #
50
- # * +app+ - The app we should handle requests for
51
48
  # * +validator+ - A Ruby class overriding the SBSM::Validator class
52
49
  # * +trans_handler+ - A Ruby class overriding the SBSM::TransHandler class
50
+ # * +session_class+ - A Ruby class overriding the SBSM::Session class
51
+ # * +unknown_user+ - A Ruby class overriding the SBSM::UnknownUser class
53
52
  # * +persistence_layer+ - Persistence Layer to use
54
53
  # * +cookie_name+ - The cookie to save persistent user data
55
- # * +drb_uri+ - URI for DRB-Server of app
56
54
  #
57
55
  # === Examples
58
56
  # Look at steinwies.ch
59
57
  # * https://github.com/zdavatz/steinwies.ch (simple, mostly static files, one form, no persistence layer)
60
58
  #
61
- def initialize(app:, validator:, trans_handler:, drb_uri:, persistence_layer: nil, cookie_name: nil)
62
- SBSM.info "initialize #{$0} app #{app.class} @app is now #{@app.class} validator #{validator} th #{trans_handler} drb_uri #{drb_uri}"
63
- @app = app unless @app
64
- @cookie_name = cookie_name || SBSM::Session::PERSISTENT_COOKIE_NAME
65
- @drb_uri = drb_uri
66
- @trans_handler = trans_handler
67
- @validator = validator
68
- super(persistence_layer)
59
+ def initialize(validator: nil,
60
+ trans_handler: nil,
61
+ session_class: nil,
62
+ persistence_layer: nil,
63
+ unknown_user: nil,
64
+ cookie_name: nil)
65
+ @@last_session = nil
66
+ SBSM.info "initialize validator #{validator} th #{trans_handler} cookie #{cookie_name} session #{session_class}"
67
+ @session_store = SessionStore.new(persistence_layer: persistence_layer,
68
+ trans_handler: trans_handler,
69
+ session_class: session_class,
70
+ cookie_name: cookie_name,
71
+ unknown_user: unknown_user,
72
+ app: self,
73
+ validator: validator)
69
74
  end
70
75
 
71
76
  SESSION_ID = '_session_id'
72
77
 
78
+ def last_session
79
+ @@last_session
80
+ end
81
+
73
82
  def call(env) ## mimick sbsm/lib/app.rb
74
83
  request = Rack::Request.new(env)
75
84
  response = Rack::Response.new
@@ -88,35 +97,31 @@ module SBSM
88
97
  end
89
98
 
90
99
  return [400, {}, []] if /favicon.ico/i.match(request.path)
91
- @drb_uri ||= @app.drb_uri
100
+ # https://www.tutorialspoint.com/ruby/ruby_cgi_sessions.htm
92
101
  args = {
93
- 'database_manager' => CGI::Session::DRbSession,
94
- 'drbsession_uri' => @drb_uri,
102
+ 'database_manager' => @session_store,
95
103
  'session_path' => '/',
96
104
  @cookie_name => session_id,
97
105
  }
98
- SBSM.debug "starting session_id #{session_id} #{request.path}: cookies #{@cookie_name} are #{request.cookies} @session #{@session.class} @cgi #{@cgi.class}"
106
+ session = @session_store[session_id]
107
+ session.app ||= self
108
+ SBSM.debug "starting session_id #{session_id} session #{session.class} #{request.path}: cookies #{@cookie_name} are #{request.cookies} @cgi #{@cgi.class}"
99
109
  @cgi = CGI.initialize_without_offline_prompt('html4') unless @cgi
100
- @session = CGI::Session.new(@cgi, args) unless @session
101
- saved = self[session_id]
102
- @start_time = Time.now.to_f
103
- GC.start
104
- SBSM.debug "GC.start took #{((Time.now.to_f)- @start_time)*1000.0} milliseconds"
105
- @proxy = DRbObject.new(saved, server_uri) unless @proxy.is_a?(DRbObject)
106
- @proxy.trans_handler = @trans_handler
107
- @proxy.app = @app unless @proxy.app
108
- res = @proxy.drb_process(self, request)
110
+ session = CGI::Session.new(@cgi, args) unless session
111
+ res = session.process_rack(rack_request: request)
109
112
  response.write res
110
113
  response.headers['Content-Type'] ||= 'text/html; charset=utf-8'
111
- response.headers.merge!(@proxy.http_headers)
114
+ response.headers.merge!(session.http_headers)
112
115
  if (result = response.headers.find { |k,v| /status/i.match(k) })
113
116
  response.status = result.last.to_i
114
117
  response.headers.delete(result.first)
115
118
  end
116
- response.set_cookie(@cookie_name, :value => @proxy.cookie_input)
119
+ response.set_cookie(session.cookie_name, :value => session.cookie_input)
117
120
  response.set_cookie(SESSION_ID, :value => session_id)
118
- SBSM.debug "finish session_id #{session_id}: header with cookies #{response.headers} from #{@proxy.cookie_input}"
121
+ @@last_session = session
122
+ SBSM.debug "finish session_id #{session_id}: header with cookies #{response.headers} from #{session.cookie_input}"
119
123
  response.finish
120
124
  end
125
+
121
126
  end
122
127
  end
@@ -25,7 +25,6 @@
25
25
  # CGI redefinitions
26
26
 
27
27
  require 'cgi'
28
- require 'drb/drb'
29
28
 
30
29
  class CGI
31
30
  # Lets satisfy cgi-offline prompt, even if request does not have
@@ -28,30 +28,28 @@
28
28
 
29
29
  require 'cgi'
30
30
  require 'sbsm/cgi'
31
- require 'sbsm/drb'
32
31
  require 'sbsm/state'
32
+ require 'sbsm/user'
33
33
  require 'sbsm/lookandfeelfactory'
34
34
  require 'delegate'
35
- require 'sbsm/trans_handler'
36
35
 
37
36
  module SBSM
38
- class Session < SimpleDelegator
39
- attr_reader :user, :active_thread, :key, :cookie_input,
40
- :unsafe_input, :valid_input, :request_path, :cgi
41
- attr_writer :trans_handler, :app, :validator
42
- include DRbUndumped
37
+ class Session
38
+ attr_reader :user, :active_thread, :key, :cookie_input, :cookie_name,
39
+ :unsafe_input, :valid_input, :request_path, :cgi, :attended_states
40
+ attr_accessor :validator, :trans_handler, :app
43
41
  PERSISTENT_COOKIE_NAME = "sbsm-persistent-cookie"
44
42
  DEFAULT_FLAVOR = 'sbsm'
45
43
  DEFAULT_LANGUAGE = 'en'
46
44
  DEFAULT_STATE = State
47
45
  DEFAULT_ZONE = nil
48
- DRB_LOAD_LIMIT = 255 * 102400
49
46
  EXPIRES = 60 * 60
50
47
  LF_FACTORY = nil
51
48
  LOOKANDFEEL = Lookandfeel
52
49
  CAP_MAX_THRESHOLD = 8
53
50
  MAX_STATES = 4
54
51
  SERVER_NAME = nil
52
+ UNKNOWN_USER = UnknownUser
55
53
  def Session.reset_stats
56
54
  @@stats = {}
57
55
  end
@@ -88,24 +86,54 @@ module SBSM
88
86
  requests, grand_total)
89
87
  ''
90
88
  end
91
- def initialize(key, app, validator=nil)
92
- SBSM.info "initialize app #{app.class} @app is now #{@app.class} validator #{validator} th #{@trans_handler}" # drb_uri #{drb_uri}"
93
- touch()
94
- reset_input()
95
- reset_cookie()
96
- raise "Must pass key and app and validator to session" unless key && app # && validator
89
+
90
+ # Session: It will be initialized indirectly whenever SessionStore cannot
91
+ # find a session in it cache. The parameters are given via SBSM::App.new
92
+ # which calls SessionStore.new
93
+ #
94
+ # === optional arguments
95
+ #
96
+ # * +validator+ - A Ruby class overriding the SBSM::Validator class
97
+ # * +trans_handler+ - A Ruby class overriding the SBSM::TransHandler class
98
+ # * +unknown_user+ - A Ruby class overriding the SBSM::UnknownUser class
99
+ # * +cookie_name+ - The cookie to save persistent user data
100
+ #
101
+ # === Examples
102
+ # Look at steinwies.ch
103
+ # * https://github.com/zdavatz/steinwies.ch (simple, mostly static files, one form, no persistence layer)
104
+ #
105
+ def initialize(app:,
106
+ trans_handler: nil,
107
+ validator: nil,
108
+ unknown_user: nil,
109
+ cookie_name: nil)
110
+ SBSM.info "initialize th #{trans_handler} validator #{validator}"
97
111
  @app = app
98
- @key = key
112
+ @unknown_user = unknown_user
113
+ @unknown_user ||= self.class::UNKNOWN_USER
99
114
  @validator = validator
115
+ @validator ||= Validator.new
116
+ fail "invalid validator #{@validator}" unless @validator.is_a?(SBSM::Validator)
117
+ @trans_handler = trans_handler
118
+ @trans_handler ||= TransHandler.instance
119
+ fail "invalid trans_handler #{@trans_handler}" unless @trans_handler.is_a?(SBSM::TransHandler)
120
+ @cookie_name = cookie_name
121
+ @cookie_name ||= self.class::PERSISTENT_COOKIE_NAME
100
122
  @attended_states = {}
101
123
  @persistent_user_input = {}
102
- logout()
103
- @unknown_user_class = @user.class
124
+ touch()
125
+ reset_input()
126
+ reset_cookie()
127
+ @user = @unknown_user
128
+ @unknown_user_class
129
+ @unknown_user_class = @unknown_user.class
104
130
  @variables = {}
105
131
  @mutex = Mutex.new
106
132
  @cgi = CGI.initialize_without_offline_prompt('html4')
107
- SBSM.debug "session initialized #{self} key #{key} app #{app.class} #{@validator.class} th #{@trans_handler.class} with @cgi #{@cgi}"
108
- super(app)
133
+ SBSM.debug "session initialized #{self} with @cgi #{@cgi}"
134
+ end
135
+ def unknown_user
136
+ @unknown_user_class.new
109
137
  end
110
138
  def age(now=Time.now)
111
139
  now - @mtime
@@ -155,9 +183,6 @@ module SBSM
155
183
  def get_cookie_input(key)
156
184
  @cookie_input[key]
157
185
  end
158
- def cookie_name
159
- self::class::PERSISTENT_COOKIE_NAME
160
- end
161
186
  def default_language
162
187
  self::class::DEFAULT_LANGUAGE
163
188
  end
@@ -165,19 +190,47 @@ module SBSM
165
190
  # used when
166
191
  @state.direct_event
167
192
  end
168
- def drb_process(app, rack_request)
193
+ def process_rack(rack_request:)
169
194
  start = Time.now
170
195
  @request_path ||= rack_request.path
171
196
  rack_request.params.each { |key, val| @cgi.params.store(key, val) }
172
197
  @trans_handler.translate_uri(rack_request)
173
198
  html = @mutex.synchronize do
174
- process(rack_request)
199
+ begin
200
+ @request_method =rack_request.request_method
201
+ @request_path = rack_request.path
202
+ logout unless @active_state
203
+ validator.reset_errors() if validator && validator.respond_to?(:reset_errors)
204
+ import_user_input(rack_request)
205
+ import_cookies(rack_request)
206
+ @state = active_state.trigger(event())
207
+ SBSM.debug "active_state.trigger state #{@state.object_id} remember #{persistent_user_input(:remember).inspect}"
208
+ #FIXME: is there a better way to distinguish returning states?
209
+ # ... we could simply refuse to init if event == :sort, but that
210
+ # would not solve the problem cleanly, I think.
211
+ unless(@state.request_path)
212
+ @state.request_path = @request_path
213
+ @state.init
214
+ end
215
+ unless @state.volatile?
216
+ SBSM.debug "Changing from #{@active_state.object_id} to state #{@state.class} #{@state.object_id} remember #{persistent_user_input(:remember).inspect}"
217
+ @active_state = @state
218
+ @attended_states.store(@state.object_id, @state)
219
+ else
220
+ SBSM.debug "Stay in volatile state #{@state.object_id}"
221
+ end
222
+ @zone = @active_state.zone
223
+ @active_state.touch
224
+ cap_max_states
225
+ ensure
226
+ @user_input_imported = false
227
+ end
175
228
  to_html
176
229
  end
177
230
  (@@stats[@request_path] ||= []).push(Time.now - start)
178
231
  html
179
232
  rescue => err
180
- SBSM.info "Error in drb_process #{err.backtrace[0..5].join("\n")}"
233
+ SBSM.info "Error in process_rack #{err.backtrace[0..5].join("\n")}"
181
234
  raise err
182
235
  end
183
236
  def error(key)
@@ -206,11 +259,11 @@ module SBSM
206
259
  age(now) > EXPIRES
207
260
  end
208
261
  def force_login(user)
262
+ binding.pry
209
263
  @user = user
210
264
  end
211
265
  def import_cookies(request)
212
266
  reset_cookie()
213
- return if request.cookies.is_a?(DRb::DRbUnknown)
214
267
  if(cuki_str = request.cookies[self::class::PERSISTENT_COOKIE_NAME])
215
268
  SBSM.debug "cuki_str #{self::class::PERSISTENT_COOKIE_NAME} #{cuki_str}"
216
269
  eval(cuki_str).each { |key, val|
@@ -224,8 +277,6 @@ module SBSM
224
277
  @@hash_ptrn = /([^\[]+)((\[[^\]]+\])+)/
225
278
  @@index_ptrn = /[^\[\]]+/
226
279
  def import_user_input(rack_req)
227
- # attempting to read the cgi-params more than once results in a
228
- # DRbConnectionRefused Exception. Therefore, do it only once...
229
280
  return if(@user_input_imported)
230
281
  hash = rack_req.env.merge rack_req.params
231
282
  hash.merge! rack_req.POST if rack_req.POST
@@ -298,7 +349,7 @@ module SBSM
298
349
  !@user.is_a?(@unknown_user_class)
299
350
  end
300
351
  def login
301
- if(user = @app.login(self))
352
+ if(user = (@app && @app.respond_to?(:login) && @app.login(self)))
302
353
  SBSM.debug "user is #{user} #{request_path.inspect}"
303
354
  @user = user
304
355
  else
@@ -307,8 +358,8 @@ module SBSM
307
358
  end
308
359
  def logout
309
360
  __checkout
310
- @user = @app.unknown_user()
311
- @active_state = @state = self::class::DEFAULT_STATE.new(self, @user)
361
+ @user = unknown_user()
362
+ @active_state = @state = self::class::DEFAULT_STATE.new(self, @user)
312
363
  SBSM.debug "logout #{request_path.inspect} setting @state #{@state.object_id} #{@state.class} remember #{persistent_user_input(:remember).inspect}"
313
364
  @state.init
314
365
  @attended_states.store(@state.object_id, @state)
@@ -339,8 +390,6 @@ module SBSM
339
390
  end
340
391
  def http_headers
341
392
  @state.http_headers
342
- rescue DRb::DRbConnError
343
- raise
344
393
  rescue NameError, StandardError => err
345
394
  SBSM.info "NameError, StandardError: #@request_path"
346
395
  {'Content-Type' => 'text/plain'}
@@ -369,40 +418,6 @@ module SBSM
369
418
  @persistent_user_input[key]
370
419
  end
371
420
  end
372
- def process(rack_request)
373
- begin
374
- @request_method =rack_request.request_method
375
- @request = rack_request
376
- @request_method ||= @request.request_method
377
- @request_path = @request.path
378
- @validator.reset_errors() if @validator && @validator.respond_to?(:reset_errors)
379
- import_user_input(rack_request)
380
- import_cookies(rack_request)
381
- @state = active_state.trigger(event())
382
- SBSM.debug "active_state.trigger state #{@state.object_id} remember #{persistent_user_input(:remember).inspect}"
383
- #FIXME: is there a better way to distinguish returning states?
384
- # ... we could simply refuse to init if event == :sort, but that
385
- # would not solve the problem cleanly, I think.
386
- unless(@state.request_path)
387
- @state.request_path = @request_path
388
- @state.init
389
- end
390
- unless @state.volatile?
391
- SBSM.debug "Changing from #{@active_state.object_id} to state #{@state.object_id} remember #{persistent_user_input(:remember).inspect}"
392
- @active_state = @state
393
- @attended_states.store(@state.object_id, @state)
394
- else
395
- SBSM.debug "Stay in volatile state #{@state.object_id}"
396
- end
397
- @zone = @active_state.zone
398
- @active_state.touch
399
- cap_max_states
400
- rescue DRb::DRbConnError
401
- raise
402
- ensure
403
- @user_input_imported = false
404
- end
405
- end
406
421
  def reset
407
422
  if @redirected
408
423
  SBSM.debug "reached Session::reset"
@@ -441,8 +456,6 @@ module SBSM
441
456
  else
442
457
  self::class::SERVER_NAME
443
458
  end
444
- rescue DRb::DRbConnError
445
- @server_name = self::class::SERVER_NAME
446
459
  end
447
460
  def state(event=nil)
448
461
  @active_state
@@ -453,8 +466,6 @@ module SBSM
453
466
  end
454
467
  def to_html
455
468
  @state.to_html(cgi)
456
- rescue DRb::DRbConnError
457
- raise
458
469
  end
459
470
  def user_agent
460
471
  @user_agent ||= (@request.user_agent if @request.respond_to?(:user_agent))
@@ -493,11 +504,10 @@ module SBSM
493
504
  @state.warning? if @state.respond_to?(:warning?)
494
505
  end
495
506
  # CGI::SessionHandler compatibility
507
+ # https://ruby-doc.org/stdlib-2.3.1/libdoc/cgi/rdoc/CGI.html
508
+ # should restore the values from a file, we return simply nothing
496
509
  def restore
497
- hash = {
498
- :proxy => self,
499
- }
500
- hash
510
+ {}
501
511
  end
502
512
  def update
503
513
  # nothing
@@ -0,0 +1,179 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+ #--
4
+ #
5
+ # State Based Session Management
6
+ # Copyright (C) 2004 Hannes Wyss
7
+ #
8
+ # This library is free software; you can redistribute it and/or
9
+ # modify it under the terms of the GNU Lesser General Public
10
+ # License as published by the Free Software Foundation; either
11
+ # version 2.1 of the License, or (at your option) any later version.
12
+ #
13
+ # This library is distributed in the hope that it will be useful,
14
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
+ # Lesser General Public License for more details.
17
+ #
18
+ # You should have received a copy of the GNU Lesser General Public
19
+ # License along with this library; if not, write to the Free Software
20
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
+ #
22
+ # ywesee - intellectual capital connected, Winterthurerstrasse 52, CH-8006 Zürich, Switzerland
23
+ # hwyss@ywesee.com
24
+ #
25
+ # SessionStore -- sbsm -- niger@ywesee.com
26
+ # 2016: ported this code from the old DrbServer
27
+ #++
28
+
29
+ require 'delegate'
30
+ require 'sbsm/session'
31
+ require 'sbsm/user'
32
+ require 'thread'
33
+ require 'digest/md5'
34
+ require 'sbsm/logger'
35
+ require 'sbsm/validator'
36
+
37
+ module SBSM
38
+ #
39
+ # SessionStore manages session, which are kept in memory
40
+ # Sessions are limited and expire after some time
41
+ # The maximal amount of concurrent session is given via CAP_MAX_THRESHOLD
42
+ #
43
+ class SessionStore
44
+ CLEANING_INTERVAL = 30
45
+ CAP_MAX_THRESHOLD = 120
46
+ ENABLE_ADMIN = false
47
+ MAX_SESSIONS = 100
48
+ RUN_CLEANER = true
49
+ SESSION = Session
50
+ UNKNOWN_USER = UnknownUser
51
+ VALIDATOR = nil
52
+ attr_reader :cleaner, :updater, :persistence_layer
53
+ def initialize(app:,
54
+ persistence_layer: nil,
55
+ trans_handler: nil,
56
+ session_class: nil,
57
+ validator: nil,
58
+ cookie_name: nil,
59
+ unknown_user: nil)
60
+ fail "You must specify an app!" unless app
61
+ @sessions = {}
62
+ @mutex = Mutex.new
63
+ @cleaner = run_cleaner if(self.class.const_get(:RUN_CLEANER))
64
+ @admin_threads = ThreadGroup.new
65
+ @async = ThreadGroup.new
66
+ @system = persistence_layer
67
+ @persistence_layer = persistence_layer
68
+ @cookie_name = cookie_name
69
+ @trans_handler = trans_handler
70
+ @trans_handler ||= TransHandler.instance
71
+ @session_class = session_class
72
+ @session_class ||= SBSM::Session
73
+ @unknown_user = unknown_user
74
+ @unknown_user ||= UNKNOWN_USER
75
+ @validator = validator
76
+ end
77
+ def _admin(src, result, priority=0)
78
+ raise "admin interface disabled" unless(self::class::ENABLE_ADMIN)
79
+ t = Thread.new {
80
+ Thread.current.abort_on_exception = false
81
+ result << begin
82
+ response = begin
83
+ instance_eval(src)
84
+ rescue NameError => e
85
+ e
86
+ end
87
+ str = response.to_s
88
+ if(str.length > 200)
89
+ response.class
90
+ else
91
+ str
92
+ end
93
+ rescue StandardError => e
94
+ e.message
95
+ end.to_s
96
+ }
97
+ t[:source] = src
98
+ t.priority = priority
99
+ @admin_threads.add(t)
100
+ t
101
+ end
102
+ def async(&block)
103
+ @async.add(Thread.new(&block))
104
+ end
105
+ def cap_max_sessions(now = Time.now)
106
+ if(@sessions.size > self::class::CAP_MAX_THRESHOLD)
107
+ SBSM.info "too many sessions! Keeping only #{self::class::MAX_SESSIONS}"
108
+ sess = nil
109
+ sorted = @sessions.values.sort
110
+ sorted[0...(-self::class::MAX_SESSIONS)].each { |sess|
111
+ sess.__checkout
112
+ @sessions.delete(sess.key)
113
+ }
114
+ if(sess)
115
+ age = sess.age(now)
116
+ SBSM.info sprintf("deleted all sessions that had not been accessed for more than %im %is", age / 60, age % 60)
117
+ end
118
+ end
119
+ end
120
+ def clean
121
+ now = Time.now
122
+ @sessions.delete_if { |key, s|
123
+ begin
124
+ if s.respond_to?(:expired?)
125
+ if s.expired?(now)
126
+ s.__checkout
127
+ true
128
+ else
129
+ s.cap_max_states
130
+ false
131
+ end
132
+ else
133
+ true
134
+ end
135
+ rescue
136
+ true
137
+ end
138
+ }
139
+ #cap_max_sessions(now)
140
+ end
141
+ def clear
142
+ @sessions.each_value { |sess| sess.__checkout }
143
+ @sessions.clear
144
+ end
145
+ def delete_session(key)
146
+ if(sess = @sessions.delete(key))
147
+ sess.__checkout
148
+ end
149
+ end
150
+ def reset
151
+ @mutex.synchronize {
152
+ @sessions.clear
153
+ }
154
+ end
155
+ def run_cleaner
156
+ # puts "running cleaner thread"
157
+ Thread.new do
158
+ Thread.current.abort_on_exception = true
159
+ #Thread.current.priority = 1
160
+ loop do
161
+ sleep self::class::CLEANING_INTERVAL
162
+ @mutex.synchronize do
163
+ clean()
164
+ end
165
+ end
166
+ end
167
+ end
168
+ def [](key)
169
+ @mutex.synchronize do
170
+ unless((s = @sessions[key]) && !s.expired?)
171
+ s = @sessions[key] = @session_class.new(app: @app, cookie_name: @cookie_name, trans_handler: @trans_handler, validator: @validator, unknown_user: @unknown_user)
172
+ end
173
+ s.reset()
174
+ s.touch()
175
+ s
176
+ end
177
+ end
178
+ end
179
+ end