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

#paramsHash{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

#rejectObject

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

#subscribedObject

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

#unsubscribedObject

Called once a client unsubscribes from the channel.



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

def unsubscribed
end