Why is my Meteor app logging to server but not client? - javascript

I'm building a meteor app that hooks into the twitter api and I've had no luck so far getting it to work. I'm using the twit package to make the call on the server side, and it logs the data to the server console, but when the client console goes to log it there is no data.
The client doesn't throw an error, it runs the console.log in the else statement for the result parameter, but it comes through as undefined. It's as if the result callback runs before the data comes back, but my understanding of the Meteor.call method is that it's supposed to wait until it hears back from the server before it runs.
What am I doing wrong here?
if (Meteor.isClient) {
Template.hello.greeting = function () {
return "Welcome to testing.";
};
Template.hello.recentFollows = function () {
return Session.get("recentFollows");
};
Template.hello.events({
'click #fetchButton': function () {
console.log("Recent tweets from stream!");
userName = "josiahgoff";
Meteor.call('getBananaTweets', function(err, result) {
if(err) {
console.log("error occurred on receiving data on server. ", err);
} else {
console.log("result: ", result);
Session.set("recentFollows", result);
}
});
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
Twit = new TwitMaker({
consumer_key: '******',
consumer_secret: '******',
access_token: '******',
access_token_secret: '******'
});
});
Meteor.methods({
getBananaTweets: function () {
Twit.get('search/tweets', { q: 'banana since:2011-11-11', count: 1 }, function(err, result) {
if (err) {
console.log("Error", err);
return err;
} else {
console.log(result);
return result;
}
});
}
});
}

You are using return in your server code in a place where it must not be used: in an asynchronous call-back. The Twit.get call returns immediately and the function ends (with no return value). So the client doesn't receive anything. Some time later the Twit.get comes back, but the return in that case goes nowhere.
This is a pretty common question. The solution is to wrap your Twit.get call into a fiber in some shape or form to make it synchronous. See for instance this answer: Iron Router Server Side Routing callback doesn't work

Related

How to watch changestream in mongoDB and send the updates to an ajax call?

I'm using the new feature of MongoDB 3.6 watch() in order to send updates of the database from the node server to ajax in the client side.
I created a webservice queried periodically by an ajax call. Between two successive ajax calls, i want the second one to get all the updates that occurred in the mean time. I know that i have to resume the change stream as shown in the official documentation here : https://docs.mongodb.com/manual/changeStreams/#resume-a-change-stream . However i didn't find out how to apply this to my specific needs, by that i mean, in which callback can i process my data and send it to the webservice response ?
Here is a part of my server side code : server.js
const pipeline = [
{
$match : {
"operationType" : "insert"
,
"fullDocument.T" : { "$exists":true}
}
},
{
$project: { "fullDocument.ts": 1,
"fullDocument.T":1}
}
];
function getLiveData(handler){
console.log("in getLiveData");
var liveArray=[];
var resumeToken;
const changeStream = dbObject.collection('status').watch(pipeline);
changeStream.hasNext(function(err, change) {
if (err) return console.log(err);
expect(err).to.equal(null);
expect(change).to.exist;
console.log("in changeStream.hasNext");
changeStream.next(function(err, change) {
if (err) return console.log(err);
expect(err).to.equal(null);
console.log("in changeStream.next");
resumeToken = change._id;
expect(change._id).to.exist;
expect(changeStream.resumeToken).to.exist;
changeStream.close(function(err) {
if (err) return console.log(err);
expect(err).to.equal(null);
console.log("in changeStream.close");
const newChangeStream = dbObject.collection('status').watch({ resumeAfter: resumeToken });
newChangeStream.next(function(err, next) {
if (err) return console.log(err);
expect(err).to.equal(null);
expect(next).to.exist;
console.log("in newChangeStream.next");
//my own code
newChangeStream.on("change", function(change) {
console.log('in change stream, change : ',change);
liveArray.push([change.fullDocument.ts, change.fullDocument.T]);
var response = {
"liveArray" : liveArray
};
console.log("from getLiveData : " , response);
handler(response);
});
//my own code
// Since changeStream has an implicit seession,
// we need to close the changeStream for unit testing purposes
newChangeStream.close();
});
});
});
});
}
webservice part :
app.get("/liveDataRequest", function(req, res){
getLiveData(function(data){
console.log("in handler", data);
res.status(200).send(data);
});
And here is the console log, as we can see, the part where i process my data never gets called :
in getLiveData
in changeStream.hasNext
in changeStream.next
in changeStream.close
in newChangeStream.next
in getLiveData
in changeStream.hasNext
in changeStream.next
in changeStream.close
in newChangeStream.next

What would be necessary to code the callback function to receive the access token?

I am trying to retrieve the access token from an API (https://github.com/Axosoft/node-axosoft/)
To receive an access token we have to follow this process:
var axo = nodeAxosoft(axosoftUrl, credentials);
axo.Api.getLoginUrl(function(url) {
// open browser using authorizationUrl and get code parameter from
//redirected Url after login
var code = 'code received from redirect';
axo.Api.exchangeCodeForToken(code);
});
As I did not understood exactly how to get the code following that example nor what is the url parameter on getLoginUrl, I did it on my own.
I have a login route that redirects the user to the axosoft website for authentication and redirects the user to the /authorization-process route on my application.
On the /authorization-process I get the code returned by the login and call a function that should get the access token by calling:
axo.Api.exchangeCodeForToken(code);
Code:
var axosoft_code = req.query.code;
console.log(axosoft_code);
var token = request.exchangeAuthCodeForAccessToken(axosoft_code)
.then(function(token)
{
res.send(token);
})
The Method:
var connection = nodeAxosoft(client_url, credentials);
return new Promise(function(resolve, reject){
console.log("CODE: ", axosoft_code)
var token = connection.Api.exchangeCodeForToken(axosoft_code, function(token){
console.log(token);
resolve(token)
})
The problem is that returns null
I had a look at the API lib api.js and found that:
https://github.com/Axosoft/node-axosoft/blob/master/lib/api.js
function exchangeCodeForToken(code, callback) {
_credentials.code = code;
_access_token = '';
_authenticateCredentails(function (err) {
if (!err) {
callback(null, _access_token);
} else {
callback(err);
}
})
}
So I have two questions:
Does anyone has an Idea what am I doing wrong?
What would be necessary to code the callback function?
The method expects a callback function but I don't really know how to do it.
EDIT:
return new Promise(function(resolve, reject){
var token = connection.Api.exchangeCodeForToken(axosoft_code, function(response,err){
if(!err){
console.log("token",response)
resolve(token);
}
else{
console.log("error",err)
resolve(token);
}
});
})
OR
var token = connection.Api.exchangeCodeForToken(axosoft_code, function(response,err){
if(!err){
console.log("token",response.body)
return response.body;
}
else{
console.log("error",err)
return err;
}
});
I am giving to my callback function two args (response and err), my problem is that I am falling at the else condition.
The output of err is something similar to a token though the documentation here shows that it should be like that:
{
"error" : "invalid_request",
"error_description" : "One or more parameters are missing: client_secret"
}
Another point is that the page is frozen waiting for something to happen but nothing happens.
Given that this is the input:
function exchangeCodeForToken(code, callback) {
_credentials.code = code;
_access_token = '';
_authenticateCredentails(function (err) {
if (!err) {
callback(null, _access_token);
} else {
callback(err);
}
})
}
You should format your call as:
exchangeCodeForToken(axosoft_code, function(err, response) {
if (err) {
// Deal with error
} else {
// Deal with response
}
}
Node functions often pass through error variables first so that you have to receive them, which is considered good practice.

node.js Query database using mongoose in socket.io

Right now, I'm writing a small web application using node.js with my partner. In the application, we need to query some data from database using mongoose, then, send the data to the client.Trying to do this, I'm using the code below:
io.sockets.on('connection', function (socket) {
var id = socket.id;
socket.on('request', function (data) {
mongoose.createConnection(dbConfig.url);
var ClassX = require("./models/" + data.request);
var class_query = ClassX.findOne({}, function (err, result) {
if (err) {
console.log("There is an error: "+ err);
return handleError(err);
}
if (!result) {
console.log("No result!");
}
io.sockets.to(id).emit("response", result);
});
});
});
But it doesn't work.
And when the code is running, the log file of the database show some information like below:
2017-02-23T15:40:48.426+0800 I NETWORK [thread1] connection accepted from 127.0.0.1:5015 #3 (3 connections now open)
2017-02-23T15:40:48.428+0800 I NETWORK [conn3] received client metadata from 127.0.0.1:5015 conn3: { driver: { name: "n
odejs", version: "2.2.24" }, os: { type: "Windows_NT", name: "win32", architecture: "x64", version: "10.0.14393" }, plat
form: "Node.js v6.9.5, LE, mongodb-core: 2.1.8" }
The information "[conn3] received client metadata ..." seems weird. And, from the experience of many attempts, I think the callback function of ClassX.finOne() has not been executed. And I totally don't know why.

Cannot insert to collection from NPM using Meteor 1.3

I am using the imap-simple NPM package to check emails, and I am having trouble getting the insert to work properly.
I have already read through this page: https://guide.meteor.com/using-npm-packages.html#async-callbacks - and I have tried the suggestions but none of them are working!
I've also simplified the code a bit just to try to get it working, but still have no luck.
The problem should be very easy to reproduce - meteor npm install imap-simple, throw the above code on the server, add some email credentials, and call the method.
Here is my code:
var imaps = require('imap-simple');
var config = {
imap: {
user: '<removed>',
password: '<removed>',
host: 'imap.gmail.com',
port: 993,
tls: true,
authTimeout: 3000
}
};
Meteor.methods({
api_connectEmail: function () {
console.log('Received call to connect email');
imaps.connect(config).then(function (connection) {
return connection.openBox('INBOX').then(function () {
var searchCriteria = [
'UNSEEN'
];
var fetchOptions = {
bodies: ['HEADER', 'TEXT'],
markSeen: true
};
return connection.search(searchCriteria, fetchOptions).then(function (results) {
results.map(function (res) {
var subject = res.parts.filter(function (part) {return part.which === 'HEADER';})[0].body.subject[0];
console.log("Subject: " + subject);
// insert
var attributes = {
subject: subject
};
console.log("Attempting to insert to collection...");
var newData = TempEmailCollection.insert(attributes);
console.log("New Database Entry ID: " + newData);
});
});
});
})
}
});
The console.log with the subject is working. The insert is not working. No error, no console.log post insert, nothing.
I've tried both strategies recommended in the guide, neither work.
The problem is that you are calling a Meteor function inside asynchronously called Promise handlers.
However, all Meteor functions that are called on the server have to run in a fiber.
Meteor actually throws an error in this case but you are ignoring it because you haven't specified catch functions for the Promises.
Consider the following simplified example (it just connects to the server and tries to insert a new document):
import { Meteor } from 'meteor/meteor';
import imaps from 'imap-simple';
const Storage = new Mongo.Collection('storage');
const config = {
imap: {
…
}
};
Meteor.methods({
connect() {
console.log('Method called');
imaps.connect(config).then(function(connection) {
console.log('Connected');
Storage.insert({
value: 'success'
});
console.log('Document inserted');
})
.catch(function(err) {
console.error(err);
});
}
});
The following message will arrive in the catch function:
[Error: Meteor code must always run within a Fiber. Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment.]
You could do something like this to wrap the insert call:
Meteor.methods({
connect() {
console.log('Method called');
const insert = Meteor.bindEnvironment(function() {
Storage.insert({
value: 'success'
});
});
imaps.connect(config).then(function(connection) {
console.log('Connected');
insert();
console.log('Document inserted');
})
.catch(function(err) {
console.error(err);
});
}
});
Then the document will be inserted as expected.

Call Magento SOAP inside Meteor method invoked by the client

I'm using zardak:soap package in Meteor to connect with Magento SOAP v2 API. I've created a file inside the 'server' folder where I create a soap connection on Meteor.startup. Then I run a ticker that invokes random soap method every 30sec just to keep the connection up.
let soapConnection;
Meteor.startup(() => {
soapConnection = createAPIConnection('http://magento.site.com/api/v2_soap/?wsdl=1', {username: 'user', apiKey: 'password'});
});
function createAPIConnection(url, credentials) {
try {
let client = Soap.createClient(url);
let loginResult = client.login(credentials);
let sessionId = loginResult.loginReturn.$value;
return {
conn: client,
sessionId: sessionId
};
} catch (e) {
if (e.error === 'soap-creation') {
console.log('SOAP Client creation failed');
}
return null;
}
}
function tick() {
try {
soapConnection.conn.catalogCategoryInfo({
sessionId: soapConnection.sessionId,
categoryId: 1
}, (err, result) => { });
} catch (e) { }
}
Then I have a Meteor method that is called from the client. When it is called, the soap method call fails and I'm getting a 'soap error' message in console.
Meteor.methods({
'createMagentoCustomer'(customer) {
try {
soapConnection.conn.customerCustomerCreate({
sessionId: soapConnection.sessionId,
customerData: customer
}, (err, res) => {
if (err)
console.log('soap error');
else
console.log(res);
});
} catch (e) {
console.log('SOAP Method <customerCustomerCreate> call failed');
}
},
});
So, the ticker works well with no problems, but when I try to call soap via Meteor method, it fails. Notice that the soapConnection method is not null and I do receive error in the soap method callback.
Any suggestions?
Meteor version 1.3.4.1

Categories

Resources