Sinatra использует клиент websocket для ответа на запрос http

125
10

Я пишу веб-сервер Sinatra, который хотел бы быть RESTful, но дело в том, что он должен взаимодействовать с другим сервером, который общается исключительно через веб-сокеты. Итак, это должно произойти:


    Запрос приходит на мой сервер Sinatra с клиента
    Мой сервер открывает веб-сокет на чужом сервере
    Мой сервер асинхронно ожидает сообщений и вещей от внешнего сервера до тех пор, пока сокет не будет закрыт (это займет всего две сотни миллисекунд).
    Мой сервер отправляет ответ клиенту

Я уверен, что это не слишком сложно сделать, но я немного застрял на нем. В принципе, если всю логику веб-сокета можно обернуть в одну функцию, тогда эта функция может быть заблокирована, и это будет так. Но я не знаю, как обернуть логику сетевого сокета и заблокировать его. Как вы думаете? Ниже приведена упрощенная версия того, что у меня есть.


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, для которого требуется 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 ...' не имеет никакого эффекта.

спросил(а) 2017-08-31T21:18:00+03:00 3 года назад
1
Решение
70

Проблема заключалась в том, что 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

ответил(а) 2017-10-25T22:39:00+03:00 2 года, 11 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема