Real time notifications with Django and Socket.io - python

currently i'm implementing real time notifications for my Django project.
I'm following instructions from this tutorial. Problem is, i'm using Socket.io 1.4.5 and tutorial is written for pre-1.0 versions. So i had to adapt some code following 'Migrating from 0.9' guideline on Socket.io site. What i got is:
var http = require('http');
var server = http.createServer().listen(8002);
var io = require('socket.io')(server);
var cookie_reader = require('cookie');
var querystring = require('querystring');
var redis = require('redis');
// Supposedly this should store cookie set by Django
io.use(function(socket,accept){
var data = socket.request;
if(data.headers.cookie){
data.cookie = cookie_reader.parse(data.headers.cookie);
return accept(null, true);
}
return accept('error', false);
});
io.sockets.on('connection', function (socket) {
// Redis client
client = redis.createClient();
// Subscribe to notification channel
client.subscribe('notifications.' + socket.handshake.cookie['sessionid']);
console.log('subscribed');
//Grab message from Redis and send to client
client.on('message', function(channel, message){
console.log('on message', message);
socket.send(message);
});
// Unsubscribe
socket.on('disconnect', function() {
client.unsubscribe('notifications.' + socket.handshake.cookie['sessionid']);
});
});
When i'm running this script:
node notifications.js
After 2 seconds of silence i get this error:
client.subscribe('notifications.' + socket.handshake.cookie['sessionid']);
^
TypeError: Cannot read property 'sessionid' of undefined
at Namespace.<anonymous> (path/to/notifications.js)
at Namespace.emit (events.js:107:17)
at Namespace.emit (/path/to/node_modules/socket.io/lib/namespace.js:206:10)
at /path/to/node_modules/socket.io/lib/namespace.js:174:14
at process._tickCallback (node.js:355:11)
Can somebody point me to what i did wrong?

Just found what my mistake was.
To access cookie, instead of socket.handshake i should be using socket.request. So my current code looks like this now:
var http = require('http');
var server = http.createServer().listen(8002);
var io = require('socket.io')(server);
var cookie_reader = require('cookie');
var querystring = require('querystring');
var redis = require('redis');
io.use(function(socket,accept){
var data = socket.request;
if(data.headers.cookie){
data.cookie = cookie_reader.parse(data.headers.cookie);
return accept(null, true);
}
return accept('error', false);
});
io.on('connection', function (socket) {
// Redis client
client = redis.createClient();
// Subscribe to notification channel
client.subscribe('notifications.' + socket.request.cookie['sessionid']);
console.log('subscribed');
//Grab message from Redis and send to client
client.on('message', function(channel, message){
console.log('on message', message);
socket.send(message);
});
// Unsubscribe
socket.on('disconnect', function() {
client.unsubscribe('notifications.' + socket.request.cookie['sessionid']);
});
});

Related

How to fetch data analyzed in python to node.js and pass it to angular?

I am new to angular and i want to display JSON data from python to angular with the help of node.js and I used child process to connect python and node.js but I dont know how to pass it to angular service
node.js file
const express = require('express')
const { spawn } = require('child_process')
const app = express()
const port = 8000
app.get('/', (req, res) => {
let dataToSend
let largeDataSet = []
// spawn new child process to call the python script
const python = spawn('python', ['test.py'])
// collect data from script
python.stdout.on('data', function (data) {
console.log('Pipe data from python script ...')
//dataToSend = data;
largeDataSet.push(data)
})
// in close event we are sure that stream is from child process is closed
python.on('close', (code) => {
console.log(`child process close all stdio with code ${code}`)
// send data to browser
res.send(largeDataSet.join(''))
})
})
app.listen(port, () => {
console.log(`App listening on port ${port}!`)
})
Technically you just have to send a Http GET request from your service.
I suggest that you should read and follow this offical http client guide to set it up correctly.
Here is a simple service snippet. This should be enough.
#Injectable({
providedIn: 'root',
})
export class MyService {
constructor(private http: HttpClient) {}
getData(): Observable<any> {
const url = '';
return this.http.get(url);
}
}

How to delete a user's facebook data from firebase with firebase admin?

I'm using firebase UI to authenticate users in a given frontend. Facebook authentication is enabled. I need to implement a facebook data deletion callback so I need to make my backend do two things:
delete/disable the facebook sign in method from the user that issued the data deletion request from facebook
delete every trace of facebook data from my firebase user (the provider user info) but without deleting the user
However, I can't find anything in firebase admin's documentation to delete facebook data. So, how can I delete the data?
PD: Keep in mind that I want to delete the user's provider user info, but not the whole user (because I need the user to stay there for data consistency)
If someone is looking for a NodeJS implementation, this is how you can do it:
module.exports = functions.https.onRequest(async (req, res) => {
try {
const signedRequest = req.body.signed_request;
const userObj = parseSignedRequest(signedRequest, FB_SECRET_KEY);
const userRecord = await admin
.auth()
.getUserByProviderUid("facebook.com", userObj.user_id);
await admin.auth().deleteUser(userRecord.uid);
res.json({
url: "<status_url>",
confirmation_code: "<code>",
});
} catch (e) {
// console.log(e);
res.status(400).json({
message: "Bad Request",
});
}
});
function base64decode(data: string) {
while (data.length % 4 !== 0) {
data += "=";
}
data = data.replace(/-/g, "+").replace(/_/g, "/");
return Buffer.from(data, "base64").toString("utf-8");
}
function parseSignedRequest(signedRequest: string, secret: string) {
var encoded_data = signedRequest.split(".", 2);
// decode the data
var sig = encoded_data[0];
var json = base64decode(encoded_data[1]);
var data = JSON.parse(json);
if (!data.algorithm || data.algorithm.toUpperCase() != "HMAC-SHA256") {
throw Error(
"Unknown algorithm: " + data.algorithm + ". Expected HMAC-SHA256"
);
}
var expected_sig = crypto
.createHmac("sha256", secret)
.update(encoded_data[1])
.digest("base64")
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace("=", "");
if (sig !== expected_sig) {
throw Error("Invalid signature: " + sig + ". Expected " + expected_sig);
}
return data;
}
PS. There is no way to just unlink providers via Firebase Admin SDK for now so best we can do is delete the user data.

