Class: SockJS::Session

Inherits:
MetaState::Machine show all
Defined in:
lib/sockjs/session.rb

Defined Under Namespace

Classes: Consumer

Constant Summary

Constants inherited from MetaState::Machine

MetaState::Machine::NON_MESSAGES

Instance Attribute Summary collapse

Attributes inherited from MetaState::Machine

#current_state

Instance Method Summary collapse

Methods inherited from MetaState::Machine

add_state, build_void_state, #debug_with, default_state, default_state=, state, #state=, state_names, states, void_state_module

Constructor Details

#initialize(connection) ⇒ Session

Returns a new instance of Session.



291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
# File 'lib/sockjs/session.rb', line 291

def initialize(connection)
  super()

  debug_with do |msg|
    SockJS::debug(msg)
  end

  @connection = connection
  @disconnect_delay = 5 # TODO: make this configurable.
  @received_messages = []
  @outbox = []
  @total_sent_content_length = 0
  @interval = 0.1
  @closing_frame = nil
  @data = {}
  @alive = true
  @timers = {}
end

Instance Attribute Details

#closing_frameObject (readonly)

Returns the value of attribute closing_frame.



289
290
291
# File 'lib/sockjs/session.rb', line 289

def closing_frame
  @closing_frame
end

#dataObject (readonly)

Returns the value of attribute data.



289
290
291
# File 'lib/sockjs/session.rb', line 289

def data
  @data
end

#disconnect_delayObject

Returns the value of attribute disconnect_delay.



288
289
290
# File 'lib/sockjs/session.rb', line 288

def disconnect_delay
  @disconnect_delay
end

#intervalObject

Returns the value of attribute interval.



288
289
290
# File 'lib/sockjs/session.rb', line 288

def interval
  @interval
end

#outboxObject (readonly)

Returns the value of attribute outbox.



289
290
291
# File 'lib/sockjs/session.rb', line 289

def outbox
  @outbox
end

#responseObject (readonly)

Returns the value of attribute response.



289
290
291
# File 'lib/sockjs/session.rb', line 289

def response
  @response
end

#transportObject (readonly)

Returns the value of attribute transport.



289
290
291
# File 'lib/sockjs/session.rb', line 289

def transport
  @transport
end

Instance Method Details

#activatedObject



276
277
# File 'lib/sockjs/session.rb', line 276

def activated
end

#after_app_runObject



270
271
# File 'lib/sockjs/session.rb', line 270

def after_app_run
end

#after_consumer_attachedObject



282
283
# File 'lib/sockjs/session.rb', line 282

def after_consumer_attached
end

#after_consumer_detachedObject



285
286
# File 'lib/sockjs/session.rb', line 285

def after_consumer_detached
end

#alive?Boolean

Returns:

  • (Boolean)


310
311
312
# File 'lib/sockjs/session.rb', line 310

def alive?
  !!@alive
end

#check_content_lengthObject



232
233
234
235
236
237
238
239
240
# File 'lib/sockjs/session.rb', line 232

def check_content_length
  if @consumer.total_sent_length >= max_permitted_content_length
    SockJS.debug "Maximum content length exceeded, closing the connection."
    #shouldn't be restarting connection?
    @consumer.disconnect
  else
    SockJS.debug "Permitted content length: #{@consumer.total_sent_length} of #{max_permitted_content_length}"
  end
end

#check_response_aliveObject



352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
# File 'lib/sockjs/session.rb', line 352

def check_response_alive
  if @consumer
    begin
      @consumer.check_alive
    rescue Exception => error
      puts "==> #{error.message}"
      SockJS.debug error
      puts "==> #{error.message}"
      on_close
      @alive_checker.cancel
    end
  else
    puts "~ [TODO] Not checking if still alive, why?"
  end
end

#clear_all_timersObject



396
397
398
399
400
401
# File 'lib/sockjs/session.rb', line 396

def clear_all_timers
  @timers.values.each do |timer|
    timer.cancel
  end
  @timers.clear
end

#clear_timer(name) ⇒ Object



391
392
393
394
# File 'lib/sockjs/session.rb', line 391

def clear_timer(name)
  @timers[name].cancel unless @timers[name].nil?
  @timers.delete(name)
end

#closedObject



273
274
# File 'lib/sockjs/session.rb', line 273

def closed
end

#disconnect_expiredObject

Timer actions:



346
347
348
349
350
# File 'lib/sockjs/session.rb', line 346

def disconnect_expired
  SockJS.debug "#{@disconnect_delay} has passed, firing @disconnect_timer"
  close
  #XXX Shouldn't destroy the session?
end

#heartbeat_triggeredObject



368
369
370
371
372
373
374
375
376
377
378
379
# File 'lib/sockjs/session.rb', line 368

def heartbeat_triggered
  # It's better as we know for sure that
  # clearing the buffer won't change it.
  SockJS.debug "Sending heartbeat frame."
  begin
    send_heartbeat
  rescue Exception => error
    # Nah these exceptions are OK ... let's figure out when they occur
    # and let's just not set the timer for such cases in the first place.
    SockJS.debug "Exception when sending heartbeat frame: #{error.inspect}"
  end
