benvenker benvenker - 7 months ago 47
Javascript Question

Meteor: Get a list of SMS texts from Twilio and insert them into mongoDB

I'm trying to store SMS text message conversations in my app. Right now, I can successfully send SMS message via the Twilio API. Basically, I have a collection of pre-built messages, that show up in a table and each can be sent by clicking a "Text it" button. This works great.

I'm running into problems with storing the list of SMS texts that my Twilio number receives (i.e. in response to the texts that I send from the app). I am able to get the list of texts from Twilio.

Here's the Meteor method code I have that pulls the list of texts:

Meteor.methods({
getTexts: function() {

// Twilio Credentials
var accountSid = 'someTwilioSid';
var authToken = 'someAuthToken';
var twilio = Twilio(accountSid, authToken);

twilio.messages.list({}, function (err, data) {
var texts = [];
data.messages.forEach(function (message) {
var text = {
to: message.to,
from: message.from,
body: message.body
};
texts.push(text);
//Texts.insert(text); // Uncommenting this causes a Meteor.bindEnvironment error
console.log(text);
});
});
});


Which returns e.g., this JSON:

I20150314-15:12:08.823(-5)? { to: '+11234567891',
I20150314-15:12:08.823(-5)? from: '+11234567890',
I20150314-15:12:08.823(-5)? body: 'Hello, welcome to Twilio from the command line!' }
I20150314-15:12:08.823(-5)? { to: '+11234567891',
I20150314-15:12:08.823(-5)? from: '+11234567890',
I20150314-15:12:08.823(-5)? body: 'Hello, welcome to Twilio!' }


Looking good, except as soon as I uncomment the
Texts.insert(text)
, I get:

> Error: Meteor code must always run within a Fiber. Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment.


Here are the alternate versions of
getTexts
that I've tried, both which get me the
bindEnvironment
error when I uncomment the
Texts.insert(text)
line:

Using
Meteor.wrapAsync


Meteor.wrapAsync(twilio.messages.list({}, function (err, data) {
var texts = [];
data.messages.forEach(function (message) {
var text = {
to: message.to,
from: message.from,
body: message.body
};
texts.push(text);
//Texts.insert(text);
console.log(text);
});
}));


Using
Meteor.bindEnvironemnt


Meteor.bindEnvironment(twilio.messages.list({}, function (err, data) {
var texts = [];
data.messages.forEach(function (message) {
var text = {
to: message.to,
from: message.from,
body: message.body
};
texts.push(text);
//Texts.insert(text);
console.log(text);
});
}));


I've read Meteor: Proper use of Meteor.wrapAsync on server, which was definitely helpful in pointing me in the right direction, but I'm still having trouble.

Answer

OK, after taking a harder look at Meteor: Proper use of Meteor.wrapAsync on server, I came up with the solution below, which worked perfectly.

Meteor.methods({
  getTexts: function() {
    // Twilio Credentials
    var accountSid = 'someTwilioSid';
    var authToken = 'someAuthToken';
    var twilio = Twilio(accountSid, authToken);

    var twilioMessagesListSync = Meteor.wrapAsync(twilio.messages.list, twilio.messages);

    var result = twilioMessagesListSync(
      function (err, data) {
        var texts = [];
        data.messages.forEach(function (message) {
          var text = {
            to: message.to,
            from: message.from,
            body: message.body,
            dateSent: message.date_sent,
            status: message.status,
            direction: message.direction
          };
          texts.push(text);
          Texts.insert(text);
        })
      }
    );
  }
});

Hope this helps someone else out. Thanks to saimeunt for the excellent answer that ported pretty easily (in the end) to a Twilio application.