Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interactive client that processes user input? #135

Closed
dtonon opened this issue Nov 17, 2022 · 2 comments
Closed

Interactive client that processes user input? #135

dtonon opened this issue Nov 17, 2022 · 2 comments

Comments

@dtonon
Copy link

dtonon commented Nov 17, 2022

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
Copy link
Collaborator

jcoglan commented Nov 18, 2022

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

  • Run EventMachine and the STDIN interaction in different threads, so that the STDIN read does not block the event loop
  • Find an EventMachine-friendly library for interacting with STDIN -- it might even have its own functions for doing this
  • Use a non-EM-based WebSocket library; for the example the underlying protocol library for this package, which is https://github.com/faye/websocket-driver-ruby, which is not tied to any particular concurrency/IO model

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
Copy link
Author

dtonon commented Nov 20, 2022

@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)
}

@dtonon dtonon closed this as completed Nov 20, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants