使用 sockjs-tornado 的私人消息传递

Private messaging using sockjs-tornado

我已经使用 sockjs-tornado 实现了聊天功能,并且可以将消息存储在 RethinkDB 中。

你能帮我看看如何在 sockjs-tornado 中建立私人消息通道吗? (我是说私聊/一对一)

下面是我的服务器端代码中的 on_message 函数 -

def on_message(self, message):
    str=message
    mg=str.split('#:#')
    sender=1 # This is the sender user id
    receiver=2 #This is the receiver user id - I need to implement session variables to have these id's so that I can use it here this way
    ts=r.expr(datetime.now(r.make_timezone('00:00')))
    connection = r.connect(host="192.x.x.x")
    r.db("djrechat").table('events').insert({"usrs":mg[0],"msg":mg[1],"tstamp":ts,"snder":sender,"rcver":receiver}).run(connection)
    log.info(message)
    self.broadcast(self.participants, '{} - {}'.format(self.stamp(),message))

目前正在向所有连接的客户端广播。 可能我应该有一个频道 ID 并且只向两个具有相同频道 ID 的客户端发送消息,但是我该如何实现它或者对此有更好的解决方案吗?

在客户端,我有以下 javascript -

      function connect() {
        disconnect();
        conn = new SockJS('http://localhost:8080/chat', ['websocket','xhr-streaming','iframe-eventsource','iframe-htmlfile','xhr-polling','iframe-xhr-polling','jsonp-polling']);
        //log('Connecting.....');
        conn.onopen = function() {
        //  log('Connected. (' + conn.protocol + ')');
        log('Connected.');
        };

        conn.onmessage = function(e) {
          log(e.data);
        };

        conn.onclose = function() {
          log('Disconnected.');
          conn = null;
        };
      }

我正在使用 python 3.4 - Django 1.8.4 和 Rethinkdb

虽然 sockjs-tornado 没有实现诸如通道或房间之类的东西,但是 example multiplex how one could implement that. Also look at sockjs - example of implementing rooms。解决方案基于结构化 msg - 在消息中您发送了附加信息 - 频道名称。

我的回答假设当前解决方案中的所有客户端都连接到一个 SockJS 服务器,该服务器的频道名称用于聊天消息的广播(或接近此场景的名称)。我进一步假设用户从客户端发送消息时的往返行程是:

[Sender (Client)] ------- Message (POST) --> [App Server] --- Message --> [Database]
                                                  |
                                               Message
                                                  v
[Receiver(s) (Client)] <-- Message (WS) -- [SockJS Server]

这个问题有多种解决方案。我这里只列出我认为最简单最稳健的:

  • 让每个用户订阅一个每用户(私有)频道另外广播频道在聊天中。 如果您实施此解决方案,唯一的 附加 更改是让 应用程序服务器 知道私人消息必须 发送到接收者的 私人 频道。

另一个稍微复杂且不优雅的解决方案是 在需要时为每个私有对创建 临时 通道。 但是,当 User A 想与 User B 聊天时,您如何让 User B 订阅(新创建的)私人频道?一种方法是 广播 请求 User B 连接到该频道,但这会告诉所有其他客户端(在代码级别)关于这个私人聊天发生;如果这些客户端中的任何一个受到威胁,该信息可能会被滥用,例如窃听或破坏私人派对。

其他建议

我还想提一下,因为我在后端写了 sockjs - example of implementing rooms answer, I have changed my own architecture to (still) use SockJS in the front-end, but with RabbitMQ using the Web-STOMP plugin。这样,

  1. 客户端在浏览器中仍然使用sockjs-client with stomp-websocket,
  2. 处理前端多路复用的所有后端代码 可以删除,
  3. (基于 RabbitMQ 的)后端快速并且非常健壮
  4. 客户端向后端应用服务器发送消息,后者又
    1. 将消息保存在数据库中,
    2. 充当 RabbitMQ 服务器的客户端,并且 (1) 将消息广播给所有连接的用户,或者如果消息是 private (2) 通过收件人自己的私人渠道将消息发送给单个收件人,如上面建议的解决方案所述。

整个新解决方案置于 HAProxy 之后,它终止 HTTPS 和 SSL/TLS-encrypted WebSocket 连接。