使用 Django Channels 向所有连接的客户端发送信息

Using Django Channels to send info to all connected clients

我正在创建一个系统,其中 Twitter Live Streaming API 通过给定的关键字获取实时的推文数据流。每当推文出现时,我都想通过 WebSockets(使用 Django Channels)将新数据发送到所有连接的客户端。这是我目前的程序:

  1. Twitter 直播代码在获取新数据时调用 consumers.py 中的 initiateHandshake() 函数
  2. Django 通道将文本 "handshake" 发送给所有客户端
  3. 客户端收到握手消息并发回消息
  4. websocket.recieve 函数获取此消息,并根据存储在客户端连接会话中的过滤器信息,发回所需的数据(这就是需要握手的原因 - 因为每个客户端都有它自己的过滤器在其连接会话中)

现在,问题是 initiateHandshake() 中的 "handshake" 消息没有发送。为什么会这样,我该如何解决?太感谢了!我的代码如下。

WebSockets 运行正常(如果客户端发送消息,我可以使用 reply_channel 回复它 - 一切正常)

routing.py

from channels.routing import route
from tweetrunner.consumers import *

channel_routing = [
    route("websocket.connect", ws_connect),
    route("websocket.receive", ws_message),
    route("websocket.disconnect", ws_disconnect),
]

consumers.py

# In consumers.py
from channels import Group, Channel
from channels.sessions import channel_session
from .models import InputTweet
from django.shortcuts import render

# Outside world connection
def initiateHandshake():
    Group("table").send({"text": "handshake"})


# Connected to websocket.connect
@channel_session
def ws_connect(message):
    # Accept connection
    message.reply_channel.send({"accept": True})
    message.channel_session["sort"] = "none"
    # Add to group
    Group("table").add(message.reply_channel)


# Connected to websocket.receive
@channel_session
def ws_message(message):
    definition = message.content['text'][:1]

    if definition == "1":
        emotion = message.content['text'][1:]
        message.channel_session["sort"] = message.content['text'][1:]

        sendback = ""

        if emotion == 'none':
            given_tweets = InputTweet.objects.all()
            given_tweets = given_tweets[(len(given_tweets) - 1250):]
            print("before render")
            sendback = render(None, 'tweetrunner/get_table_update.html', {'given_tweets': given_tweets})
            print("rendered")
        else:
            given_tweets = InputTweet.objects.filter(emotion__startswith=emotion).order_by('score')
            given_tweets = given_tweets[(len(given_tweets) - 1250):]
            sendback = render(None, 'tweetrunner/get_table_update.html', {'given_tweets': given_tweets})

        print("about to send")
        message.reply_channel.send({
            "text": sendback.content.decode('utf-8'),
        })
        print("sent -- END CONNECTION LOGS")

    elif definition == "3":
        print("Keep alive!")

    else:

        emotion = message.channel_session["sort"]

        sendback = ""

        print("entered 2")

        if emotion == 'none':
            given_tweets = InputTweet.objects.all()
            given_tweets = given_tweets[(len(given_tweets) - 1250):]
            print("before render")
            sendback = render(None, 'tweetrunner/get_table_update.html', {'given_tweets': given_tweets})
            print("rendered")
        else:
            given_tweets = InputTweet.objects.filter(emotion__startswith=emotion).order_by('score')     
            given_tweets = given_tweets[(len(given_tweets) - 1250):]
            sendback = render(None, 'tweetrunner/get_table_update.html', {'given_tweets': given_tweets})

        print("about to send")

        #content = sendback.read()

        message.reply_channel.send({
            "text": sendback.content.decode('utf-8'),
        })

        print("sent -- END CONNECTION LOGS")


# Connected to websocket.disconnect
@channel_session
def ws_disconnect(message):
    Group("table").discard(message.reply_channel)

我的代码不在任何 django 应用程序中,正在像这样初始化 django(我可以访问数据库并使用 django 调用,所以它可以工作):

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "analyticsui.settings")

import django
django.setup()

JavaScript 客户端:

socket = new WebSocket("ws://" + window.location.host + "/");

socket.onmessage = function(e) {
alert("Got message: " + e.data)
    if (e.data == "handshake") {
        socket.send("2handshake");
        alert("sent");
    } else {
        document.getElementById("tweetTable").innerHTML = e.data;
        $('.tooltiphere').tooltip('remove');
        $('.tooltiphere').tooltip({delay: 10});
    }
}

initiateHandshake() 使用 In-memory Channel 层时不会发送任何消息。

From the doc: In-Memory layer does not support cross-process communication

请特别使用其他通道层类型<a href="https://channels.readthedocs.io/en/stable/backends.html#redis" rel="nofollow noreferrer">Redis channel layer</a>。一切都会按预期进行。