I am writing a Sinatra web server that I would like to be RESTful, but the thing is that it has to interact with another server that communicates exclusively via web sockets. So, this needs to happen:
- A request comes into my Sinatra server from a client
- My server opens a web socket to the foreign server
- My server asynchronously waits for messages and things from the foreign server until the socket is closed (this should only take two hundred or so milliseconds)
- My server sends back a response to client
I'm sure this is not too complicated to accomplish, but I'm a bit stuck on it. Basically, if the entire web socket logic can be wrapped in a single function, then that function could be made to be blocking, and that'd be that. But I don't know how to wrap the web socket logic and block it. What do you think? A simplified version of what I've got is below.
require 'sinatra'
require 'websocket-client-simple'
get '/' do
ws = WebSocket::Client::Simple.connect(' ws://URL... ')
ws.on :message do
puts 'bar'
end
ws.on :close do
# At this point we need to send an HTTP response back to the client. But how?
end
ws.on :open do
ws.send 'foo'
end
end
EDIT
After further thought, I realized that a way that this might be done using a thread halt and a thread wake up. This feels rather elaborate, and I'm not sure how to do this correctly with Ruby, but this is the idea:
require 'sinatra'
require 'websocket-client-simple'
get '/' do
socketResponse('wss:// ... URL ...')
'Got a response from the web socket server!'
end
def socketResponse(url)
thread = Thread.new do
ws = WebSocket::Client::Simple.connect(url)
ws.on :message do
puts 'bar'
# Maybe store each response in a thread-safe array to retrieve later or something
end
ws.on :close do
thread.run
end
ws.on :open do
ws.send 'foo'
end
Thread.stop
end
end
EDIT 2
I have made further progress. I am now using the Async Sinatra gem, which requires the Thin web server. This is how it is set up:
require 'sinatra'
require 'sinatra/async'
require 'websocket-client-simple'
set :server, 'thin'
register Sinatra::Async
aget '/' do
puts 'Request received'
socketResponse('wss:// ... URL ...')
end
def socketResponse(url)
ws = WebSocket::Client::Simple.connect(url)
puts 'Connected to web socket'
ws.on :message do |message|
puts 'Got message:' + message.to_s
end
ws.on :close do
puts 'WS closed'
body 'Closed ...'
end
ws.on :open do
puts 'WS open'
message = 'A nice message to process'
ws.send message
puts 'Sent: ' + message
end
end
The thing is, it still isn't working. Its console output is as expected:
Request received
Connected to web socket
WS open
Sent: A nice message to process
Got message: blah blah blah
WS closed
But it is not sending any data back to the client. The body 'Closed ...'
method does not seem to have any effect.
socketResponse()
, should block until the WS closes. That is the problem. – Eugenioeugenius