Meteor wrapAsync returning undefined to external service using php connector - asynchronous

I've been stuck on this for way too long. Can anyone help show me why my wrapasync method is returning as "undefined"? I'm trying to make a call to Facebook api and have used a php connector that my meteor app should use to talk to the Facebook PHP SDK. My app talks to the my php file and returns simple functions. But when I actually call the external service it comes back as undefined, although when I run the php function in php it comes out fine and returns expected results. Here's the code, everything is server-side:
var phpAsync = function() {
var execPhp = Meteor.npmRequire('exec-php');
execPhp('C:/xampp/htdocs/xampp/Facebook/file.php', function(error, php, output){
// php now contain user defined php functions.
php.me( function(error, result, output, printed){
// `result` is return value of `my_own_php_function` php function.
console.log(result);
return result;
});
});
};
Meteor.methods({
phpConnect: function () {
var phpSync = Meteor.wrapAsync(phpAsync);
var result = phpSync();
console.log(result);
return result
}
});

The function that is passed in to Meteor.wrapAsync should have callback as the final parameter. From the docs,
Wrap a function that takes a callback function as its final parameter.
The signature of the callback of the wrapped function should be
function(error, result){}
So you should do something like this,
var phpSync = function() {
var execPhp = Meteor.npmRequire('exec-php');
var execPhpSync = Meteor.wrapAsync(execPhp);
var php = execPhpSync('C:/xampp/htdocs/xampp/Facebook/file.php');
php.meSync = Meteor.wrapAsync(php.me);
var result = php.meSync();
console.log(result);
return result;
};
Meteor.methods({
phpConnect: function () {
var result = phpSync();
console.log(result);
return result;
}
});
OR
if you want other stuff like output and printed then you do it like this
var phpAsync = function(cb) {
var execPhp = Meteor.npmRequire('exec-php');
execPhp('C:/xampp/htdocs/xampp/Facebook/file.php', function(error, php, output){
//IMPORTANT: you need to call php.me only if there is no error
// php now contain user defined php functions.
php.me( function(error, result, output, printed){
// `result` is return value of `my_own_php_function` php function.
if (typeof cb === "function) {
cb(error, {
result: result,
output: output,
printed: printed
});
}
});
});
};
Meteor.methods({
phpConnect: function () {
var phpSync = Meteor.wrapAsync(phpAsync);
var result = phpSync();
console.log(result.result, result.output, result.printed);
return result.result;
}
});

Related

getting some part of URL

I'm trying to get the end part of this URL (in the sever side):
http://localhost:3000/insAds/D79htZY8DQ3YmcscE
I mean I want to get this string:
D79htZY8DQ3YmcscE
there is a similar question: How to get the query parameters in Iron-router?
but non of the answers can't help me! because I have no query params in the URL.
I know these codes gives me the string that I want:
this.params.id
and
Router.current().params.id
but these codes works only in client side! I want to get that string in the server side!
finally I'm trying to get that string and use here:
Ads.before.insert(function(userId, doc) {
//console.log(this.params.id);
doc._categoryId = this.params.id;
doc.createdAt = new Date();
doc.createdBy = Meteor.userId();
});
You can use Router.current().params or this.params like this
Router.route('/insAds/:id', function () {
console.log(this.params.id); // this should log D79htZY8DQ3YmcscE in console
});
Check the third example in Quick Start section of iron router documentation
EDIT: Based on our chat,
Your hook is
Ads.before.insert(function(userId, doc) {
//console.log(this.params.id);
doc._categoryId = this.params.id;
doc.createdAt = new Date();
doc.createdBy = Meteor.userId();
});
Change it to
Ads.before.insert(function(userId, doc) {
doc.createdAt = new Date();
doc.createdBy = Meteor.userId();
});
And then define meteor method in server like this
Meteor.methods({
'myInsertMethod': function (id) {
Ads.insert({
_categoryId: id
});
}
});
Call this from client side like this
Meteor.call('myInsertMethod', Router.params().id, function (err, res) {
console.log (err, res);
});

Meteor wrapasync save Twitter REST response to Mongo collection giving an error "Error: Meteor code must always run within a Fiber."

