Стратегия построения системы talk-to-talk с использованием em-websocket в рельсах?
Может быть, это хороший пример для системы push сервера. В системе много пользователей, и пользователи могут общаться друг с другом. Это может быть выполнено следующим образом: один пользователь отправляет сообщение (через веб-сокет) на сервер, а затем сервер пересылает сообщение другому пользователю. Ключ должен найти связь между ws (объект websocket) и пользователем. Пример кода, как показано ниже:
EM.run {
EM::WebSocket.run(:host => "0.0.0.0", :port => 8080, :debug => false) do |ws|
ws.onopen { |handshake|
# extract the user id from handshake and store the binding between user and ws
}
ws.onmessage { |msg|
# extract the text and receiver id from msg
# extract the ws_receiver from the binding
ws_receiver.send(text)
}
end
}
Я хочу выяснить следующие вопросы:
ws
объект может быть сериализован, так что он может быть сохранен на диске или в базе данных? В противном случае я могу только сохранить привязку в памяти.В чем разница между em-websocket и websocket-rails?
Какой драгоценный камень вы рекомендуете для веб-сокета?
2 ответа
Следующее является дополнением к краткому ответу Чейза Гиллиама, который включал ссылки на em-websocket, websocket-rails (которые давно не поддерживались), faye-websocket-rails и ActionCable.
Я бы порекомендовал каркас Plezi. Он работает как в качестве независимой инфраструктуры приложений, так и в качестве усовершенствования Rails Websocket.
Я бы также рассмотрел следующие вопросы:
Вам нужно, чтобы сообщение сохранялось между соединениями (т. е. если другой пользователь находится в автономном режиме, должно ли сообщение ждать в "окне сообщения"? Как долго должно ждать сообщение?)...?
Вы хотите сохранить историю сообщений?
Эти пункты помогут вам решить, использовать ли постоянное хранилище (то есть базу данных) для сообщений или нет.
то есть, чтобы использовать Plezi с Rails, создайте init_plezi.rb
в вашем приложении config/initializers
папка. используйте (в качестве примера) следующий код:
class ChatDemo
# use JSON events instead of raw websockets
@auto_dispatch = true
protected #protected functions are hidden from regular Http requests
def auth msg
@user = User.auth_token(msg['token'])
return close unless @user
# creates a websocket "mailbox" that will remain open for 9 hours.
register_as @user.id, lifetime: 60*60*9, max_connections: 5
end
def chat msg, received = false
unless @user # require authentication first
close
return false
end
if received
# this is only true when we sent the message
# using the `broadcast` or `notify` methods
write msg # writes to the client websocket
end
msg['from'] = @user.id
msg['time'] = Plezi.time # an existing time object
unless msg['to'] && registered?(msg['to'])
# send an error message event
return {event: :err, data: 'No recipient or recipient invalid'}.to_json
end
# everything was good, let's send the message and inform
# this will invoke the `chat` event on the other websocket
# notice the `true` is setting the `received` flag.
notify msg['to'], :chat, msg, true
# returning a String will send it to the client
# when using the auto-dispatch feature
{event: 'message_sent', msg: msg}.to_json
end
end
# remember our route for websocket connections.
route '/ws_chat', ChatDemo
# a route to the Javascript client (optional)
route '/ws/client.js', :client
Plezi устанавливает свой собственный сервер (Iodine, сервер Ruby), поэтому не забудьте удалить из своего приложения любые ссылки на puma
, thin
или любой другой пользовательский сервер.
На стороне клиента вы можете использовать помощник Javascript, предоставляемый Plezi (это необязательно)... добавить:
<script src='/es/client.js' />
<script>
TOKEN = <%= @user.token %>;
c = new PleziClient(PleziClient.origin + "/ws_chat") // the client helper
c.log_events = true // debug
c.chat = function(event) {
// do what you need to print a received message to the screen
// `event` is the JSON data. i.e.: event.event == 'chat'
}
c.error = function(event) {
// do what you need to print a received message to the screen
alert(event.data);
}
c.message_sent = function(event) {
// invoked after the message was sent
}
// authenticate once connection is established
c.onopen = function(event) {
c.emit({event: 'auth', token: TOKEN});
}
// // to send a chat message:
// c.emit{event: 'chat', to: 8, data: "my chat message"}
</script>
Я не проверял реальный код сообщения, потому что это просто скелет, а также для него требуется приложение Rails с User
модель и token
что я не хотел редактировать, чтобы просто ответить на вопрос (без обид).
Вы подходите к варианту использования, для которого очень хороши веб-сокеты, поэтому вы на правильном пути.
- Вы могли бы сериализовать
ws
возьмите объект с Marshal, но воспринимайте объекты websocket как нечто, похожее на объекты http-запроса, поскольку они являются абстракциями для какого-либо типа связи. Вы, вероятно, лучше всего маршалинг / хранение данных. - em-websocket - это библиотека веб- сокетов с более низким (ish) рычагом, построенная более или менее непосредственно на веб-машине. websocket-rails - это абстракция более высокого уровня для веб-сокетов, с множеством встроенных хороших инструментов и довольно хороших документов. Он построен поверх faye-websocket-rails, который сам построен на веб-машине. * Обратите внимание, кабель действий, который является новой библиотекой веб-сокетов для Rails 5, построен на faye.
- В прошлом я использовал рельсы для веб-розеток и мне это нравилось. Это многое о вас позаботится. Однако, если вы можете использовать Rails 5 и Action Cable, сделайте это, это будущее.