在铁轨中使用em-websocket构建一个谈话 - 谈话系统的策略?

时间:2015-12-29 06:21:42

标签: ruby-on-rails websocket em-websocket websocket-rails

也许它是服务器推送系统的一个很好的例子。系统中有许多用户,用户可以互相交谈。它可以这样完成:一个用户(通过websocket)向服务器发送消息,然后服务器将消息转发给另一个用户。关键是找到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
}

我想弄清楚以下问题:

  1. ws对象可以序列化,以便存储到磁盘或数据库中?否则我只能将绑定存储到内存中。

  2. em-websocket和websocket-rails之间有什么区别?

  3. 您对websocket推荐哪种宝石?

2 个答案:

答案 0 :(得分:1)

您正在接近websockets非常适合的用例,因此您处于正确的轨道上。

  1. 您可以使用Marshal序列化ws对象,但将websocket对象视为有点像http请求对象,因为它们是一种通信类型的抽象。你可能最好是编组/存储数据。
  2. em-websocket是一个较低的(ish)杠杆websocket库,或多或少直接在网络机器上构建。 websocket-rails是websockets的更高级抽象,内置了许多漂亮的工具和非常好的文档。它建立在faye-websocket-rails之上,它本身就是在Web机器上构建的。 *注意,动作电缆是Rails 5的新websocket库,建立在faye上。
  3. 我过去使用过websocket-rails而非常喜欢它。它会照顾你很多。但是,如果您可以使用Rails 5和Action Cable,那么就这样做,它的未来。

答案 1 :(得分:1)

以下内容仅适用于Chase Gilliam's succinct answer,其中包含对em-websocketwebsocket-rails的引用(很长时间内没有维护),faye-websocket-rails和{{ 3}}

我会推荐ActionCable框架。它既可以作为独立的应用程序框架,也可以作为Rails Websocket增强功能。

我也会考虑以下几点:

  1. 您是否需要在连接之间保留消息(即如果其他用户离线,消息是否应在“消息框”中等待?消息应等待多长时间?)...?

  2. 您是否希望保留邮件记录?

  3. 这些要点有助于您决定是否对邮件使用持久存储(即数据库)。

    即,要在Rails中使用Plezi,请在应用程序的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服务器),所以请记住从您的应用程序中删除对pumathin或任何其他自定义服务器的任何引用。

    在客户端,你可能想要使用Plezi提供的Javascript助手(可选)...添加:

    <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>
    

    我没有测试实际的消息代码,因为它只是一个骨架,而且它还需要一个带有User模型和token的Rails应用程序,我不想编辑它只是为了回答一个问题(没有冒犯)。