1

In my project I'm using Twitter API user timeline (both v1 and v2) and filtered stream (v2) with needle successfully, but I can't get the v1 version of filtered stream (statuses/filter) working with needle.

I feel clueless, as needle's streaming works fine with API v2 (just like the official example) and I've tested the authentication part (OAuth) of my v1 code and verified that it works well (response code: 200) - yet I'm not getting any data from the stream.

I even tried finding the problem by setting up Fiddler as a proxy of needle, but I saw nothing strange.

I've created an extracted, stand alone version of the v1 streaming module, hoping that someone can spot the issue/bug.

const uuid = require('uuid');
const oauth = require('oauth-sign');
const needle = require('needle');

const keys = {
    twitter: {
        consumerKey: '<your-consumerKey>', //API Key
        consumerSecretKey: '<your-consumerSecretKey>', //API Secret Key
        oauthToken: '<your-oauthToken>', //Access Token
        oauthTokenSecret: '<your-oauthTokenSecret>', //Access Token Secret
    }
};

const streamURL = 'https://stream.twitter.com/1.1/statuses/filter.json';

const apiParams = {
    'track': 'pizza',
};

function getAuthHeader() {
    const timestamp = Date.now() / 1000;
    const nonce = uuid.v4().replace(/-/g, '');

    let oauthParams = {
        'oauth_consumer_key': keys.twitter.consumerKey,
        'oauth_nonce': nonce,
        'oauth_signature_method': 'HMAC-SHA1',
        'oauth_timestamp': timestamp,
        'oauth_token': keys.twitter.oauthToken,
        'oauth_version': '1.0'
    };

    let mergedParams = { ...apiParams, ...oauthParams };

    oauthParams['oauth_signature'] = oauth.hmacsign(
        'POST', streamURL, mergedParams, 
        keys.twitter.consumerSecretKey, 
        keys.twitter.oauthTokenSecret
    );

    return Object.keys(oauthParams).sort().map(function (k) {
        return k + '="' + oauth.rfc3986(oauthParams[k]) + '"';
    }).join(', ');
}

function streamConnect(retryAttempt) {
    const stream = needle.post(streamURL, apiParams, {
        headers: {
            'Authorization': `OAuth ${getAuthHeader()}`,
            'Content-Type': 'application/x-www-form-urlencoded',
        },
        timeout: 20000
    });

    stream.on('header', (statusCode, headers) => {
        console.log(
            `Status: ${statusCode} ` + 
            `(${statusCode === 200 ? 'OK' : 'ERROR'})`
        );
    }).on('data', data => {
        //never receiving any data ???
        console.log('data received:');
        console.log(data);
    }).on('err', error => {
        // This reconnection logic will attempt to reconnect when a disconnection is detected.
        // To avoid rate limits, this logic implements exponential backoff, so the wait time
        // will increase if the client cannot reconnect to the stream. 
        let retryTimeout = 2 ** retryAttempt;
        console.warn(`A connection error occurred: ${error.message}. Reconnecting in ${retryTimeout/1000} seconds...`)
        setTimeout(() => {
            streamConnect(++retryAttempt);
        }, retryTimeout);
    });

    return stream;
}

streamConnect(0);

(I know that there are a couple of libraries that I could use, but 1: I don't want to use one just because of this bug, 2: I truly hate when I can't find a solution for a problem)

frzsombor
  • 2,274
  • 1
  • 22
  • 40

0 Answers0