faye / faye-websocket-ruby

Standards-compliant WebSocket client and server
Other
1.03k stars 97 forks source link

Interactive client that processes user input? #135

Closed dtonon closed 1 year ago

dtonon commented 1 year ago

Hi, I would like to create a client that reads the user input in console and sends it to the server; I did some tests with STDIN.gets inside a loop, plain, within a thread and with EM.tick_loop, but I was unable to achieve the desidered result. Is there any best pratice / code example around?

Bonus point: the client should reconnect on lost network; this could make the things trickyer as I found experimenting with the websocket-client-simple gem.

Thanks! :)

jcoglan commented 1 year ago

I have not implemented anything like this, but my best guess is you need to do one of the following:

Making a WebSocket client automatically reconnect is not a good idea as the protocol provides no application-level support for this and it can result in lost messages. You need to implement this in the application layer.

dtonon commented 1 year ago

@jcoglan thank you for the suggestions, you point me on the right direction. I was able to solve using a channel, an example code follows. I don't know if it is the best solution, I have to battle test it, but for a quick working prototype it's fine.

require 'faye/websocket'
require 'eventmachine'

relay_host = "wss://127.0.0.1"

def relay_connect(relay_host)

  ws = Faye::WebSocket::Client.new(relay_host, nil, {ping: 60})
  sid = nil

  ws.on :open do |event|
    puts "---------- Open -----------------\n#{event.inspect}\n\n"
    sid = @channel.subscribe { |msg| ws.send build_event(msg) }
  end

  ws.on :message do |event|
    puts "---------- Event -----------------\n#{event.inspect}\n\n"
    # ....
  end

  ws.on :error do |event|
    puts "---------- Error -----------------\n#{event.inspect}\n\n"
    # .....
  end

  ws.on :close do |event|
    puts "---------- Close -----------------\n#{event.inspect}\n\n"
    puts "Reconnecting..."
    sleep(5)
    @channel.unsubscribe(sid)
    relay_connect(relay_host)
  end

end

EM.run {
  @channel = EM::Channel.new

  Thread.new {
    loop do
      @channel.push STDIN.gets.strip
    end
  }

  relay_connect(relay_host)
}