How can I use the Python socket module to connect to the socket.io server in node.js?

I created a server using socket.io in node.js. Then, using Python's socket module, we attempted to connect to the node.js server, which resulted in 400 errors. How can I solve this error? Here's my code.
app.js
var http = require('http').Server(app); //1
var io = require('socket.io')(http); //1
var count=1;
io.on('connection', function(socket){ //3
console.log('user connected: ', socket.id); //3-1
var name = "user" + count++; //3-1
io.to(socket.id).emit('change name', name); //3-1
socket.on('disconnect', function(){ //3-2
console.log('user disconnected: ', socket.id);
});
socket.on('send message', function(name,text){ //3-3
var msg = name + ' : ' + text;
console.log(msg);
io.emit('receive message', msg);
});
});
http.listen(8000, function(){ //4
console.log('server on!');
});
client.py
import socketio
sio = socketio.Client()
sio.connect('http://localhost:8000')
print('my sid is', sio.sid)
sio.emit('my message', {'foo': 'bar'})

Emitting messages from python-shell to a browser in a Node Express App

I have an express app and I would like to be able to trigger python scripts via routes and emit the log into the browser.
I have created a route which triggers the python scripts correctly and outputs the log into the node console using python-shell module. How can I push this log to the browser in real time.
I have a button on an index.html page which triggers an Ajax post request to a /python route below. I have tried to implement this with socket.io but haven't managed to get my head around it. Is socket.io the way forward, please point me in the right direction or can someone recommend an alternative?
My file layout is:
server.js
var express = require('express');
var path = require('path');
var app = express();
var port = process.env.PORT || 3000;
var http = require('http');
var server = http.createServer(app);
var io = require('socket.io').listen(server);
/* A bit inbetween */
server.listen(port)
app/routes.js
var PythonShell = require('python-shell');
var config = require('../config/config');
module.exports = function(app) {
app.get('/', function(req, res) {
res.render('pages/index.ejs', {
pageTitle: 'Index'
}); // load the index.ejs file
});
app.post('/test', function(req, res) {
var options = {
mode: 'text',
pythonPath: config.pythonPath,
pythonOptions: ['-u'],
scriptPath: config.pythonScriptsDirectory
};
var pyshell = new PythonShell('printRange.py', options);
pyshell.on('message', function (message) {
console.log(message);
});
res.sendStatus(200)
});
}
Thanks in advance
socket.io is a good solution. This will take care of passing the messages from the server to the client. You just post the message to on the server side, and have a callback react to it on the client side
On the server side you'll have something like this:
var app = require('express')();
var server = require('http').createServer(app);
var io = require('socket.io')(server);
io.on('connection', function(){
console.log('connected');
});
server.listen(3000);
...
var pyshell = new PythonShell('printRange.py', options);
pyshell.on('message', function (message) {
if (connected)
io.emit('logentry',message);
});
On the client side, you'll have something like this:
<script src='/socket.io/socket.io.js'></script>
<script>
var socket = io();
socket.on('logentry',function(log_entry){
add_to_html(log_entry); // You need to implement this function.
});
</script>

zeromq ROUTER,DEALER message encoding format

I have written an application which is nodejs (main app) and python (client) app that i want to communicate with each other using zmq Router,Dealer pattern.
the problem is i could not read the messages sent from clients to nodejs (router) app.
its encoded some how.
the code is as simple as below:
var responder = zmq.socket('router');
responder.on('message', function(request) {
console.log(request);
// i could not read the messages here.its obfuscated
});
responder.bind('tcp://127.0.0.1:8000', function(err) {
if (err) {
console.log(err);
} else {
console.log('Listening on 8000...');
}
});
python:
socket = context.socket(zmq.DEALER)
socket.connect("tcp://127.0.0.1:8000")
socket.send('blaaaa')
print 'message sent!'
If you wish to use the DEALER/ROUTER sockets, then the message is actually given as the second argument for the callback function.
var responder = zmq.socket('router');
responder.on('message', function(header, body) {
console.log(body.toString('utf8'));
});
The message is in the format of a Buffer, but you can turn it into a string using .toString(encoding);
The header contains an identity, this allows you to later route the response/answer back to the correct sender/requester that made the original request.
For your application, PUSH-PULL seems more appropriate:
var zmq = require('zmq');
var responder = zmq.socket('pull');
responder.on('message', function(request) {
console.log(request.toString());
// Use `toString` to convert Buffer to string
});
responder.bind('tcp://127.0.0.1:8000', function(err) {
if (err) {
console.log(err);
} else {
console.log('Listening on 8000...');
}
});
import zmq
context = zmq.Context()
socket = context.socket(zmq.PUSH)
socket.connect("tcp://127.0.0.1:8000")
socket.send('blaaaa')
print 'message sent!'

Categories

Resources