Sails.js: stream socket and send to controller - node.js

I'm writing a REST API in Sails.js and alongside the regular HTTP routes, I need the application to listen for notifications on a socket from Salesforce.
I have a controller with some logic but I don't know how to get it to subscribe to the socket on startup, so right now nothing is reaching it.
Controller:
pushTopicHandler: function(req, res) {
if (!req.isSocket) {
return res.badRequest();
}
var nforce = require('nforce');
var org = nforce.createConnection({
clientId: sails.config.client_id,
clientSecret: sails.config.client_secret,
redirectUri: sails.config.callback_url + '/oauth/_callback',
mode: 'multi',
environment: 'sandbox'
});
org.authenticate({ username: sails.config.sfUsername, password: sails.config.sfPassword }, function(err, oauth) {
if(err) return res.serverError(err);
var str = org.stream({ topic: sails.config.push_topic, oauth: oauth });
str.on('connect', function(){
console.log('Connected to pushtopic: ' + sails.config.push_topic);
});
str.on('error', function(error) {
console.log('Error received from pushtopic: ' + error);
});
str.on('data', function(data) {
console.log('Received the following from pushtopic ---');
console.log(data);
});
});
}

Sails has a bootstrap.js file which lets you write anything you want to run before the server lifts.
I was able to subscribe to the push topic in a small function before the cb() in that file and it works, the server starts the REST API normally and it's still listening for events.

Related

Angular 6 authentificate client after server restart socket.io socketio-jwt

Id like to auth eacht socket.io event on server side.
When i open angular page first, call method initSocket(login: Login), its ok.
Authentification successfull and i can send a message to server.
But if i restart server, angular reconnect to server by Htttp, but cant send a message by socketio.
In my server no messages in logs.
It seems that socketio-jwt block an clients message.
If i press F5 on client side its still ok again.
How to solve it without refreshing a page?
It seems taht i have to pass a token to each event on client side, after connection established to, but i dont know how to do it.
Angular 6:
public initSocket(login: Login): void {
this.socket = socketIo(SERVER_URL);
console.log('Socket init at' + SERVER_URL);
this.socket.emit('authenticate', { token: this.login.token });
this.socket.on('authenticated', function () {
console.log('socket is jwt authenticated');
});
this.socket.on('unauthorized', function (error, callback) {
if (error.data.type === 'UnauthorizedError' || error.data.code === 'invalid_token') {
// redirect user to login page perhaps or execute callback:
callback();
console.error('Users token has expired');
}
});
this.socket.on('disconnect', function (error) {
console.error('socket disconnect', error);
});
this.socket.on('connect_failed', function (error) {
console.error('socket connect_failed');
});
}
Server side:
io.sockets
.on('connection', socketioJwt.authorize({
secret: environment.secret,
timeout: 15000,
callback: false
})).on('authenticated', function (socket) {
clients[socket.decoded_token.id] = socket.decoded_token.login;
console.error('Connected: ', socket.decoded_token.login);
socket.on('message', async function (data) {
try {
// Проверка что пользователь пишите от себя
if (data.from === socket.decoded_token.id) {
data.totalCount = await db_helper.saveMessage(data);
if (clients[data.from] && clients[data.to]) {
io.sockets.connected[clients[data.to].socket].emit("message", data);
console.log("Sending from: " + clients[data.from].name + " to: " + clients[data.from].name + " '" + data.text + "'");
} else {
console.log('User does not exist: from=>', data.from, ':', clients[data.from], 'to=>', data.to, ':', clients[data.to]);
}
}
}
catch (error) {
console.error(error.message);
}
});
//Removing the socket on disconnect
socket.on('disconnect', function () {
});
});
This is because whenever your server/client goes offline, a new socket is created for re connection purpose and to establish a new connection i.e re connection, Server disconnects all it's previous connection from the same client, this process is asynchronous and thus is not visible to developers easily.
I would have also checked if my socket reconnection which is done is reconnected to the , by default socket reconnects to the port your client is connected to.
if that's the case then you need to reconnect with the help of io (socket manager)
There is also a possibility that your client re connection is set to false, you can check your socket properties by consoling it as follows:
this.socket.on('disconnect', function (error) {
console.log('disconnected', this)
//this sets whether the re connection is allowed or not
this.io._reconnection = true;
});
this.socket.on('reconnect', (error, callback) => {
console.log('reconnect succesfully', this);
//connect to the previously connected socket.
this.io.socket.reconnect()
});

Sails and Socket publishUpdate Can't Send data

