Class: Rage::Cable::Channel

Inherits:
Object
  • Object
show all
Defined in:
lib/rage/cable/channel.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.after_subscribe(action_name = nil, **opts, &block) ⇒ Object

Note:

This callback will be triggered even if the subscription was rejected with the #reject method.

Register a new after_subscribe hook that will be called after the #subscribed method.

Examples:

after_subscribe do
  ...
end
after_subscribe :my_method, unless: :subscription_rejected?


215
216
217
# File 'lib/rage/cable/channel.rb', line 215

def after_subscribe(action_name = nil, **opts, &block)
  add_action(:after_subscribe, action_name, **opts, &block)
end

.after_unsubscribe(action_name = nil, **opts, &block) ⇒ Object

Register a new after_unsubscribe hook that will be called after the #unsubscribed method.



225
226
227
# File 'lib/rage/cable/channel.rb', line 225

def after_unsubscribe(action_name = nil, **opts, &block)
  add_action(:after_unsubscribe, action_name, **opts, &block)
end

.before_subscribe(action_name = nil, **opts, &block) ⇒ Object

Register a new before_subscribe hook that will be called before the #subscribed method.

Examples:

before_subscribe :my_method
before_subscribe do
  ...
end
before_subscribe :my_method, if: -> { ... }


202
203
204
# File 'lib/rage/cable/channel.rb', line 202

def before_subscribe(action_name = nil, **opts, &block)
  add_action(:before_subscribe, action_name, **opts, &block)
end

.before_unsubscribe(action_name = nil, **opts, &block) ⇒ Object

Register a new before_unsubscribe hook that will be called before the #unsubscribed method.



220
221
222
# File 'lib/rage/cable/channel.rb', line 220

def before_unsubscribe(action_name = nil, **opts, &block)
  add_action(:before_unsubscribe, action_name, **opts, &block)
end

.broadcast_to(streamable, data) ⇒ Object

Broadcast data to all the clients subscribed to a channel-local stream.

Examples:

NotificationsChannel.broadcast_to(current_user, { message: "You have a new notification!" })

