2017-08-31 25 views
9

का जवाब देने के लिए एक वेबसाईट क्लाइंट का उपयोग करके सिनात्रा, मैं एक सिनात्रा वेब सर्वर लिख रहा हूं जिसे मैं रीस्टफुल करना चाहता हूं, लेकिन बात यह है कि इसे किसी अन्य सर्वर से बातचीत करना है जो विशेष रूप से वेब सॉकेट के माध्यम से संचार करता है। तो, यह तो होना ही चाहिए:http अनुरोध

  1. एक अनुरोध एक ग्राहक से मेरी सिनात्रा सर्वर में आता है
  2. मेरे सर्वर विदेशी सर्वर के लिए एक वेब सॉकेट खोलता
  3. मेरे सर्वर एसिंक्रोनस रूप से विदेशी से संदेश और बातों के लिए इंतजार कर रहा है सर्वर जब तक सॉकेट बंद कर दिया है (यह केवल दो सौ या तो मिलीसेकेंड लेना चाहिए)
  4. मेरे सर्वर क्लाइंट के लिए एक प्रतिक्रिया वापस भेजता है

मुझे यकीन है यह भी पूरा करने के लिए जटिल नहीं है कर रहा हूँ लेकिन मैं उस पर थोड़ा फंस गया हूँ। असल में, यदि पूरे वेब सॉकेट तर्क को एक ही फ़ंक्शन में लपेटा जा सकता है, तो उस फ़ंक्शन को अवरुद्ध करने के लिए बनाया जा सकता है, और वह वह होगा। लेकिन मुझे नहीं पता कि वेब सॉकेट तर्क को कैसे लपेटें और इसे अवरुद्ध करें। तुम क्या सोचते हो? मुझे जो मिला है उसका सरलीकृत संस्करण नीचे है।

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 

संपादित

आगे सोचा के बाद, मुझे एहसास हुआ कि एक तरह से यह एक धागा पड़ाव और एक धागा जगाने का उपयोग किया जा सकता है। इस बल्कि विस्तृत लगता है, और मैं कैसे रूबी के साथ सही ढंग से ऐसा करने के लिए यकीन नहीं है, लेकिन यह विचार है:

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 मणि का उपयोग कर रहा हूं, जिसके लिए वेब सर्वर की आवश्यकता है। इस प्रकार यह स्थापित किया गया है:

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

सिडेनोटे: आपके प्रश्न में सुझाए गए डिज़ाइन प्रति-उत्पादक और प्रदर्शन भारी हैं। जब तक आपका एप्लिकेशन चल रहा है, तब तक वेबस्केट कनेक्शन को खुले रखने में अधिक समझदारी होती है। यह वेबसाइकिलों का पूरा बिंदु है - लगातार कनेक्शन बनाए रखना। – Myst

+0

यह मेरा असली कोड नहीं है, लेकिन इसे लिखने का सबसे आसान तरीका है कि मैं समस्या का प्रदर्शन करने के बारे में सोच सकता हूं। लेकिन धन्यवाद, यह एक अच्छी टिप है। – tschwab

+0

बस स्पष्ट करने के लिए, आप वेब सॉकेट कोड चलाने के बाद पृष्ठ लोड नहीं करना चाहते हैं? आप यह भी कहते हैं कि यह async होना चाहिए, इसलिए मैं उलझन में हूँ। आपके पास रूट के अंदर एसिंक फ़ंक्शन हो सकता है, क्योंकि मार्ग एसिंक विधि से किसी भी जानकारी के बिना वापस आ जाएगा। – 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