0

I've got socket.io set up with node.js. My scenario is a user/client supplies a twitter screen_name to follow, and then I need to subscribe to that twitter stream using the supplied screen_name (for some asinine reason the API requires a user_id instead of a screen_name).

I've run into a sequence problem where I have to subscribe to the stream before I know the screen_name (and subsequently the user_id):

var tweetStream;

io.sockets.on('connection', function connect( socket )
{
  socket.on('subscribe', function(data)
  {
    twitter.get(
      'statuses/user_timeline',
      { "screen_name": data.screen_name },
      function getTweets( err , tweets )
      {
        // …
        // var user_id …

        tweetStream = twitter.stream('statuses/filter', { "follow": user_id });
        console.log('\n','tweetStream: ', tweetStream, '\n');

        tweetStream.on('tweet', function onTweet(tweet)
        {
          console.log( '\ntweetStream -> new tweet: ', tweet, '\n' );
          io.sockets.in( data.screen_name ).emit('tweets', tweet );
        });
      }
    );
  });
}

The above does not subscribe to the tweetstream and does not produce an error. If I move the tweetStream code outside of socket.io and hard-code a user_id (because it's otherwise not available), it works:

var tweetStream;

io.sockets.on('connection', function connect( socket )
{
  …
}

tweetStream = twitter.stream('statuses/filter', { "follow": 6253282 });
console.log('\n','tweetStream: ', tweetStream, '\n');

tweetStream.on('tweet', function onTweet(tweet)
{
  console.log( '\ntweetStream -> new tweet: ', tweet, '\n' )
  io.sockets.in( tweet.user.screen_name ).emit('tweets', data );
});

EDIT

The tweetStream objects in both cases are identical (compared via FileMerge).

Here's a Gist with the complete code.

Jakob Jingleheimer
  • 30,952
  • 27
  • 76
  • 126
  • Assuming that the problem isn't related to the code getting the `user_id`, and `data.screen_name` is valid, you're still using a global `tweetStream` variable which will be overwritten with any new incoming subscription. – robertklep Dec 15 '13 at 08:28
  • @robertklep, the `user_id` and `screen_names` are valid etc. I need to be able to access the stream outside *connection* to check if the stream should be closed (if no-one is listening). – Jakob Jingleheimer Dec 15 '13 at 09:02
  • Can't you listen for `disconnect` events on each socket? – robertklep Dec 15 '13 at 09:20
  • Ohh you're right. I thought i saw `io.sockets.on('disconnect',…)`, but according to the [exposed events doc](https://github.com/LearnBoost/socket.io/wiki/Exposed-events) it's per-socket. Sooo, if I remove the global pointer for `tweetStream`, it will fire and subscribe? – Jakob Jingleheimer Dec 15 '13 at 09:30
  • I don't know, try it :) If it doesn't work, you should add some debugging statements and/or error handlers to see where exactly it starts to fail. – robertklep Dec 15 '13 at 09:34
  • @robertklep, to be clear, it does not produce an error; the on("tweet") callback doesn't fire when a new tweet is created. I compared (using FileMerge) the `tweetStream` object of both the working on and the non-working one, and they are identical. Also, I removed the global `tweetStream` (and put `var` in front of real initter), but that didn't seem to make a difference (the logger after the tweetStream initialiser prints the tweetStream object to Terminal). – Jakob Jingleheimer Dec 15 '13 at 19:38

1 Answers1

0

The problem was that the twitter instance needs to be instantiated inside the socket.on('subscribe') callback:

// …
var io      = require('socket.io').listen(server);
var Twit    = require('twit');

io.sockets.on('connection', function connect( socket )
{
    //…
    socket.on('subscribe', function subscribe( data )
    {
        var twitter = new Twit({ … });
        // …
    });
    //…
});
Jakob Jingleheimer
  • 30,952
  • 27
  • 76
  • 126