Parameters:

  • streamable (#id, String, Symbol, Numeric, Array) —

    an object that will be used to generate the stream name

  • data (Object) —

    the data to send to the clients

Raises:

  • (ArgumentError) —

    if the streamable object does not satisfy the type requirements



305
306
307
# File 'lib/rage/cable/channel.rb', line 305

def broadcast_to(streamable, data)
  Rage.cable.broadcast(__stream_name_for(streamable), data)
end

.periodically(method_name = nil, every:, &block) ⇒ Object

Set up a timer to periodically perform a task on the channel. Accepts a method name or a block.

Examples:

periodically every: 3.minutes do
  transmit({ action: :update_count, count: current_count })
end
periodically :update_count, every: 3.minutes

Parameters:

  • method_name (Symbol, nil) (defaults to: nil) —

    the name of the method to call

  • every (Integer) —

    the calling period in seconds



273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
# File 'lib/rage/cable/channel.rb', line 273

def periodically(method_name = nil, every:, &block)
  callback_name = if block_given?
    raise ArgumentError, "Pass the `method_name` argument or provide a block, not both" if method_name
    define_tmp_method(block)
  elsif method_name.is_a?(Symbol)
    define_tmp_method(eval("-> { #{method_name} }"))
  else
    raise ArgumentError, "Expected a Symbol method name, got #{method_name.inspect}"
  end

  unless every.is_a?(Numeric) && every > 0
    raise ArgumentError, "Expected every: to be a positive number of seconds, got #{every.inspect}"
  end

  callback = eval("->(channel) { channel.#{callback_name} }")

  if @__periodic_timers.nil?
    @__periodic_timers = []
  elsif @__periodic_timers.frozen?
    @__periodic_timers = @__periodic_timers.dup
  end

  @__periodic_timers << [callback, every]
end

.rescue_from(*klasses, with: nil, &block) ⇒ Object

Register an exception handler.

Examples:

rescue_from StandardError, with: :report_error

private

def report_error(e)
  SomeExternalBugtrackingService.notify(e)
end
rescue_from StandardError do |e|
  SomeExternalBugtrackingService.notify(e)
end

Parameters:

  • klasses (Class, Array<Class>) —

    exception classes to watch on

  • with (Symbol) (defaults to: nil) —

    the name of a handler method. The method can take one argument, which is the raised exception. Alternatively, you can pass a block, which can also take one argument.



245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/rage/cable/channel.rb', line 245

def rescue_from(*klasses, with: nil, &block)
  unless with
    if block_given?
      with = define_tmp_method(block)
    else
      raise ArgumentError, "No handler provided. Pass the `with` keyword argument or provide a block."
    end
  end

  if @__rescue_handlers.nil?
    @__rescue_handlers = []
  elsif @__rescue_handlers.frozen?
    @__rescue_handlers = @__rescue_handlers.dup
  end

  @__rescue_handlers.unshift([klasses, with])
end

Instance Method Details

#broadcast(stream, data) ⇒ Object

Broadcast data to all the clients subscribed to a stream.

Examples:

def subscribed
  broadcast("notifications", { message: "A new member has joined!" })
end

Parameters:

  • stream (String) —

    the name of the stream

  • data (Object) —

    the data to send to the clients



508
509
510
# File 'lib/rage/cable/channel.rb', line 508

def broadcast(stream, data)
  Rage.cable.broadcast(stream, data)
end

#params ⇒ Hash{Symbol=>String,Array,Hash,Numeric,NilClass,TrueClass,FalseClass}

Get the params hash passed in during the subscription process.

Returns:

  • (Hash{Symbol=>String,Array,Hash,Numeric,NilClass,TrueClass,FalseClass})


416
417
418
# File 'lib/rage/cable/channel.rb', line 416

def params
  @__params
end

#reject ⇒ Object

Reject the subscription request. The method should only be called during the subscription process (i.e. inside the #subscribed method or before_subscribe/after_subscribe hooks).



422
423
424
# File 'lib/rage/cable/channel.rb', line 422

def reject
  @__subscription_rejected = true
end

#stop_stream_for(streamable) ⇒ Object

Unsubscribe from a local stream. The counterpart to #stream_for.

Examples:

Unsubscribe from a model stream

class NotificationsChannel < Rage::Cable::Channel
  def unfollow(data)
    stop_stream_for User.find(data['user_id'])
  end
end

Parameters:

  • streamable (#id, String, Symbol, Numeric, Array) —

    an object that will be used to generate the stream name

Raises:

  • (ArgumentError) —

    if the streamable object does not satisfy the type requirements



496
497
498
# File 'lib/rage/cable/channel.rb', line 496

def stop_stream_for(streamable)
  stop_stream_from(self.class.__stream_name_for(streamable))
end

#stop_stream_from(stream) ⇒ Object

Unsubscribe from a global stream.

Examples:

Unsubscribe from a stream and subscribe to a new one

class ChatChannel < Rage::Cable::Channel
  def subscribed
    stream_from "chat_#{params[:room]}"
  end

  def switch_room(data)
    stop_stream_from "chat_#{params[:room]}"
    stream_from "chat_#{data['new_room']}"
  end
end

Parameters:

  • stream (String) —

    the name of the stream

Raises:

  • (ArgumentError) —

    if the stream name is not a String



481
482
483
484
# File 'lib/rage/cable/channel.rb', line 481

def stop_stream_from(stream)
  raise ArgumentError, "Stream name must be a String" unless stream.is_a?(String)
  Rage.cable.__protocol.unsubscribe(@__connection, stream, @__params)
end

#stream_for(streamable) ⇒ Object

Subscribe to a local stream. Local streams are associated with a specific channel instance and can be used to send data to the current channel only.

Examples:

Subscribe to a stream

class NotificationsChannel < Rage::Cable::Channel
  def subscribed
    stream_for current_user
  end
end

Broadcast to the stream

NotificationsChannel.broadcast_to(current_user, { message: "You have a new notification!" })

Parameters:

  • streamable (#id, String, Symbol, Numeric, Array) —

    an object that will be used to generate the stream name

Raises:

  • (ArgumentError) —

    if the streamable object does not satisfy the type requirements



462
463
464
# File 'lib/rage/cable/channel.rb', line 462

def stream_for(streamable)
  stream_from(self.class.__stream_name_for(streamable))
end

#stream_from(stream) ⇒ Object

Subscribe to a stream global stream. Global streams are not associated with any specific channel instance and can be used to broadcast data to multiple channels at once.

Examples:

Subscribe to a stream

class NotificationsChannel < Rage::Cable::Channel
  def subscribed
    stream_from "notifications"
  end
end

Broadcast to the stream

Rage::Cable.broadcast("notifications", { message: "A new member has joined!" })

Parameters:

  • stream (String) —

    the name of the stream

Raises:

  • (ArgumentError) —

    if the stream name is not a String



445
446
447
448
# File 'lib/rage/cable/channel.rb', line 445

def stream_from(stream)
  raise ArgumentError, "Stream name must be a String" unless stream.is_a?(String)
  Rage.cable.__protocol.subscribe(@__connection, stream, @__params)
end

#subscribed ⇒ Object

Called once a client has become a subscriber of the channel.



532
533
# File 'lib/rage/cable/channel.rb', line 532

def subscribed
end

#subscription_rejected? ⇒ Boolean

Checks whether the #reject method has been called.

Returns:

  • (Boolean)


429
430
431
# File 'lib/rage/cable/channel.rb', line 429

def subscription_rejected?
  !!@__subscription_rejected
end

#transmit(data) ⇒ Object

Transmit data to the current client.

Examples:

def subscribed
  transmit({ message: "Hello!" })
end

Parameters:

  • data (Object) —

    the data to send to the client



519
520
521
522
523
524
525
526
527
528
529
# File 'lib/rage/cable/channel.rb', line 519

def transmit(data)
  message = Rage.cable.__protocol.serialize(@__params, data)

  if @__is_subscribing
    # we expect a confirmation message to be sent as a result of a successful subscribe call;
    # this will make sure `transmit` calls send data after the confirmation;
    ::Iodine.defer { @__connection.write(message) }
  else
    @__connection.write(message)
  end
end

#unsubscribed ⇒ Object

Called once a client unsubscribes from the channel.



536
537
# File 'lib/rage/cable/channel.rb', line 536

def unsubscribed
end