I try learn Socket With sails but I have a problem with publishUpdate can't send data.
Let me show my code
User Module server Side
'subscribe': function(req,res,next){
User.find(function(err,users){
if (err) return next(err);
User.watch(req.socket);
User.subscribe(req.socket, users);
console.log('now user is subscribe in ',req.socket.id);
res.send(200);
});
}
app.js Client Side
(function(io){
// Connect To Socket
var socket = io.sails.connect();
if(typeof console !== 'undefined'){
console.log('Connecting to Sails.js ...');
}
socket.on('connect', function(){
// is undefined
console.log("This is handshake: ",socket.handshake)
// is undefined
console.log("This is from the connect: ", socket.id);
//console.log(socket);
// listen for message
socket.on('message', function(message){
console.log('New Message is Coming', message);
});
// Subscribe to the user model classroom and instance room
io.socket.get('/user/subscribe',function(){
//console.log('user now is subscribe ');
});
// log
console.log(
'Socket is now connected and globally accessible as `socket`.\n' +
'e.g. to send a GET request to Sails, try \n' +
'`socket.get("/", function (response) ' +
'{ console.log(response); })`'
);
});
})(
// In case you're wrapping socket.io to prevent pollution of the global namespace,
// you can replace `window.io` with your own `io` here:
window.io
);
in Session module server Side
user.online = true;
user.save(function(err,user){
//req.isSocket
var io = sails.io;
// emit to all sockets (aka publish)
// including yourself
I try this and work great and I revived message
//io.sockets.emit('message', {thisIs: 'USer Log in Id is ' + user.id});
User.publishUpdate(user.id,{
loggedIn : true,
id : user.id
});
console.log('User is signin', user.id);
// User Redirect To His Profile
if (user.admin){
res.redirect('/user/');
return;
}
res.redirect('/user/show/'+ user.id);
});
Now I try reload the server and show me in chrome browser
This is handshake: undefined
app.js:14 This is from the connect: undefined
app.js:32 Socket is now connected and globally accessible as socket.
e.g. to send a GET request to Sails, try
socket.get("/", function (response) { console.log(response); })
I remove publishUpdate and try emit.
I try this and work great and I revived message.
//io.sockets.emit('message', {thisIs: 'USer Log in Id is ' + user.id});

How to connect CouchDb with HapiJs?

