2017-08-31 91 views
9

我正在编写一个Sinatra Web服务器,我想成为RESTful,但事情是它必须与另一台通过Web套接字进行通信的服务器进行交互。所以,这需要发生:Sinatra使用WebSocket客户端来响应http请求

  1. 一个请求进入我的末日服务器从客户
  2. 我的服务器打开一个网络套接字连接到国外服务器
  3. 我的服务器异步等待来自国外的消息,事情服务器,直到关闭套接字(这应该只需要两百元左右毫秒)
  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 

编辑

进一步的思考后,我意识到,一种方式,这可能会使用一个线程停止和线程唤醒来完成。这种感觉相当精巧,我不知道如何使用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 

EDIT 2

我已经取得了进一步进展。我现在使用的是Async Sinatra宝石,它需要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 ...'似乎没有任何效果。

+1

旁注:在您的问题建议的设计是适得其反,性能沉重。只要应用程序运行,保持WebSocket连接始终处于打开状态更有意义。这就是websockets的重点 - 维持持续的连接。 – Myst

+0

这不是我真正的代码,而只是写出来的最简单的方式,我可以想象它来演示问题。但是,谢谢你,这是一个很好的提示。 – tschwab

+0

只是为了澄清,你不希望网页加载后,直到网络套接字代码运行?你也说它应该是异步的,所以我很困惑。您可以在路由中使用异步函数,因为路由将返回而不包含异步方法的任何信息。 – Cereal

回答

0

问题是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 
相关问题