2017-08-31 12 views
9

私はRESTfulになりたいSinatra Webサーバーを作成していますが、それはWebソケット経由で通信する別のサーバーと対話しなければならないことです。だから、これは起こる必要があります:SinatraがHTTPリクエストに応答するためにwebsocketクライアントを使用

  1. 要求が私のサーバが外部サーバへのWebソケットを開き
  2. クライアントからの私のシナトラサーバーに入ってくる
  3. 私のサーバが非同期的に外国からのメッセージや物事を待ち
  4. ソケットが閉じられるまで、サーバーが
  5. 私のサーバがクライアントに応答を返す(これが唯一の200かそこらミリ秒を取る必要があります)

私は、これは達成するにはあまりにも複雑ではありません確信しているが、私はちょっとそれに固執しています。基本的には、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 

EDIT

さらに考えた後、私は、これはスレッド停止とスレッドウェイクアップを使用して行われるかもしれないというやり方ことに気づきました。これはかなり精巧な感じ、と私は、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 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 

問題はまだありません。そのコンソール出力は期待どおりです:

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接続を開いたままにしておく方が理にかなっています。それがウェブソケットの全ポイントです。永続的な接続を維持しています。 – 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 
関連する問題