I have an App written using the HapiJs framework for Node and want to connect it to a CouchDb databse, but am having trouble finding the code to do so.
Can anyone help me with the code to do that? What is the 'normal' way of doing that?
Cheers!
Well you don't need any framework for couchdb. Everything is available via a rest api. Just use request module to make requests to the api. A few examples : -
Read a document
request.get("http://localhost:5984/name_of_db/id_of_docuement",
function(err,res,data){
if(err) console.log(err);
console.log(data);
});
Read from a view
request.get(
"http://localhost:5984/name_of_db/_design/d_name/_view/_view_name",
function(err,res,data){
if(err) console.log(err);
console.log(data);
});
The entire api is documented here
There is no need to manage connections or to handle the opening and closing of database that you might be doing with other databases. Simply start couchdb and start making requests to from your application.
However if you find that making requests to the api directly is a bit cumbersome for you, then you can try using nano which provides a nicer syntax for doing things with couchdb.
Some snippets of code
All right so I am not familliar with hapi so I will just tell you how do do it with request.
Consider this example from the docs
var Hapi = require('hapi');
var server = new Hapi.Server(3000);
var request = require("request");
server.route({
method: 'GET',
path: '/',
handler: function (request, reply) {
reply('Hello, world!');
}
});
server.route({
method: 'GET',
path: '/{name}',
handler: function (req, rep) {
request.get("http://localhost:5984/name_of_db/id_of_docuement",
function(err,res,data){
if(err) console.log(err);
rep(data);
});
}
});
server.start(function () {
console.log('Server running at:', server.info.uri);
});
When you call the / endpoint it the request handler for it is executed. It makes a request to a couchdb endpoint to fetch a a document. You don't need anything to connect to couchdb besides that.
Another option could be the hapi-couchdb plugin (https://github.com/harrybarnard/hapi-couchdb).
Using it is a little more "hapi-like" than making direct calls into the Couch API directly.
Here's an example from the plugin documentation:
var Hapi = require('hapi'),
server = new Hapi.Server();
server.connection({
host: '0.0.0.0',
port: 8080
});
// Register plugin with some options
server.register({
plugin: require('hapi-couchdb'),
options: {
url: 'http://username:password#localhost:5984',
db: 'mycouchdb'
}
}, function (err) {
if(err) {
console.log('Error registering hapi-couchdb', err);
} else {
console.log('hapi-couchdb registered');
}
});
// Example of accessing CouchDb within a route handler
server.route({
method: 'GET',
path: '/',
handler: function (request, reply) {
var CouchDb = request.server.plugins['hapi-couchdb'];
// Get a document from the db
CouchDb.Db.get('rabbit', { revs_info: true }, function(err, body) {
if (err) {
throw new Error(CouchDb.Error(error); // Using error decoration convenience method
} else {
reply(body);
});
}
});
server.start(function() {
console.log('Server running on host: ' + server.info.uri);
});

Avoiding multiple verification for Twitter API (node.js)

I'm trying to create a basic app in node.js that a) tracks a keyword in twitter and temporarily stores messages relating to that keyword, b) after enough messages have been accumulated, return it to the user. I'm using the ntwitter library.
I've a basic long polling system implemented on my client and server side, but I'm having some trouble on verification. The way I set it up currently, it verifies the user each time /api/streamfeed is called, so potentially every 30sec (since I have a 30s timeout schedule) before checking the stream. I'm thinking this will get me into trouble since I believe verification is rate-limited? Is there a way to check whether I'm verified without having to ping Twitter's API (perhaps store a boolean after the first attempt)?
Client side:
//upon receiving a response, poll again
function getStreamFeed() {
console.log('calling getStreamFeed');
$http.get('/api/streamfeed').success(function(data) {
console.log(data)
getStreamFeed();
});
};
setTimeout(getStreamFeed, 1000);
Server side:
app.get('/api/streamfeed', function(req, res) {
/*
...
polling code
...
*/
twit.verifyCredentials(function(err, data) {
if (err) res.send(404);
twit.stream('statuses/filter', {
track: 'justin bieber'
}, function(stream) {
stream.on('data', function(data) {
console.log(data.text)
messages.push(data.text);
});
})
});
});
I'd send the credentials back and resend them again... this could be a bool, or actual credentials to use. these aren't your private keys or anything, only the user's.
could also be sent in headers and cookies and properly hashed etc.
this just simply shows a pattern that should work.
client side:
function getStreamFeed(credentials) {
//upon receiving a response, poll again
console.log('calling getStreamFeed');
var url = '/api/streamfeed';
if (credentials) {
url += '&credentials=' + credentials;
}
$http
.get(url)
.success(function(data) {
console.log(data)
getStreamFeed(true);
});
};
setTimeout(getStreamFeed, 1000);
Server side:
app.get('/api/streamfeed', function(req, res) {
function twitStream () {
twit.stream('statuses/filter', {track: 'justin bieber'}, function(stream) {
stream.on('data', function(data) {
console.log(data.text)
messages.push(data.text);
});
}
}
var credentials = req.query.credentials;
if (credentials) {
twitStream()
}
twit.verifyCredentials(function(err, data) {
if (err) res.send(404);
twitStream()
});
});

need to send error to unauthorized user in socket.io

as the title is obvoius i need to send back some error message for unauthorized user and i need to know how to achive this for example i need to send this message to user
you dont have any username to begin chat
and print it in users browser how should i do that? the client side code is something like this
//this is the client side code
var socket = io.connect('http://localhost', { resource: '/chat/app.js' });
// on connection to server, ask for user's name with an anonymous callback
socket.on('connect', function(){
// call the server-side function 'adduser' and send one parameter (value of prompt)
socket.emit('adduser')
});
socket.socket.on('error', function (reason){
console.log('Unable to connect Socket.IO', reason);
});
but the reason which i get in console is
Unable to connect Socket.IO handshake error
how should i print the message which is the cause of user is nothing get authorized?
this is the server side code
var io = require('socket.io').listen(80);
io.configure(function (){
io.set('authorization', function (handshakeData, callback) {
// findDatabyip is an async example function
findDatabyIP(handshakeData.address.address, function (err, data) {
if (err) return callback(err);
if (data.authorized) {
handshakeData.foo = 'bar';
for(var prop in data) handshakeData[prop] = data[prop];
callback(null, true);
} else {
//THIS IS THE MESSAGE *********************************************
callback('you dont have any username to begin chat', false);
}
})
});
});
To send the error back to the user you must modify the error function on manager.js (socket.io\lib\manager.js; line 768 approx) from this
function error (err) {
writeErr(500, 'handshake error');
self.log.warn('handshake error ' + err);
};
to this
function error (err) {
writeErr(500, /*'handshake error'*/ err);
self.log.warn('handshake error ' + err);
};

Resources