Rails 怎样使用 websocket 建立 one to one 的聊天,类似 ruby-china 的推送

flowerwrong · 2014年11月03日 · 最后由 maolan 回复于 2017年11月06日 · 12 次阅读

我最近在学习 websocket-rails (https://github.com/websocket-rails/websocket-rails), 可以用来建立多人聊天室,但是不知道怎么建立one to one的聊天,类似qq的私人聊天, 我没有找到相关的api. 请指点下,谢谢.


socket.io我也看了下,他有提供private message这个event,可以监听fromto.


ruby-china的通知机制也类似,推送到个人. 于是我参考了ruby-china的代码,发现是用的faye-rails (https://github.com/jamesotron/faye-rails).

主要逻辑如下:
服务器:
# https://github.com/ruby-china/ruby-china/blob/master/app/models/notification/base.rb#L20
# coding: utf-8
class Notification::Base
  store_in collection: 'notifications'

  field :read, default: false
  belongs_to :user

  index read: 1
  index user_id: 1, read: 1

  scope :unread, -> { where(read: false) }

  after_create :realtime_push_to_client
  after_update :realtime_push_to_client

  def realtime_push_to_client
    if self.user
      hash = self.notify_hash
      hash[:count] = self.user.notifications.unread.count
      FayeClient.send("/notifications_count/#{self.user.temp_access_token}", hash) # 注意self.user.temp_access_token 和 FayeClient
    end
  end
end

# https://github.com/ruby-china/ruby-china/blob/55a3b35d9bd3db028221a4b6470a2f4e04c802dd/app/models/faye_client.rb
# faye_client.rb
require 'net/http'
class FayeClient
  def self.send(channel, params)
    Thread.new {
      params[:token] = Setting.faye_token
      message = {channel: channel, data: params}
      uri = URI.parse(Setting.faye_server)
      Net::HTTP.post_form(uri, message: message.to_json)
    }
  end
end

# user model
def temp_access_token
  Rails.cache.fetch("user-#{self.id}-temp_access_token-#{Time.now.strftime("%Y%m%d")}") do
    SecureRandom.hex
  end
end
客户端:
initNotificationSubscribe : () ->
  return if not App.access_token?
  faye = new Faye.Client(App.faye_client_url)
  faye.subscribe "/notifications_count/#{App.access_token}", (json) ->
    span = $("#user_notifications_count span")
    new_title = document.title.replace(/^\(\d+\) /,'')
    if json.count > 0
      span.addClass("badge-error")
      new_title = "(#{json.count}) #{new_title}"
      url = App.fixUrlDash("#{App.root_url}#{json.content_path}")
      console.log url
      $.notifier.notify("",json.title,json.content,url)
    else
      span.removeClass("badge-error")
    span.text(json.count)
    document.title = new_title
  true

具体来说通过token来区分和维护多个channel, 即每一个用户和server之间酒有一个channel, 不过faye-rails不是走的websocket. 见官网Faye is a publish-subscribe messaging system based on the Bayeux protocol. 但是官方的架构有说:

# http://faye.jcoglan.com/architecture.html
    Persistent connections using WebSocket
    Long-polling via HTTP POST
    Cross Origin Resource Sharing
    Callback-polling via JSON-P

这也是我疑惑不解的地方.可能作者加了websocket部分的实现.

Since version 0.5, Faye has supported WebSockets as a network transport for sending messages to the browser. The code that handles this is decoupled from the rest of the library and can be used to make your own WebSocket applications.

These classes are available as a stand-alone library, faye-websocket
推荐文章:

https://github.com/DavidEGrayson/websocket-chat/blob/master/rws1/server.rb

https://blog.engineyard.com/2013/getting-started-with-ruby-and-websockets

http://www.jianshu.com/p/64114b220410

共收到 9 条回复

可以看看RabbitMQ 提供多种消息推送模式 http://www.rabbitmq.com/getstarted.html

bunny这个ruby实现的客户端也超简单 http://rubybunny.info/articles/getting_started.html

通过STOMP插件 配合sockjs非常方便 http://www.rabbitmq.com/stomp.html https://github.com/sockjs/sockjs-client

#1楼 @zhang_soledad 谢谢. 我的目的其实不是推送.而是one to one的聊天.如果用pub/sub实现那就是1:1,我觉得这样做不值得.换句话说,我想用websocket或者amqp等其他一些协议来实现1对1的聊天.

one to one 的聊天, 用 channel 的意义不大吧, 可以直接收到 A 的消息, 然后转发给 B 的.

#3楼 @42thcoder 可以直接收到 A 的消息, 然后转发给 B 的. 这里就是关键,我可能转发给B, 也可能转发给BCDEF......问题就是怎么去转发,我可以识别是哪个发来的(在message里面带username).但是我看到的websocket实现除了socket.io有fromto,其他都没有.

#4楼 @flowerwrong 维护一个在线用户列表, 每个用户可能有多个 connection. 转发给B, 就是往 B 的所有 connection 中发消息. 可以看源码, 文档未必有写清楚.

#4楼 @flowerwrong

websocket-rails 中可以这样写:

WebsocketRails.users[receiver.id].send_message :new_message, { content: 'Hey there~' }

@flowerwrong @42thcoder 你们好,请问,websocket-rails有在生产环境正式的用起吗?这东西靠谱吗?方便的话,还请指点一下。谢谢!

我觉得这种东西自己开发太麻烦了,就别自己捣鼓了,找个第三方,方便,GoEasy就挺不错的,我昨天试了一下,代码简洁易懂,几分钟我就洗了一个自己的实时推送功能;官网: http://goeasy.io/

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册