end

#max_permitted_content_lengthObject



320
321
322
# File 'lib/sockjs/session.rb', line 320

def max_permitted_content_length
  @max_permitted_content_length ||= ($DEBUG ? 4096 : 128_000)
end

#on_closeObject

XXX This is probably important - need to examine this case



315
316
317
318
# File 'lib/sockjs/session.rb', line 315

def on_close
  SockJS.debug "The connection has been closed on the client side (current status: #{@status})."
  close_session(1002, "Connection interrupted")
end

#openedObject



267
268
# File 'lib/sockjs/session.rb', line 267

def opened
end

#parse_json(data) ⇒ Object



324
325
326
327
328
329
330
331
332
# File 'lib/sockjs/session.rb', line 324

def parse_json(data)
  if data.empty?
    return []
  end

  JSON.parse("[#{data}]")[0]
rescue JSON::ParserError => error
  raise SockJS::InvalidJSON.new(500, "Broken JSON encoding.")
end

#process_message(message) ⇒ Object



264
265
# File 'lib/sockjs/session.rb', line 264

def process_message(message)
end

#receive_message(data) ⇒ Object

All incoming data is treated as incoming messages, either single json-encoded messages or an array of json-encoded messages, depending on transport.



210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/sockjs/session.rb', line 210

def receive_message(data)
  clear_timer(:disconnect)
  activate

  SockJS.debug "Session receiving message: #{data.inspect}"
  messages = parse_json(data)
  SockJS.debug "Message parsed as: #{messages.inspect}"
  unless messages.empty?
    @received_messages.push(*messages)
  end

  EM.next_tick do
    run_user_app
  end

  set_disconnect_timer
end

#reset_alive_timerObject



410
411
412
413
# File 'lib/sockjs/session.rb', line 410

def reset_alive_timer
  clear_timer(:alive_check)
  set_alive_timer
end

#reset_close_timerObject



453
454
455
456
# File 'lib/sockjs/session.rb', line 453

def reset_close_timer
  clear_timer(:close)
  set_close_timer
end

#reset_disconnect_timerObject



442
443
444
445
# File 'lib/sockjs/session.rb', line 442

def reset_disconnect_timer
  clear_timer(:disconnect)
  set_disconnect_timer
end

#reset_heartbeat_timerObject



427
428
429
430
431
432
433
434
# File 'lib/sockjs/session.rb', line 427

def reset_heartbeat_timer
  clear_timer(:heartbeat)
  if current_state == SockJS::Session::Closed
    SockJS.debug "trying to setup heartbeat on closed session!"
  else
    set_heartbeat_timer
  end
end

#run_user_appObject



242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'lib/sockjs/session.rb', line 242

def run_user_app
  unless @received_messages.empty?
    reset_heartbeat_timer #XXX Only one point which can set hearbeat while state is closed

    SockJS.debug "Executing user's SockJS app"

    raise @error if @error

    @received_messages.each do |message|
      SockJS.debug "Executing app with message #{message.inspect}"
      process_message(message)
    end
    @received_messages.clear

    after_app_run

    SockJS.debug "User's SockJS app finished"
  end
rescue SockJS::CloseError => error
  Protocol::ClosingFrame.new(error.status, error.message)
end

#set_alive_timerObject



404
405
406
407
408
# File 'lib/sockjs/session.rb', line 404

def set_alive_timer
  set_timer(:alive_check, EM::PeriodicTimer, 1) do
    check_response_alive
  end
end

#set_close_timerObject



447
448
449
450
451
# File 'lib/sockjs/session.rb', line 447

def set_close_timer
  set_timer(:close, EM::Timer, @disconnect_delay) do
    @alive = false
  end
end

#set_disconnect_timerObject



436
437
438
439
440
# File 'lib/sockjs/session.rb', line 436

def set_disconnect_timer
  set_timer(:disconnect, EM::Timer, @disconnect_delay) do
    disconnect_expired
  end
end

#set_heartbeat_timerObject



415
416
417
418
419
420
421
422
423
424
425
# File 'lib/sockjs/session.rb', line 415

def set_heartbeat_timer
  if current_state == SockJS::Session::Closed
    SockJS.debug "trying to setup heartbeat on closed session!"
    return
  end
  clear_timer(:disconnect)
  clear_timer(:alive)
  set_timer(:heartbeat, EM::PeriodicTimer, 25) do
    heartbeat_triggered
  end
end

#set_timer(name, type, delay, &action) ⇒ Object

Timer machinery



383
384
385
386
387
388
389
# File 'lib/sockjs/session.rb', line 383

def set_timer(name, type, delay, &action)
  @timers[name] ||=
    begin
      SockJS.debug "Setting timer: #{name} to expire after #{delay}"
      type.new(delay, &action)
    end
end

#suspendedObject



279
280
# File 'lib/sockjs/session.rb', line 279

def suspended
end

#suspended?Boolean

Returns:

  • (Boolean)


228
229
230
# File 'lib/sockjs/session.rb', line 228

def suspended?
  current_state == SockJS::Session::Suspended
end