Sinatra使用websocket客户端来响应http请求

tsc*_*wab 9 rest asynchronous thin sinatra websocket

我正在编写一个我想成为RESTful的Sinatra Web服务器,但问题是它必须与另一个通过Web套接字进行通信的服务器进行交互.所以,这需要发生:

  1. 请求从客户端进入我的Sinatra服务器
  2. 我的服务器打开外部服务器的Web套接字
  3. 我的服务器异步等待来自外部服务器的消息和东西,直到套接字关闭(这应该只需要大约200毫秒)
  4. 我的服务器向客户端发回响应

我确信这不是太复杂,但我有点卡在上面.基本上,如果整个Web套接字逻辑可以包装在单个函数中,那么该函数可以被阻塞,那就是那样.但我不知道如何包装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
Run Code Online (Sandbox Code Playgroud)

编辑

经过深思熟虑后,我意识到这可以通过线程停止和线程唤醒来实现.这感觉相当复杂,我不知道如何正确地使用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
Run Code Online (Sandbox Code Playgroud)

编辑2

我取得了进一步的进展.我现在正在使用Async Sinatra gem,它需要Thin Web服务器.这就是它的设置方式:

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
Run Code Online (Sandbox Code Playgroud)

问题是,它仍然无法正常工作.它的控制台输出如预期:

Request received
Connected to web socket
WS open
Sent: A nice message to process
Got message: blah blah blah
WS closed
Run Code Online (Sandbox Code Playgroud)

但它不会将任何数据发送回客户端.该body 'Closed ...'方法似乎没有任何影响.

tsc*_*wab 1

问题在于它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
Run Code Online (Sandbox Code Playgroud)