Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django: JSON Notifications using Redis PubSub, Node.js & Socket.io

I came across this article: http://maxburstein.com/blog/realtime-django-using-nodejs-and-socketio/

Which has steered me in the somewhat right direction.

I currently have an iOS front end and a Django back end. I use Gunicorn to serve data to the front end application. The communication between my iOS application and my backed is REST based. I simply send JSON back and forth. I don't serve any webpages. Just JSON responses.

I've implemented a simple Post & Comment Model:

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)

Users can make blog posts and other users can comment on them. So if userX has a blog post and userY comments on it. I would like to notify userX that userY commented on his/her post.

I used to rely on pyAPNS to notify users; a python wrapper that uses Twisted to send notifications to APNS, but if userX turns off push notifications for my app, then userX will not be able to receive in-app notifications. So I'm out of luck.

I only care about in-app notifications. I would still like userX to receive live updates while he is in the app.

Django can publish the message to a channel on Redis when a user makes a POST request. Node.js will subscribe to that channel and socket.io will send it out to that particular user.

Here is a stripped down version of my views.py where the comment object is created. I send the id the user who made the comment, the id of the post, and the id of the user who made the blog post. The user will make a post request to this url with 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 Implementation (According to Max Burstein's Article from Above)

var http = require('http');
var server = http.createServer().listen(4000);
var io = require('socket.io').listen(server);

And this is as far as I get :( I know this is quite sad but I'm left with many questions. How can I subscribe node.js to the remote Redis server that I published to from Django? How many clients can connect to this socket? is there limit? is a socket created for every client? or does every client listen in on the same socket? Can I send json data over this socket to one specific client? I know this is one big mammoth of post , but I'm in need of desperate help. If I wasn't clear with something, please do let me know so that I can edit the question. Thank you!

like image 625
deadlock Avatar asked Jan 12 '14 06:01

deadlock


2 Answers

I'd definitely not use node.js for this. You can handle websockets in Python just fine, with Celery or gevent or whatever.

Just create a thread which registers to Redis and listens for new messages.

When the user connects, put the socket into a weak-value hash indexed by the user's name; when a message for them arrives, look up the destination username in that hash and send it off. Weak-value because it cleans up after itself when the user disconnects. Simple, really.

I'd also send new messages to the server using the websocket instead of HTTP-PUT.

like image 136
Matthias Urlichs Avatar answered Oct 05 '22 01:10

Matthias Urlichs


Take a look at the implementation here: http://blog.sneawo.com/blog/2013/02/08/real-time-messaging-in-django-using-node-dot-js-and-redis/

like image 42
djvine Avatar answered Oct 05 '22 01:10

djvine