The answer in - "What's going on with Meteor and Fibers/bindEnvironment()?" is very helpful however it could not help me resolve my issue.
Here is what I am doing :
- Login with google
- Call FunGoogle(user) from Accounts.onCreateUser
code:
SocialFunGoogle = function (user) {
var config = Accounts.loginServiceConfiguration.findOne({service: 'google'});
var opts = {
consumerKey: config.clientId,
consumerSecret: config.secret,
token: user.services.google.accessToken,
refreshToken: user.services.google.refreshToken
};
var gcontacts = new GoogleContacts(opts);
gcontacts.refreshAccessToken(opts.refreshToken, function (err, accessToken) {
if (err && err != null) {
console.log('gcontact.refreshToken, ', err);
return false;
} else {
console.log('gcontact.access token success!');
gcontacts.token = accessToken;
}
});
var fn = Meteor.bindEnvironment(function () {
var Fiber = Meteor.require('fibers');
var Future = Meteor.require('fibers/future');
var future = new Future();
setTimeout(function () {
return future.return(
Fiber(function () {
gcontacts.getContacts(
function (err, contact) {
contact = [{
name: 'S Sharma',
email: '[email protected]',
photoUrl: 'https://www.google.com/m8/feeds/photos/media/procrazium%40gmail.com/adf456aaaabbnndaa',
mime_type: 'image/*'
}, {
name: 'A Kapil',
email: '[email protected]',
photoUrl: 'https://www.google.com/m8/feeds/photos/media/procrazium%40gmail.com/22aaaab555758bc37952',
mime_type: 'image/*'
}, {
name: 'A Kartik',
email: '[email protected]',
photoUrl: 'https://www.google.com/m8/feeds/photos/media/procrazium%40gmail.com/2f2aaa02aab00f7aa85a2',
mime_type: 'image/*'
}];
contact.map(function (c) {
SocialConnect.insert(c);
});
return contact;
});
}).run()
);
}, 500);
});
fn();
}
When I try logging in, my code throws the following errors.
Exception while invoking method 'login' TypeError: Cannot set property '_meteor_dynamics' of undefined
Error: Meteor code must always run within a Fiber. Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment
Can you please point out what am I doing here wrong?
This isn't the correct way to do async in JavaScript:
SocialFunGooglereaches// Abefore the code at// Bexecutes, so there's no guarantee thatgcontacts.tokenhas been set. (That's probably what the timeout is for, but that's not reliable since then the function will mysteriously fail if refreshing the token takes more than 500ms.)returnat// Creturns from the anonymous callback function, not fromSocialFunGoogle, so this won't do what you want.Normally you would have to nest the rest of your function inside this callback, but Meteor uses Fibers, so you don't have to. Fibers lets you write code as if it were synchronous, but behind the scenes it still runs asynchronously like any other node.js application.
Unfortunately most npm packages are written for the callback style, but there are simple ways to adapt callback code for Fibers. I'll use Futures. Here's how you could rewrite that code using Futures:
Here's how that executes:
wait()on the Future. The current Fiber goes to sleep, waiting for the Future to be resolved.returnmethod.future.returnpops out offuture.wait.You can use this pattern to deal with the
getContactscall as well. Since the only code that runs outside of the Fiber is thefuture.returncalls, you don't ever need tobindEnvironmentor create your own Fiber.