Sinatra 使用 websocket 客户端响应 http 请求
Sinatra using a websocket client to respond to a http request
我正在编写一个 Sinatra Web 服务器,我希望它成为 RESTful,但问题是它必须与另一个仅通过 Web 套接字进行通信的服务器进行交互。所以,这需要发生:
- 一个请求从客户端进入我的 Sinatra 服务器
- 我的服务器打开一个到外部服务器的网络套接字
- 我的服务器异步等待来自外部服务器的消息和东西,直到套接字关闭(这应该只需要 200 毫秒左右)
- 我的服务器向客户端发回响应
我相信这不会太复杂,但我有点坚持不下去了。基本上,如果整个 Web 套接字逻辑可以包装在一个函数中,那么该函数就可以被阻塞,就是这样。但我不知道如何包装网络套接字逻辑并阻止它。你怎么看?下面是我得到的简化版本。
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
编辑
经过进一步思考,我意识到可以使用线程暂停和线程唤醒来完成此操作。这感觉相当复杂,我不确定如何使用 Ruby 正确地做到这一点,但这就是想法:
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
编辑 2
我又进步了。我现在正在使用 Async Sinatra gem, which requires the Thin 网络服务器。这是它的设置方式:
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
问题是,它仍然无法正常工作。它的控制台输出符合预期:
Request received
Connected to web socket
WS open
Sent: A nice message to process
Got message: blah blah blah
WS closed
但它没有将任何数据发送回客户端。 body 'Closed ...'
方法似乎没有任何效果。
问题在于 async-sinatra
正在使用自己的线程,websocket-client-simple
也是如此。解决方案是使用绑定和 eval
函数,尽管这根本不是很有效。希望能有优化或更好的解决方案。
require 'sinatra'
require 'sinatra/async'
require 'websocket-client-simple'
set :server, 'thin'
register Sinatra::Async
aget '/' do
puts 'Request received'
socketResponse('wss:// ... URL ...', binding)
end
def socketResponse(url, b)
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'
EM.schedule { b.eval " body 'Closed' " }
end
ws.on :open do
puts 'WS open'
message = 'A nice message to process'
ws.send message
puts 'Sent: ' + message
end
end
我正在编写一个 Sinatra Web 服务器,我希望它成为 RESTful,但问题是它必须与另一个仅通过 Web 套接字进行通信的服务器进行交互。所以,这需要发生:
- 一个请求从客户端进入我的 Sinatra 服务器
- 我的服务器打开一个到外部服务器的网络套接字
- 我的服务器异步等待来自外部服务器的消息和东西,直到套接字关闭(这应该只需要 200 毫秒左右)
- 我的服务器向客户端发回响应
我相信这不会太复杂,但我有点坚持不下去了。基本上,如果整个 Web 套接字逻辑可以包装在一个函数中,那么该函数就可以被阻塞,就是这样。但我不知道如何包装网络套接字逻辑并阻止它。你怎么看?下面是我得到的简化版本。
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
编辑
经过进一步思考,我意识到可以使用线程暂停和线程唤醒来完成此操作。这感觉相当复杂,我不确定如何使用 Ruby 正确地做到这一点,但这就是想法:
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
编辑 2
我又进步了。我现在正在使用 Async Sinatra gem, which requires the Thin 网络服务器。这是它的设置方式:
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
问题是,它仍然无法正常工作。它的控制台输出符合预期:
Request received
Connected to web socket
WS open
Sent: A nice message to process
Got message: blah blah blah
WS closed
但它没有将任何数据发送回客户端。 body 'Closed ...'
方法似乎没有任何效果。
问题在于 async-sinatra
正在使用自己的线程,websocket-client-simple
也是如此。解决方案是使用绑定和 eval
函数,尽管这根本不是很有效。希望能有优化或更好的解决方案。
require 'sinatra'
require 'sinatra/async'
require 'websocket-client-simple'
set :server, 'thin'
register Sinatra::Async
aget '/' do
puts 'Request received'
socketResponse('wss:// ... URL ...', binding)
end
def socketResponse(url, b)
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'
EM.schedule { b.eval " body 'Closed' " }
end
ws.on :open do
puts 'WS open'
message = 'A nice message to process'
ws.send message
puts 'Sent: ' + message
end
end