2

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.

Community
  • 1
  • 1
benvenker
  • 355
  • 1
  • 3
  • 10

2 Answers2

2

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.

Community
  • 1
  • 1
benvenker
  • 355
  • 1
  • 3
  • 10
0

Here's my solution. It's very similar to benvenker's but includes extra lines of code to keep duplicate data from populating my local mongo database.

SMS = new Mongo.Collection('sms');

// Configure the Twilio client
var twilioClient = new Twilio({
  from: Meteor.settings.TWILIO.FROM,
  sid: Meteor.settings.TWILIO.SID,
  token: Meteor.settings.TWILIO.TOKEN
});
var getTwilioMessages = Meteor.wrapAsync(twilioClient.client.messages.list, twilioClient.client.messages);

function updateMessages() {
  getTwilioMessages(function(err, data) {
    if (err) {
      console.warn("There was an error getting data from twilio", err);
      return
    }
    data.messages.forEach(function(message) {
      if (SMS.find({
        sid: message.sid
      }).count() > 0) {
        return;
      }
      SMS.insert(message);
    });
  });
}

updateMessages();
Meteor.setInterval(updateMessages, 60000);

I couldn't have figured this out without the following really helpful blog post:

http://blog.jakegaylor.com/2015/11/26/hello-twilio-meteor-here/

roses
  • 1
  • 1