Django: уведомления JSON с использованием Redis PubSub, Node.js & Socket.io
Я столкнулся с этой статьей: http://maxburstein.com/blog/realtime-django-using-nodejs-and-socketio/
Который управлял мной в несколько правильном направлении.
В настоящее время у меня есть передний конец iOS и задний конец Django. Я использую Gunicorn для передачи данных в приложение переднего конца. Связь между моим приложением iOS и моей поддержкой основана на REST. Я просто посылаю JSON туда и обратно. Я не обслуживаю никаких веб-страниц. Только ответы JSON.
Я реализовал простую модель публикации и комментариев:
class Post(models.Model):
user = models.ForeignKey(User)
blog = models.CharField(max_length=5000)
class Comment(models.Model):
comment = models.CharField(max_length=140)
user = models.ForeignKey(User)
post_id = models.ForeignKey(Post)
created_at = models.DateTimeField(auto_now_add=True)
Пользователи могут создавать записи в блогах, а другие пользователи могут комментировать их. Поэтому, если userX имеет сообщение в блоге и комментарии пользователя на нем. Я хотел бы уведомить userX, что userY прокомментировал его/ее сообщение.
Раньше я полагался на pyAPNS для уведомления пользователей; оболочка python, использующая Twisted для отправки уведомлений APNS, но если userX отключает push-уведомления для моего приложения, тогда пользовательский интерфейс не сможет получать уведомления в приложении. Поэтому мне не повезло.
Мне больше всего нравятся уведомления в приложении. Я все равно хотел бы, чтобы userX получал живые обновления, пока он находится в приложении.
Django может опубликовать сообщение на канал в Redis, когда пользователь делает запрос POST. Node.js будет подписаться на этот канал, и socket.io отправит его этому конкретному пользователю.
Вот урезанная версия my views.py, где создается объект комментария. Я отправляю идентификатор пользователя, который сделал комментарий, идентификатор сообщения и идентификатор пользователя, который сделал запись в блоге. Пользователь отправит запрос на этот URL с помощью json: http://example.com:8000/upload-comment/
def UploadComment(request):
data = json.loads(request.body)
redis_server = redis.Redis(host='12.345.678.9', port=6379, db=0, password='mypassword')
newComment = Comment()
newComment.comment = data['comment']
newComment.user_id = data['user_id']
newComment.post_id = data['post_id']
newComment.save()
PostOwner = data['post_owner_id'] #id of the blog post owner
# Need to send a notification to PostOwner
response_data = []
response_data.append(
{'send_notifcation_to': PostOwner
'action': 'comment'
'comment_by': newComment.user.username)}
redis_server.publish("notifications", json.dumps(response_data))
return HttpResponse('Request Successful')
Node.js Реализация (согласно статье Максима Бурштейна выше)
var http = require('http');
var server = http.createServer().listen(4000);
var io = require('socket.io').listen(server);
И это насколько я понимаю:( Я знаю, что это довольно грустно, но у меня много вопросов. Как я могу подписаться на Node.js на удаленный сервер Redis, который я опубликовал с Django? многие клиенты могут подключиться к этому сокету? существует ли ограничение? - это сокет, созданный для каждого клиента, или каждый клиент слушает в одном и том же сокете? Могу ли я отправлять данные json через этот сокет одному конкретному клиенту? Я знаю, что это один большой мамонт почты, но мне нужна отчаянная помощь. Если бы я ничего не понимал, пожалуйста, дайте мне знать, чтобы я мог отредактировать вопрос. Спасибо!
Ответы
Ответ 1
Я бы определенно не использовал node.js для этого. Вы можете обрабатывать websockets в Python просто отлично, с Celery или gevent или что-то еще.
Просто создайте поток, который регистрируется в Redis и прослушивает новые сообщения.
Когда пользователь подключается, поместите сокет в хэш-код слабого значения, проиндексированный именем пользователя; когда приходит сообщение для них, найдите имя пользователя назначения в этом хэше и отправьте его. Слабая ценность, потому что она очищается после себя, когда пользователь отключается. Простой, действительно.
Я также отправлял новые сообщения на сервер, используя websocket вместо HTTP-PUT.
Ответ 2
Взгляните на реализацию здесь:
http://blog.sneawo.com/blog/2013/02/08/real-time-messaging-in-django-using-node-dot-js-and-redis/
Ответ 3
Похоже, вы должны использовать что-то вроде RabbitMQ http://www.rabbitmq.com/devtools.html там node.js и многое другое.
Проверьте это, он должен поднять настроение:)
Ответ 4
Я также использую замечательную библиотеку, называемую django-websocket-redis.
Хотя он не использует gunicorn, он использует uWSGI, у которого не должно быть слишком много накладных расходов при переходе на. Просто следуйте документам, они довольно полные.
https://django-websocket-redis.readthedocs.org/en/latest/
Взяв некоторый код и реализуя его с помощью django-websockets-redis:
## Make a json representation of your model available.
class Comment(models.Model):
comment = models.CharField(max_length=140)
user = models.ForeignKey(User)
post_id = models.ForeignKey(Post)
created_at = models.DateTimeField(auto_now_add=True)
def as_json(self):
return dict(
id=self.id,
comment=self.comment,
created_at=self.created_at.strftime('%m/%d/%Y'),
post_id=self.post_id
user=self.user
)
Затем в ваших представлениях, когда вы делаете запрос, сохраните json-представление для объекта redis, на который вы подписаны... вы можете сделать это в любом месте, будь то ваш сериализатор или просмотр, но я оставлю это вам.
def UploadComment(request):
data = json.loads(request.body)
## In django-websockets-redis, this portion below is registered in the settings.py file, therefore i am commenting this out.
## redis_server = redis.Redis(host='12.345.678.9', port=6379, db=0, password='mypassword')
newComment = Comment()
newComment.comment = data['comment']
newComment.user_id = data['user_id']
newComment.post_id = data['post_id']
newComment.save()
PostOwner = data['post_owner_id'] #id of the blog post owner
# Need to send a notification to PostOwner
## Need to turn this into a string before posting to redis
json_comment = str(newComment.as_json())
## Create a facility based on the PostOwner ID. The PostOwner will always be subscribed to this channel.
RedisPublisher(facility=PostOwner, broadcast=True).publish_message(json_comment)
return HttpResponse('Request Successful')
Теперь, когда у нас есть бэкэнд, о котором мы заботимся, на визе front-vis vie JavaScript ваш пользователь подпишится на Facility на основе его user.id:
jQuery(document).ready(function($) {
var ws4redis = WS4Redis({
uri: '{{ WEBSOCKET_URI }}{{ PostOwner.id }}?subscribe-broadcast&publish-broadcast&echo',
receive_message: receiveMessage,
heartbeat_msg: {{ WS4REDIS_HEARTBEAT }}
});
// receive a message though the Websocket from the server
function receiveMessage(msg) {
//This is where you would retrieve the JSON string from the Redis server, and subsequently manipulate the DOM with appends, Toastr Notifications, Etc...
}