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.



195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/sockjs/session.rb', line 195

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.



193
194
195
# File 'lib/sockjs/session.rb', line 193

def closing_frame
  @closing_frame
end

#dataObject (readonly)

Returns the value of attribute data.



193
194
195
# File 'lib/sockjs/session.rb', line 193

def data
  @data
end

#disconnect_delayObject

Returns the value of attribute disconnect_delay.



192
193
194
# File 'lib/sockjs/session.rb', line 192

def disconnect_delay
  @disconnect_delay
end

#intervalObject

Returns the value of attribute interval.



192
193
194
# File 'lib/sockjs/session.rb', line 192

def interval
  @interval
end

#outboxObject (readonly)

Returns the value of attribute outbox.



193
194
195
# File 'lib/sockjs/session.rb', line 193

def outbox
  @outbox
end

#responseObject (readonly)

Returns the value of attribute response.



193
194
195
# File 'lib/sockjs/session.rb', line 193

def response
  @response
end

#transportObject (readonly)

Returns the value of attribute transport.



193
194
195
# File 'lib/sockjs/session.rb', line 193

def transport
  @transport
end

Instance Method Details

#after_app_runObject



188
189
# File 'lib/sockjs/session.rb', line 188

def after_app_run
end

#alive?Boolean

Returns:

  • (Boolean)


214
215
216
# File 'lib/sockjs/session.rb', line 214

def alive?
  !!@alive
end

#check_content_lengthObject



150
151
152
153
154
155
156
157
158
# File 'lib/sockjs/session.rb', line 150

def check_content_length
  if @consumer.total_sent_length >= max_permitted_content_length
    SockJS.debug "Maximum content length exceeded, closing the connection."

    @consumer.disconnect
  else
    SockJS.debug "Permitted content length: #{@consumer.total_sent_length} of #{max_permitted_content_length}"
  end
end

#check_response_aliveObject

XXX Remove? What’s this for?



256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
# File 'lib/sockjs/session.rb', line 256

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

#clear_all_timersObject



300
301
302
303
304
305
# File 'lib/sockjs/session.rb', line 300

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

#clear_timer(name) ⇒ Object



295
296
297
298
# File 'lib/sockjs/session.rb', line 295

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

#disconnect_expiredObject

Timer actions:



250
251
252
253
# File 'lib/sockjs/session.rb', line 250

def disconnect_expired
  SockJS.debug "#{@disconnect_delay} has passed, firing @disconnect_timer"
  close
end

#heartbeat_triggeredObject



272
273
274
275
276
277
278
279
280
281
282
283
# File 'lib/sockjs/session.rb', line 272

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



224
225
226
# File 'lib/sockjs/session.rb', line 224

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



219
220
221
222
# File 'lib/sockjs/session.rb', line 219

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

#openedObject



185
186
# File 'lib/sockjs/session.rb', line 185

def opened
end

#parse_json(data) ⇒ Object



228
229
230
231
232
233
234
235
236
# File 'lib/sockjs/session.rb', line 228

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



182
183
# File 'lib/sockjs/session.rb', line 182

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.



133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/sockjs/session.rb', line 133

def receive_message(data)
  clear_timer(:disconnect)

  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



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

def reset_alive_timer
  clear_timer(:alive_check)
  set_alive_timer
end

#reset_close_timerObject



349
350
351
352
# File 'lib/sockjs/session.rb', line 349

def reset_close_timer
  clear_timer(:close)
  set_close_timer
end

#reset_disconnect_timerObject



338
339
340
341
# File 'lib/sockjs/session.rb', line 338

def reset_disconnect_timer
  clear_timer(:disconnect)
  set_disconnect_timer
end

#reset_heartbeat_timerObject



327
328
329
330
# File 'lib/sockjs/session.rb', line 327

def reset_heartbeat_timer
  clear_timer(:heartbeat)
  set_heartbeat_timer
end

#run_user_appObject



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/sockjs/session.rb', line 160

def run_user_app
  unless @received_messages.empty?
    reset_heartbeat_timer

    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



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

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

#set_close_timerObject



343
344
345
346
347
# File 'lib/sockjs/session.rb', line 343

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

#set_disconnect_timerObject



332
333
334
335
336
# File 'lib/sockjs/session.rb', line 332

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

#set_heartbeat_timerObject



319
320
321
322
323
324
325
# File 'lib/sockjs/session.rb', line 319

def set_heartbeat_timer
  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



287
288
289
290
291
292
293
# File 'lib/sockjs/session.rb', line 287

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