emit user-specific events for long poll - event-handling

What's the best way to implement long-polling for user-specific events? I have a "home feed" for each user that I want dynamically updated with new information immediately as it comes in.
Right now I'm making an AJAX call from the client to /register?id=2, for example, to listen for updates. The server itself sends a GET request to /emit?id=2&eventid=3 when some other event(eventid=3) related to user(id=2) occurs. The Node.js server has code similar to below:
var event_emitter = new events.EventEmitter();
http.createServer(function(req,res) {
var uriParse = url.parse(req.url,true);
var pathname = uriParse.pathname;
if (pathname=="/register") {
var userid = uriParse.query.id;
var thisRes = res;
event_emitter.addListener('event'+userid,function(eventid){
if (thisRes) {
console.log(thisRes);
thisRes.writeHead(200, { "Content-Type": "text/plain" });
thisRes.end(eventid);
thisRes = null;
}
});
} else if (pathname=="/emit") {
var userid = uriParse.query.id;
var eventid = uriParse.query.eventid;
event_emitter.emit('event'+userid,eventid);
res.writeHead(200, { "Content-Type": "text/plain" });
res.end('success');
}
}).listen(3000,"0.0.0.0");
So the client's AJAX call doesn't load until the event occurs, at which point the server returns a response with the eventid. The client uses this eventid to make a different AJAX call (unrelated, since I'm using Django for the main application but Node.js for event-driven super-powers).
I'm just bothered by creating so many listeners for "event2" "event454" etc as more users connect. Is this scalable with something like Node.js? How else can I emit user-specific events?
Thanks in advance!

You can remove the listener after emitting the events using removeAllListeners.

Related

How to handle api failure in gupshup bot http call

I am making a http call from the gupshup IDE bot as below.
function MessageHandler(context, event) {
if(event.message. == "postdata") {
var url = "https://abcserver.com/sm/postData";
var header = {"token":"ca916a68d94","Content-Type": "application/x-www-form-urlencoded"};
var param = "userName=John&phoneNumber=1123111111";
context.simplehttp.makePost(url,param,header);
}
function HttpResponseHandler(context, event) {
var result= JSON.parse(event.getresp);
if(result=="success")
context.sendResponse("We have successfully stored your data");
}
I need a way to handle the failure i.e if the url (https://abcserver.com/sm/postData) is not reachable then I don't get any callback, HttpResponseHandler is not called in this case and the bot stops abruptly. I need a way to know that the corresponding api request has failed.I tried using try catch but it doesn't work.
Any link to the correct documentation or code example is welcome.

Firebase transactions via REST API

I find transactions (https://www.firebase.com/docs/transactions.html) to be a cool way of handling concurrency, however it seems they can only be done from clients.
The way we use Firebase is mainly by writing data from our servers and observing them on clients. Is there a way to achieve optimistic concurrency model when writing data via REST API?
Thanks!
You could utilize an update counter to make write ops work in a similar way to transactions. (I'm going to use some pseudo-code below; sorry for that but I didn't want to write out a full REST API for an example.)
For example, if I have an object like this:
{
total: 100,
update_counter: 0
}
And a write rule like this:
{
".write": "newData.hasChild('update_counter')",
"update_counter": {
".validate": "newData.val() === data.val()+1"
}
}
I could now prevent concurrent modifications by simply passing in the update_counter with each operation. For example:
var url = 'https://<INSTANCE>.firebaseio.com/path/to/data.json';
addToTotal(url, 25, function(data) {
console.log('new total is '+data.total);
});
function addToTotal(url, amount, next) {
getCurrentValue(url, function(in) {
var data = { total: in.total+amount, update_counter: in.update_counter+1 };
setCurrentValue(ref, data, next, addToTotal.bind(null, ref, amount, next));
});
}
function getCurrentValue(url, next) {
// var data = (results of GET request to the URL)
next( data );
}
function setCurrentValue(url, data, next, retryMethod) {
// set the data with a PUT request to the URL
// if the PUT fails with 403 (permission denied) then
// we assume there was a concurrent edit and we need
// to try our pseudo-transaction again
// we have to make some assumptions that permission_denied does not
// occur for any other reasons, so we might want some extra checking, fallbacks,
// or a max number of retries here
// var statusCode = (server's response code to PUT request)
if( statusCode === 403 ) {
retryMethod();
}
else {
next(data);
}
}
FYI, Firebase Realtime Database officially supports this now.
Read the blog and the docs for more info.
check out Firebase-Transactions project: https://github.com/vacuumlabs/firebase-transactions
I believe, this may be quite handy for your case, especially if you do a lot of writes from the server.
(disclaimer: I'm one of the authors)

Handling CSRF/XSRF tokens with Angular frontend and Drupal 7 backend

I'm in the process of building a new AngularJS frontend for a Drupal 7 website. This is using the Services module with session-based authentication, across two domains using CORS. I am able to authenticate with Drupal, retrieve the user object and session data, and then get the CSRF token from the services module. What I'm having trouble with is setting all this up in the header so that subsequent requests are authenticated. I understand the overall concept but am new to both AngularJS and preventing CSRF attacks.
From what I have gathered reading about this set-up with AngularJS and RubyOnRails, there can be inconsistencies between platforms concerning what the token is named and how it is processed. There also seems to be a number of suggestions on how to set this token in the header. However, I'm having trouble in finding a solid example of how to get these platforms speaking the same language.
The only thing I'm doing with my $httpProvider in app.js is:
delete $httpProvider.defaults.headers.common['X-Requested-With'];
The login controller, in controller.js:
.controller('LoginCtrl', ['$scope', '$http', '$cookies', 'SessionService', function($scope, $http, $cookies, SessionService) {
$scope.login = function(user) {
//set login url and variables
var url = 'http://mywebsite.com/service/default/user/login.json';
var postDataString = 'name=' + encodeURIComponent(user.username) + '&pass=' + encodeURIComponent(user.password);
$http({
method: 'POST',
url: url,
data : postDataString,
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).success(function (data, status, headers, config) {
var sessId = data.sessid;
var sessName = data.session_name;
$cookies[sessName] = sessId;
var xsrfUrl = 'http://mywebsite.com/services/session/token';
$http({
method: 'GET',
url: xsrfUrl
}).success(function (data, status, headers, config) {
$cookies["XSRF-TOKEN"] = data;
SessionService.setUserAuthenticated(true);
}).error(function (data, status, headers, config) {
console.log('error loading xsrf/csrf');
});
}).error(function (data, status, headers, config) {
if(data) {
console.log(data);
var msgText = data.join("\n");
alert(msgText);
} else {
alert('Unable to login');
}
});
};
The solution has to do with how the cookies need to be set and then passed through subsequent requests. Attempts to set them manually did not go well but the solution was simpler than I expected. Each $http call needs to set the options:
withCredentials: true
Another change I made was to use the term CSRF instead of XSRF, to be consistent with Drupal. I didn't use any built-in AngularJS CSRF functionality.
addItem: function(data)
{
return $http.post('api/programs/'+$stateParams.id+'/workouts', {item:data},{
headers:
{
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'X-CSRF-Token': $('meta[name="xxtkn"]').attr('content')
}
});
}
since it has been a year of this topic! not sure still encountering the same problem but for the ones who comes to search for answers here is how i handle it!
Pay attention the headers{} part i define a new header and call it X-CSRF-Token and grab value from the DOM of (serverside) generated html or php. It is not a good practise to also request the csrf token from the server.Cuz attacker could somehow request that as well. Since you save it as a cookie. Attacker can steal the cookie! No need to save it in a cookie! send the token with header and read it in the serverside to match it!
and for multitab of a same page issue. I use the same token thruout the whole session.
Only regenerate on login, logout and change of major site or user settings.
There is a great library callse ng-drupal-7-services. If you use this in you project it solves authentication / reauthentication and file / node creation aut of the box and you can fokuse on the importent stuff in your project.
So Authentication is there solved like this:
function login(loginData) {
//UserResource ahndles all requeste of the services 3.x user resource.
return UserResource
.login(loginData)
.success(function (responseData, status, headers, config) {
setAuthenticationHeaders(responseData.token);
setLastConnectTime(Date.now());
setConnectionState((responseData.user.uid === 0)?false:true)
setCookies(responseData.sessid, responseData.session_name);
setCurrentUser(responseData.user);
AuthenticationChannel.pubLoginConfirmed(responseData);
})
.error(function (responseError, status, headers, config) {
AuthenticationChannel.pubLoginFailed(responseError);
});
};
(function() {
'use strict';
AuthenticationHttpInterceptor.$inject = [ '$injector'];
function AuthenticationHttpInterceptor($injector) {
var intercepter = {
request : doRequestCongiguration,
};
return intercepter;
function doRequestCongiguration (config) {
var tokenHeaders = null;
// Need to manually retrieve dependencies with $injector.invoke
// because Authentication depends on $http, which doesn't exist during the
// configuration phase (when we are setting up interceptors).
// Using $injector.invoke ensures that we are provided with the
// dependencies after they have been created.
$injector.invoke(['AuthenticationService', function (AuthenticationService) {
tokenHeaders = AuthenticationService.getAuthenticationHeaders();
}]);
//add headers_______________________
//add Authorisation and X-CSRF-TOKEN if given
if (tokenHeaders) {
angular.extend(config.headers, tokenHeaders);
}
//add flags_________________________________________________
//add withCredentials to every request
//needed because we send cookies in our request headers
config.withCredentials = true;
return config;
};
There is also some kind of kitchen sink for this project here: Drupal-API-Explorer
Yes, each platform has their own convention in naming their tokens.
Here is a small lib put together hoping to make it easy to use with different platforms. This will allow you to use set names and could be used across all requests. It also works for cross-domain requests.
https://github.com/pasupulaphani/angular-csrf-cross-domain

Updating MongoDB in Meteor Router Filter Methods

I am currently trying to log user page views in meteor app by storing the userId, Meteor.Router.page() and timestamp when a user clicks on other pages.
//userlog.js
Meteor.methods({
createLog: function(page){
var timeStamp = Meteor.user().lastActionTimestamp;
//Set variable to store validation if user is logging in
var hasLoggedIn = false;
//Checks if lastActionTimestamp of user is more than an hour ago
if(moment(new Date().getTime()).diff(moment(timeStamp), 'hours') >= 1){
hasLoggedIn = true;
}
console.log("this ran");
var log = {
submitted: new Date().getTime(),
userId: Meteor.userId(),
page: page,
login: hasLoggedIn
}
var logId = Userlogs.insert(log);
Meteor.users.update(Meteor.userId(), {$set: {lastActionTimestamp: log.submitted}});
return logId;
}
});
//router.js This method runs on a filter on every page
'checkLoginStatus': function(page) {
if(Meteor.userId()){
//Logs the page that the user has switched to
Meteor.call('createLog', page);
return page;
}else if(Meteor.loggingIn()) {
return 'loading';
}else {
return 'loginPage';
}
}
However this does not work and it ends up with a recursive creation of userlogs. I believe that this is due to the fact that i did a Collection.find in a router filter method. Does anyone have a work around for this issue?
When you're updating Meteor.users and setting lastActionTimestamp, Meteor.user will be updated and send the invalidation signal to all reactive contexts which depend on it. If Meteor.user is used in a filter, then that filter and all consecutive ones, including checkLoginStatus will rerun, causing a loop.
Best practices that I've found:
Avoid using reactive data sources as much as possible within filters.
Use Meteor.userId() where possible instead of Meteor.user()._id because the former will not trigger an invalidation when an attribute of the user object changes.
Order your filters so that they run with the most frequently updated reactive data source first. For example, if you have a trackPage filter that requires a user, let it run after another filter called requireUser so that you are certain you have a user before you track. Otherwise if you'd track first, check user second then when Meteor.logginIn changes from false to true, you'd track the page again.
This is the main reason we switched to meteor-mini-pages instead of Meteor-Router because it handles reactive data sources much easier. A filter can redirect, and it can stop() the router from running, etc.
Lastly, cmather and others are working on a new router which is a merger of mini-pages and Meteor.Router. It will be called Iron Router and I recommend using it once it's out!

Facebook get number of sent requests and accepted request

i need to make a page that will have a request dialog for a facebook page or a facebook app.
I need to get the number of friends the user sent the request to and at the end of the day the number of request that got accpeted from the specific user.
The scenario is for giving awards , the user that sent the most request to freinds gets an award and the user that had the most requests accepted also gets an award.
I dont know if the seccond is possible , but i think it should be , couse games on FB give u points for sent request and also u get new missions when friends accept your request , so there mut be a way.
--
I will record the number of invites sent.
Return Data
request_ids
A comma-separated list of the request_ids that were created. To learn who the requests were sent to, you should loop through the information for each request object identified by a request id.
FB.ui({
method: 'apprequests',
title:'Suggest '+fbAppName+' to your friends',
message: 'I thought you would dig this app!',
data: 'gameID=96'
}, onInviteFriend);
//jquery required for ajax function
onInviteFriend = function(response) {
if (response && response.request_ids) {
var idsLength = response.request_ids.length;
var idList = "";
var data = {};
var ajaxSettings = {};
for (var i = 0; i < idsLength; i++){
idList += response.request_ids[i];
if (i < idsLength-1){
idList += ",";
}
}
if (idsLength > 0){
data.idList = idList;
ajaxSettings = {
type: "GET",
url: sketchnpass.root+"/ajax/log-invite-sent/",
data: data,
success: sketchnpass.onSaveInvites
};
$.ajax(ajaxSettings);
}
//was published
} else {
//was not published
}
}
i think using the code above i can get the number of sent requests.
But when some1 accepts the request how will i know that happened , does the accepted request send the user to my app along with some data?
The Facebook requests dialog documentation basically walks you through how to do this.
When requests are sent, request_ids is returned as return data so you would want to log this information in your system to track who sent how many requests.
To track accepted invitations, the documentation says that this url is called: http://apps.facebook.com/[app_name]/?request_ids=012345678910 so you would just need to parse the request id and look that request id up in your system and mark it as accepted.