imanel / websocket-eventmachine-client

WebSocket client for Ruby

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Proper EM reconnect support

MmKolodziej opened this issue · comments

Hey,
I've been having trouble while trying to setup proper reconnecting using your gem (using it through action_cable_client, but I believe that's irrelevant). Anyway, event machine supports reconnecting, but the method is not exposed in WebSocket::EventMachine::Client and due to this: eventmachine/eventmachine#218 implementing it is not straight forward.

This is what I've had to do in order to get stable reconnects:

require 'websocket-eventmachine-client'

EventMachine.run do
  ws = WebSocket::EventMachine::Client.connect(uri: 'ws://localhost:3000/websocket')

  ws.onclose do |code, reason|
    puts "Disconnected with status code: #{code}"
    EM.add_timer(2) do
      EventMachine.reconnect "localhost", 3000, ws
      ws.post_init
    end
  end
end

It should be pretty easy to remember the host and port and implement a simple reconnect method that will take care of firing post_init callback for the user. Let me know if this is something you'd like to see in your gem, I'll prepare a PR.

Sounds awesome, I would love to see it implemented.

@MmKolodziej did you make any progress on this?

here is my solution on this matter:

require 'websocket-eventmachine-client'
require 'forwardable'
require 'json'

class Websocket
  extend Forwardable

  ATTR_READER = %i[
    _websocket_client _uri _subscribed connection_tries
  ]

  ATTR_WRITER = %i[
    _subscribed connection_tries
  ]

  attr_reader *ATTR_READER

  attr_writer *ATTR_WRITER

  def initialize(uri:, params:, connect_on_start: true, headers: {}, tls: {})
    @_uri = uri
    @connection_tries = 0
    @_subscribed = false
    # @_message_factory = MessageFactory.new(params)
    @_websocket_client = WebSocket::EventMachine::Client.connect(uri: @_uri, headers: headers, tls: tls)

    connect!(headers, tls) if connect_on_start
  end

  def connect!(headers = {}, tls = {})
    _websocket_client.onopen do
      self.connection_tries += 1
      puts "Connected"
      puts "Connection attempt #{connection_tries}"
    end

    _websocket_client.onclose do |code, reason|
      puts "Disconnected with status code: #{code}"
      self._subscribed = false
      _disconnected_callback&.call
    end

    _websocket_client.onmessage do |msg, type|
      if msg.include?('disconnect')
        message = JSON.parse(msg)
        if message['reconnect'] == true
          puts "reconnecting to server please wait..."
          EM.add_timer(3) do
            EventMachine.reconnect "app.example.dev", 443, _websocket_client
            _websocket_client.post_init
          end
        else
          puts "proceeding to disconnect"
        end
      else
        puts "Received message: #{msg}"
      end
    end
  end
end

# Then we can use it by calling it like this
EventMachine.run do
  uri = "wss://app.example.dev/cable"
  client = Websocket.new(uri: uri, params: 'ClientUserChannel', headers: {
    'Authorization' => "Token token=#{token}" # If needed
  })
end