Module: Rage::Cable

Defined in:
lib/rage/cable/cable.rb

Overview

Rage::Cable provides built-in WebSocket support for Rage apps, similar to Action Cable in Rails. It lets you mount a separate WebSocket application, define channels and connections, subscribe clients to named streams, and broadcast messages in real time.

Define a channel:

class ChatChannel < Rage::Cable::Channel
  def subscribed
    stream_from "chat"
  end

  def receive(data)
    puts "Received message: #{data['message']}"
  end
end

Mount the Cable application:

Rage.routes.draw do
  mount Rage::Cable.application, at: "/cable"
end

Broadcast a message to a stream:

Rage.cable.broadcast("chat", { message: "Hello, world!" })

Defined Under Namespace

Modules: Protocols, RemoteDisconnect Classes: Channel, Connection, Router, WebSocketConnection

Constant Summary collapse

Protocol =
Protocols

Class Method Summary collapse

Class Method Details

.application(namespace: Object, protocol: nil) ⇒ Object

Create a new Cable application.

Examples:

map "/cable" do
  run Rage.cable.application
end


41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/rage/cable/cable.rb', line 41

def self.application(namespace: Object, protocol: nil)
  unless namespace.is_a?(Module)
    raise ArgumentError, "The `namespace` option must be a Module, got #{namespace.class}."
  end

  protocol = __protocol_for(protocol || Rage.config.cable.protocol)

  unless __protocols.include?(protocol)
    __protocols << protocol.tap(&:init)
    @__adapter&.add_broadcaster(PUBSUB_BROADCASTER_ID, Relay)
  end

  router = Router.new(protocol, namespace)
  handler = __build_handler(protocol, router)
  accept_response = [101, protocol.protocol_definition, []]

  application = ->(env) do
    Rage::Telemetry.tracer.span_cable_websocket_handshake(env:) do
      if env["HTTP_UPGRADE"] == "websocket" || env["HTTP_UPGRADE"]&.downcase == "websocket"
        env["rack.upgrade?"] = :websocket
        env["rack.upgrade"] = handler
        accept_response
      else
        [426, { "connection" => "upgrade", "upgrade" => "websocket" }, []]
      end
    end
  end

  chain = Rage.with_middlewares(application, Rage.config.cable.middlewares)

  chain.define_singleton_method(:__rage_root_app) do
    root_app = Rage.with_middlewares(application, Rage.config.cable.middlewares(include_http_middleware: false))
    root_app.define_singleton_method(:__rage_app_name) do
      namespace == Object ? "Rage::Cable" : "Rage::Cable(namespace: #{namespace})"
    end

    root_app
  end

  chain
end

.broadcast(stream, data) ⇒ true

Broadcast data directly to a named stream.

Examples:

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

Parameters:

  • stream (String) —

    the name of the stream

  • data (Object) —

    the object to send to the clients. This will later be encoded according to the protocol used.

Returns:

  • (true)


196
197
198
199
200
201
202
203
# File 'lib/rage/cable/cable.rb', line 196

def self.broadcast(stream, data)
  Rage::Telemetry.tracer.span_cable_stream_broadcast(stream:) do
    Relay.broadcast(stream, data)
    @__adapter&.publish(PUBSUB_BROADCASTER_ID, stream, data)
  end

  true
end