I am trying to use Twitter REST API GET followers/ids and save it to Mongo using Mongo collection insert method
Code inside /server/server.js:
Meteor.startup(function () {
// code to run on server at startup
TwitterFollowersIDsCollecions = new Mongo.Collection("twitterFollowersIDs");
var Twit = Meteor.npmRequire('twit');
var T = new Twit({
consumer_key: '###',
consumer_secret: '###',
access_token: '###',
access_token_secret: '###'
});
var getTwitterFollowersIDsAsync = function (screenname, cb) {
T.get('followers/ids', { screen_name: screenname }, function (err, data, response) {
console.log(data);
var vids = data.ids;
for(var i in vids) {
TwitterFollowersIDsCollecions.insert({
twitterFollowerID:vids[i]
});
}
}
);
};
Meteor.methods({
getTwitterFollowersIDsCollectionsClient : function (screenname){
var getTwitterFollowersIDsNow = Meteor.wrapAsync(getTwitterFollowersIDsAsync);
var result = getTwitterFollowersIDsNow('meteorjs');
console.log(result);
return result;
}
});
});
Error in server console:
Error: Meteor code must always run within a Fiber.
Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment.
Objective is to save twitter followers to a Mongo collection.
Meteor v. 1.1.0.2
Meteor packages:
meteor-platform
autopublish
insecure
differential:vulcanize
accounts-twitter
accounts-ui
meteorhacks:npm
npm-container
npm modules being used inside Meteor through meteorhacks:npm: "twit": "1.1.20" (added inside packages.json)
**UPDATE Second attempt **
Meteor.startup(function () {
// code to run on server at startup
TwitterFollowersIDsCollecions = new Mongo.Collection("twitterFollowersIDs");
var Twit = Meteor.npmRequire('twit');
var T = new Twit({
consumer_key: '###',
consumer_secret: '###',
access_token: '###',
access_token_secret: '###'
});
Meteor.methods({
// this is the server method called from the client
getTwitterFollowersIDsCollectionsClient : function (){
setTimeout(function(){
Meteor.call('getTwitterFollowersIDsNow', 'meteorjs');
},10);
return;
},
getTwitterFollowersIDsNow : function (screenname) {
T.get('followers/ids', { screen_name: screenname }, function (err, data, response) {
console.log(data);
});
}
});
});
I'm then calling the below code from browser console:
Meteor.call('getTwitterFollowersIDsCollectionsClient');
The server crashes with the same error:
Error: Meteor code must always run within a Fiber. Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment.
UDPATE:
getTwitterFollowersIDsCollectionsClient : function (screenname){
Meteor.setTimeout(function(screenname){
T.get('followers/ids', { screen_name: screenname }, Meteor.bindEnvironment(function (err, data, response) {
console.log("from getTwitterFollowersIDsCollectionsClient : "+data.ids);
var vids = data.ids;
for(var i in vids)
{
TwitterFollowersIDsCollecions.insert({
twitterFollowerID:vids[i]
});
}
return data;
}));
},10);
return;
}
Added Meteor.bindEnvironment to T.get callback method. This code worked and I was able to save the follower IDs to a mongo collection
Glad you got it working, but I played around with this and Meteor provides another, super easy way: wrapAsync. At least, it was easy once I figured it out! Here's the server code I wound up with -
var T = new TwitMaker({
consumer_key: '...'
, consumer_secret: '...'
, access_token: '...'
, access_token_secret: '...'
})
var wrapGet = Meteor.wrapAsync(T.get, T);
Meteor.methods({
getTwitImg: function(target) {
data = wrapGet('users/show', {screen_name: target});
if (data) {
img_url = data['profile_image_url'];
US.update({twitter: target}, {$set: {'targetImg': img_url}});
return img_url;
}
}
});
For the client and template code see this gist: https://gist.github.com/DanAncona/a09ce375e48bfa8efeca
Your code is a bit confusing. It seems like you're trying to execute a web service call async, but still return the result immediately (which won't work).
First of all, you probably wouldn't need to wrap the function to fetch the followers in an async block.
If you want your server method to return something immediately to the client after it has been called, I'd use a Meteor.setTimeout (see What's the point of Meteor.setTimeout() vs just setTimeout()?) block and call another method to do the fetching:
Meteor.methods({
// this is the server method called from the client
getTwitterFollowersIDsCollectionsClient : function (screenname){
Meteor.setTimeout(function() {
Meteor.call('getTwitterFollowersIDsNow', 'meteorjs');
}, 10);
return;
},
getTwitterFollowersIDsNow : function (screenname) {
T.get('followers/ids', { screen_name: screenname }, function (err, data, response) {
console.log(data);
var vids = data.ids;
for(var i in vids) {
TwitterFollowersIDsCollecions.insert({
twitterFollowerID:vids[i]
});
}
}
}
});
Ideally you would use a template helper to retrieve your followers from your collection. Due to these kind of helpers being reactive, you could just call the server method from the client and let the reactivity of Meteor solve your problem of returning the followers via the helper (which is re-executed/re-rendering the template on data change).
try calling:
var wrappedInsert = Meteor.bindEnvironment(function(tweet) {
TweetsCollection.insert(tweet);},
"Failed to insert tweet into Posts collection.");
from inside of api callback
getTwitterFollowersIDsNow : function (screenname) {
T.get('followers/ids', { screen_name: screenname }, function (err, data, response) {
for(var i in data)
{
wrappedInsert(data[i]);
}
});
}

Method call that fetches data. Can it be made reactive?

I want to get data from a number of queries on the same collection, and unfortunately this is not yet supported on meteor. That's why I tried to do something like this:
Common
Dep = new Deps.Dependency;
Server
Meteor.methods({
fetch: function(){
var results = Data.find(dataQuery).fetch();
var otherResults = Data.find(queryThatCannotBeCombinedWithPrevious).fetch();
return results.concat(otherResults);
},
save: function(data){
Data.insert(data);
Dep.changed();
}
update: function(data){
Data.update({_id: data._id}, data);
Dep.changed();
}
});
Client
Session.setDefault('combinedData', []);
Template.demo.data = function(){
Dep.depend();
Meteor.call('fetch',function(error, data){
Session.set('combinedData', data);
});
return Session.get('combinedData');
};
This doesn't work though, propably because the Dep variable on the client is different from the Dep on the server. Is there a way to make the method call reactive when the contents of the Data collection change?
Notes
I am currently using Meteor 0.8.1.1, which doesn't allow subscriptions that return multiple cursors of the same collection yet.
This requires a small hack and you're close. First, you need a client–only dependence, the server just passes a data returned from the method and doesn't share variables (also there's nothing on the server that requires deps). Second, you only want to fetch the actual variable once, otherwise you'll end up with an infinite loop.
Example implementation:
var value = null;
var valueInitialized = false;
var valueDep = new Deps.Dependency();
Template.demo.data = function() {
valueDep.depend();
if(!valueInitialized) {
valueInitialized = true;
Meteor.call('fetchData', function(err, result) {
value = result;
valueDep.changed();
});
}
return value;
};

meteor findOne or find returns undefined

I'm trying to do some validation prior to loading the main page. To do this I need to find a document that I have confirmed, exist in the Mongo Collection. Unfortunately finding the document in the client.js doesn't seem to work. In my opinion the client and server collection are not in sync. Based on similar articles i have read I made many changes without success. Here is a quick summary of what I have tried.
Option1: Try to find the record in the client side and not using auto-subscribe: record not found.
In app.js
credentialToken = "2KcNCRzpTHzyZ1111";
if (Meteor.isClient) {
Template.hello.greeting = function () {
return "Welcome to ares_sso.";
};
Meteor.startup(function () {
var results = Meteor.findrec(credentialToken);
console.log("results:",results); //results is undefined.
});
Template.hello.events({
'click input': function () {
if (typeof console !== 'undefined')
console.log("You pressed the button");
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
});
}
In /client/app.js
crs_collection = new Meteor.Collection("crs");
Meteor.subscribe("crs");
Meteor.findrec = function(credentialToken) {
target = {credentialtoken:credentialToken};
recfound = crs_collection.findOne(target);
//No luck with find either.
//recfound = crs_collection.find({credentialtoken:credentialToken}, {limit:1}).fetch()[0];
console.log("recfound:",recfound); //returns recfound is undefined.
return recfound;
}
In /server/server.js
crs_collection = new Meteor.Collection("crs");
Meteor.publish("crs", function(){
return crs_collection.find();
});
Option2: Next I did the find in the server side, using a method "server_recfind" which worked but I'm not able get the content to the client.
In app.js
credentialToken = "2KcNCRzpTHzyZ1111";
if (Meteor.isClient) {
Template.hello.greeting = function () {
return "Welcome to ares_sso.";
};
Meteor.startup(function () {
var results = Meteor.call('server_findrec',credentialToken);
console.log("results=",results); // also returns undefined
});
Template.hello.events({
'click input': function () {
if (typeof console !== 'undefined')
console.log("You pressed the button");
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
});
}
In /client/app.js
crs_collection = new Meteor.Collection("crs");
Meteor.subscribe("crs");
In /server/app.js
crs_collection = new Meteor.Collection("crs");
Meteor.publish("crs", function(){
return crs_collection.find();
});
// Using Sync which finds the record but how do I sent the content to the client?
Meteor.methods ({
'server_findrec': function(credentialToken) {
// tried unblock but didnt work
//this.unblock();
var rec = crs_collection.findOne({'credentialtoken': credentialToken});
console.log("INSIDE server findrec rec=",rec); //shows content found
// tried flush but it didn't do anything
crs_collection.flush;
return rec; //rec not returning to the client
}
})
Option3: Frustrated and since I was able to find the document record with the server method. I tried adding global variables to delivery the content to the client side. Unfortunately it didn't work
In app.js
credentialToken = "2KcNCRzpTHzyZ1111";
//added global variables
c1 = '';
c2 = '';
c3 = ''
if (Meteor.isClient) {
Template.hello.greeting = function () {
return "Welcome to ares_sso.";
};
Meteor.startup(function () {
var results = Meteor.call('server_findrec',credentialToken);
console.log("results=",results); // also returns undefined
console.log("c1=",c1);
console.log("c2=",c2);
console.log("c3=",c3);
});
Template.hello.events({
'click input': function () {
if (typeof console !== 'undefined')
console.log("You pressed the button");
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
});
}
In /client/app.js
crs_collection = new Meteor.Collection("crs");
Meteor.subscribe("crs");
In /server/app.js
crs_collection = new Meteor.Collection("crs");
Meteor.publish("crs", function(){
return crs_collection.find();
});
// Using Sync which finds the record but how do I sent the content to the client?
Meteor.methods ({
'server_findrec': function(credentialToken) {
// tried unblock but didnt work
//this.unblock();
var rec = crs_collection.findOne({'credentialtoken': credentialToken});
console.log("INSIDE server findrec rec=",rec); //shows content found
c1 = rec.cont1;
c2 = rec.cont2;
c3 = rec.cont3;
//confirm that c1,c2 and c3 have content
console.log(In server_findrec c1=",c); //shows content
console.log(In server_findrec c2=",c2); //shows content
console.log(In server_findrec c3=",c3); //shows content
// tried flush to sync to client...didn't work
crs_collection.flush;
return rec; //rec not returning to the client
}
})
There is a lot more code, so I have assembled all of the above hoping it gives you a clear picture of what I have tried and what I'm trying to do. I'm sorry if I made a mistake in the process.
Overall it will be great to know what am I doing wrong? I believe the 3 scenarios should work. Any help or recommendation will be appreciated.
I'm using Meteor Release 0.7.1.2, no CoffeeScript.
Thank you all
You're making two mistakes:
Define crs_collection once, and make sure its in a file thats executed on the client AND the server. It should be defined globally.
crs_collection must be defined before your pub/sub code. Meteor executes files in the lib directory first, so its best to put your collection code there.
That's really all there is to it. I'm happy to provide an example if needed.

Can't get result data with $http angularjs

I'm trying to use $http, but why it return null result?
angular.module('myApp')
.factory('sender', function($http) {
var newData = null;
$http.get('test.html')
.success(function(data) {
newData = data;
console.log(newData)
})
.error(function() {
newData = 'error';
});
console.log(newData)
return newData
})
Console say: http://screencast.com/t/vBGkl2sThBd4. Why my newData first is null and then is defined? How to do it correctly?
As YardenST said, $http is asynchronous so you need to make sure that all functions or display logic that are dependent on the data that is returned by your $http.get(), gets handle accordingly. One way to accomplish this is to make use of the "promise" that $http returns:
Plunkr Demo
var myApp = angular.module('myApp', []);
myApp.factory('AvengersService', function ($http) {
var AvengersService = {
getCast: function () {
// $http returns a 'promise'
return $http.get("avengers.json").then(function (response) {
return response.data;
});
}
};
return AvengersService;
});
myApp.controller('AvengersCtrl', function($scope, $http, $log, AvengersService) {
// Assign service to scope if you'd like to be able call it from your view also
$scope.avengers = AvengersService;
// Call the async method and then do stuff with what is returned inside the function
AvengersService.getCast().then(function (asyncCastData) {
$scope.avengers.cast = asyncCastData;
});
// We can also use $watch to keep an eye out for when $scope.avengers.cast gets populated
$scope.$watch('avengers.cast', function (cast) {
// When $scope.avengers.cast has data, then run these functions
if (angular.isDefined(cast)) {
$log.info("$scope.avengers.cast has data");
}
});
});
This JavaScript code is asynchronous.
console.log(newData)
return newData
Is executed before what inside success
newData = data;
console.log(newData)
So at first time, the newData is null (you set it to be null)
And when the http response is returned (inside the success), the newData gets its new value.
This is very common in Javascript, you should do all your work inside the success.

Resources