4

I want to send a

"Keep alive from client"

message every 30 seconds for my websocket connection. Here's what the code that I have in my websocket initializer looks like:

ws = WebSocket::Client::Simple.connect 'wss://bitcoin.toshi.io/'

ws.on :message do |msg|
  rawJson = msg.data
  message_response = JSON.parse(rawJson)
end

ws.on :open do
  ws.send "{\"subscribe\":\"blocks\"}"
end

ws.on :close do |e|
  puts "WEBSOCKET HAS CLOSED #{e}"
  exit 1
end

ws.on :error do |e|
  puts "WEBSOCKET ERROR #{e}"
end

Without any sort of 'keep alive', the connect closes in about 45 seconds. How should I send the 'heart-beat' packet? It seems that the connection is closed by their server, not mine.

Skull1234567
  • 73
  • 12
  • possible duplicate of [Keeping the WebSocket connection alive](http://stackoverflow.com/questions/8218936/keeping-the-websocket-connection-alive) – Brad Werth Aug 04 '15 at 21:24
  • It's similar, but a different issue. I'm having trouble specifically with toshi cutting the connection due to the lack of a response -- if they did not have this behavior, the connection would be solid. I can keep the connection alive if I periodically send a message that says I'm still listening. – Skull1234567 Aug 04 '15 at 21:32

2 Answers2

2

You can use Websocket Eventmachine Client gem to send hearbeat:

require 'websocket-eventmachine-client'

EM.run do
  ws = WebSocket::EventMachine::Client.connect(:uri => 'wss://bitcoin.toshi.io/')
  puts ws.comm_inactivity_timeout
  ws.onopen do
    puts "Connected"
  end

  ws.onmessage do |msg, type|
    puts "Received message: #{msg}"
  end

  ws.onclose do |code, reason|
    puts "Disconnected with status code: #{code}"
  end

  EventMachine.add_periodic_timer(15) do
    ws.send "{}"
  end
end

You can setup timer for EventMachine with EM::add_periodic_timer(interval_in_seconds), and then send your heartbeat with it.

EugZol
  • 6,476
  • 22
  • 41
  • I can get it to work up until including `EventMachine.next_tick`, I end up getting `error code 1002`. What do you mean when you say I can check the current time in `#next_tick`? – Skull1234567 Aug 05 '15 at 01:32
  • @Skull1234567 I fixed my answer. You actually should use `#add_periodic_timer` instead of `#next_tick` – now it works. – EugZol Aug 05 '15 at 07:49
  • How to I close this connection and how do I stop the periodic timer? – bonafernando Jul 16 '20 at 15:44
2

You can use the auto-ping feature (its default and can't be turned off) if you're using Iodine's Websocket client:

require 'iodine/http'
# prevents the Iodine's server from running
Iodine.protocol = :timer
# starts Iodine while the script is still running
Iodine.force_start!
# set pinging to a 40 seconds interval.
Iodine::Http::Websockets.default_timeout = 40

settings = {}
# set's the #on_open event callback.
settings[:on_open] = Proc.new do
    write 'sending this connection string.'
end
# set's the #on_message(data) event callback.
settings[:on_message] = Proc.new { |data| puts "Received message: #{data}" }
# connects to the websocket
Iodine::Http.ws_connect 'ws://localhost:8080', settings

It's a fairly basic client, but also easy to manage.

EDIT

Iodine also includes some cookie and custom header's support, as now seen in Iodine's documentation. So it's possible to use different authentication techniques (authentication headers or cookies).

Myst
  • 18,516
  • 2
  • 45
  • 67
  • Sorry if it is a newbie question, but how do I send a `ws.send "{\"subscribe\":\"blocks\"}"` type message with this once it has been connected? – Skull1234567 Aug 05 '15 at 02:47
  • @Skull1234567 - No worries. I updated my answer. You use the websocket object (event object) to send data or close the connection. You can find the documentation for the [Websocket event object here](http://www.rubydoc.info/github/boazsegev/GRHttp/master/GRHttp/WSEvent). – Myst Aug 05 '15 at 03:10