Class: Rage::Cable::Protocols::RawWebSocketJson

Inherits:
Base
  • Object
show all
Defined in:
lib/rage/cable/protocols/raw_web_socket_json.rb

Overview

The RawWebSocketJson protocol allows a direct connection to a Rage::Cable application using the native WebSocket object. With this protocol, each WebSocket connection directly corresponds to a single channel subscription. As a result, clients are automatically subscribed to a channel as soon as they establish a connection.

Heartbeats are also supported - the server will respond with pong to every ping message. Additionally, all ping messages are buffered and processed once a second, which means it can take up to a second for the server to respond to a ping.

Examples:

Server side

class TodoItemsChannel
  def subscribed
    stream_from "todo-items-#{params[:user_id]}"
  end

  def receive(data)
    puts "New Todo item: #{data}"
  end
end

Client side

socket = new WebSocket("ws://localhost:3000/cable/todo_items?user_id=123")
socket.send(JSON.stringify({ item: "New Item" }))

See Also:

Class Method Summary collapse

Methods inherited from Base

broadcast, protocol_definition

Class Method Details

.init(router) ⇒ Object



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/rage/cable/protocols/raw_web_socket_json.rb', line 47

def self.init(router)
  super

  @ping_connections = Set.new

  Iodine.on_state(:on_start) do
    Iodine.run_every(1_000) do
      @ping_connections.each_slice(500) do |slice|
        Iodine.defer { slice.each { |connection| connection.write("pong") } }
      end

      @ping_connections.clear
    end
  end
end

.on_close(connection) ⇒ Object



120
121
122
# File 'lib/rage/cable/protocols/raw_web_socket_json.rb', line 120

def self.on_close(connection)
  @router.process_disconnection(connection)
end

.on_message(connection, raw_data) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/rage/cable/protocols/raw_web_socket_json.rb', line 105

def self.on_message(connection, raw_data)
  if raw_data == "ping"
    @ping_connections << connection
    return
  end

  data = JSON.parse(raw_data)

  message_status = @router.process_message(connection, IDENTIFIER, :receive, data)
  unless message_status == :processed
    connection.write(MESSAGES::UNKNOWN)
  end
end

.on_open(connection) ⇒ Object



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/rage/cable/protocols/raw_web_socket_json.rb', line 64

def self.on_open(connection)
  accepted = @router.process_connection(connection)

  unless accepted
    connection.write(MESSAGES::UNAUTHORIZED)
    connection.close
    return
  end

  channel_id = connection.env["PATH_INFO"].split("/")[-1]

  channel_name = if channel_id.end_with?("Channel")
    channel_id
  else
    if channel_id.include?("_")
      tmp = ""
      channel_id.split("_") { |segment| tmp += segment.capitalize! || segment }
      channel_id = tmp
    else
      channel_id.capitalize!
    end

    "#{channel_id}Channel"
  end

  query_string = connection.env["QUERY_STRING"]
  params = query_string == "" ? DEFAULT_PARAMS : Iodine::Rack::Utils.parse_nested_query(query_string)

  status = @router.process_subscription(connection, IDENTIFIER, channel_name, params)

  if status == :rejected
    connection.write(MESSAGES::REJECTED)
    connection.close
  elsif status == :invalid
    connection.write(MESSAGES::INVALID)
    connection.close
  end
end

.serialize(_, data) ⇒ Object



125
126
127
# File 'lib/rage/cable/protocols/raw_web_socket_json.rb', line 125

def self.serialize(_, data)
  data.to_json
end

.supports_rpc?Boolean



130
131
132
# File 'lib/rage/cable/protocols/raw_web_socket_json.rb', line 130

def self.supports_rpc?
  false
end