+48
-46
@@ -130,56 +130,58 @@ // | ||
| this.request.on('response', function (response) { | ||
| res = response | ||
| res.setEncoding('utf8') | ||
| res = response | ||
| self.emit('connected', res) | ||
| res.setEncoding('utf8') | ||
| //pass all response data to parser to get parsed | ||
| res.on('data', function (chunk) { | ||
| //reset stall timer | ||
| self.resetStallTimer() | ||
| self.parser.parse(chunk) | ||
| }) | ||
| //pass all response data to parser | ||
| res.on('data', function (chunk) { | ||
| self.resetStallTimer() | ||
| self.parser.parse(chunk) | ||
| }) | ||
| //tcp errors: | ||
| //250ms , increment linearly til 16s | ||
| //http errors: | ||
| //5s, double til 320s | ||
| // | ||
| //back off linearly @ 250ms til 16s, then double til 320s | ||
| .on('close', function () { | ||
| self.stopStallTimer() | ||
| }); | ||
| //self.abortedBy gets set to `twit-client` if twit.stop() is called. | ||
| //Since we stopped it explicity, don't try to reconnect | ||
| if (self.abortedBy === 'twit-client') | ||
| return | ||
| //tcp errors: | ||
| //250ms , increment linearly til 16s | ||
| //http errors: | ||
| //5s, double til 320s | ||
| // | ||
| //back off linearly @ 250ms til 16s, then double til 320s | ||
| this.request.on('close', function () { | ||
| self.stopStallTimer() | ||
| //remember we got disconnected by Twitter and the reconnect is | ||
| //about to get scheduled | ||
| self.abortedBy = 'twitter' | ||
| //self.abortedBy gets set to `twit-client` if twit.stop() is called. | ||
| //Since we stopped it explicity, don't try to reconnect | ||
| if (self.abortedBy === 'twit-client') | ||
| return | ||
| if (self.connectInterval === undefined) { | ||
| self.connectInterval = 0 | ||
| return self.keepAlive() | ||
| } | ||
| //rate limited - back off for a minute (danger of getting blocked by twitter) | ||
| if (res && res.statusCode === 420) | ||
| self.connectInterval = 60000 | ||
| //increment by 250ms linearly til 16s | ||
| else if (self.connectInterval < 16000) | ||
| self.connectInterval += 250 | ||
| //double til 320s | ||
| else if (self.connectInterval >= 16000 && self.connectInterval <= 320000) | ||
| self.connectInterval = 2*self.connectInterval | ||
| //remember we got disconnected by Twitter and the reconnect is | ||
| //about to get scheduled | ||
| self.abortedBy = 'twitter' | ||
| self.emit('reconnect', self.request, res, self.connectInterval) | ||
| if (self.connectInterval === undefined && res && res.statusCode !== 420) { | ||
| self.connectInterval = 0 | ||
| return self.keepAlive() | ||
| } | ||
| //rate limited - back off for a minute (danger of getting blocked by twitter) | ||
| if (res && res.statusCode === 420) | ||
| self.connectInterval = 60000 | ||
| //increment by 250ms linearly til 16s | ||
| else if (self.connectInterval < 16000) | ||
| self.connectInterval += 250 | ||
| //double til 320s | ||
| else if (self.connectInterval >= 16000 && self.connectInterval <= 320000) | ||
| self.connectInterval = 2*self.connectInterval | ||
| setTimeout(function () { | ||
| self.keepAlive() | ||
| }, self.connectInterval) | ||
| }) | ||
| .on('error', function (err) { | ||
| self.stopStallTimer() | ||
| }) | ||
| .end() | ||
| self.emit('reconnect', self.request, res, self.connectInterval) | ||
| setTimeout(function () { | ||
| self.keepAlive() | ||
| }, self.connectInterval) | ||
| }); | ||
| this.request.on('error', function (err) { | ||
| self.stopStallTimer() | ||
| }); | ||
| this.request.end(); | ||
| this.emit('connect', this.request) | ||
@@ -186,0 +188,0 @@ |
+2
-2
| { | ||
| "name": "twit", | ||
| "description": "Twitter API client for node (REST & Streaming)", | ||
| "version": "1.1.13", | ||
| "version": "1.1.14", | ||
| "author": "Tolga Tezel", | ||
@@ -32,4 +32,4 @@ "keywords": [ | ||
| "scripts": { | ||
| "test": "./node_modules/.bin/mocha tests/* -t 30000 -R spec" | ||
| "test": "./node_modules/.bin/mocha tests/* -t 60000 -R spec" | ||
| } | ||
| } |
+13
-0
@@ -218,2 +218,12 @@ #twit | ||
| ##event: 'connected' | ||
| Emitted when the response is received from Twitter. The http `response` object is emitted. | ||
| ```javascript | ||
| stream.on('connected', function (response) { | ||
| //... | ||
| }) | ||
| ``` | ||
| ##event: 'reconnect' | ||
@@ -398,2 +408,5 @@ | ||
| ###1.1.14 | ||
| * Emit `connected` event upon receiving the response from twitter | ||
| ###1.0.0 | ||
@@ -400,0 +413,0 @@ * now to stop and start the stream, use `stream.stop()` and `stream.start()` instead of emitting the `start` and `stop` events |
+53
-25
@@ -1,33 +0,61 @@ | ||
| var Twit = require('../lib/twitter') | ||
| , config1 = require('../config1') | ||
| , colors = require('colors') | ||
| var assert = require('assert'); | ||
| var Twit = require('../lib/twitter'); | ||
| var config1 = require('../config1'); | ||
| var colors = require('colors'); | ||
| var restTest = require('./rest.js'); | ||
| /* | ||
| skip this test unless specifically needed, since twitter tolerates | ||
| multiple connections sometimes, and sometimes not. | ||
| Don't run these tests often otherwise Twitter will rate limit you | ||
| */ | ||
| Twitter is not consistent enough to merit running this every time | ||
| and expecting extra streams to close. If running this test, increase | ||
| the test timeout to make sure twitter sends back `disconnect` objects | ||
| before the timeout. | ||
| */ | ||
| describe.skip('multiple connections', function () { | ||
| var twit = new Twit(config1) | ||
| it('results in one of the streams closing', function (done) { | ||
| var twit = new Twit(config1); | ||
| var streamFoo = twit.stream('statuses/sample'); | ||
| var streamBar = twit.stream('statuses/sample'); | ||
| var streamFoo = twit.stream('statuses/sample') | ||
| var streamBar = twit.stream('statuses/sample') | ||
| streamFoo.on('disconnect', function (disconnect) { | ||
| assert.equal(typeof disconnect, 'object'); | ||
| assert.equal(streamFoo.abortedBy, 'twit-client'); | ||
| done(); | ||
| }); | ||
| it('results in one of the streams closing', function (done) { | ||
| streamFoo.on('disconnect', function (disconnect) { | ||
| assert.equal(typeof disconnect, 'object') | ||
| assert.equal(streamFoo.abortedBy, 'twit-client') | ||
| done() | ||
| }) | ||
| streamBar.on('disconnect', function (disconnect) { | ||
| assert.equal(typeof disconnect, 'object'); | ||
| assert.equal(streamBar.abortedBy, 'twit-client'); | ||
| done(); | ||
| }); | ||
| }); | ||
| }); | ||
| streamBar.on('disconnect', function (disconnect) { | ||
| assert.equal(typeof disconnect, 'object') | ||
| assert.equal(streamBar.abortedBy, 'twit-client') | ||
| done() | ||
| describe.skip('Managing multiple streams legally', function () { | ||
| this.timeout(60000); | ||
| it('updating track keywords without losing data', function (done) { | ||
| var twit = new Twit(config1); | ||
| var stream1 = twit.stream('statuses/filter', { track: ['#no'] }); | ||
| stream1.once('tweet', function (tweet) { | ||
| console.log('got tweet from first stream') | ||
| restTest.checkTweet(tweet); | ||
| restTest.assertTweetHasText(tweet, '#no'); | ||
| // update our track list and initiate a new connection | ||
| var stream2 = twit.stream('statuses/filter', { track: ['#fun'] }); | ||
| stream2.once('connected', function (res) { | ||
| console.log('second stream connected') | ||
| // stop the first stream immediately | ||
| stream1.stop(); | ||
| assert.equal(res.statusCode, 200) | ||
| stream2.once('tweet', function (tweet) { | ||
| restTest.checkTweet(tweet); | ||
| restTest.assertTweetHasText(tweet, '#fun'); | ||
| return done(); | ||
| }) | ||
| }) | ||
| }) | ||
| }); | ||
| }); | ||
| }); | ||
| }); |
+13
-5
@@ -8,4 +8,8 @@ var assert = require('assert') | ||
| describe('REST API', function () { | ||
| var twit = new Twit(config1) | ||
| var twit = null | ||
| before(function () { | ||
| twit = new Twit(config1); | ||
| }) | ||
| it('GET `account/verify_credentials`', function (done) { | ||
@@ -172,4 +176,4 @@ twit.get('account/verify_credentials', function (err, reply, response) { | ||
| it('GET `search/tweets` { q: "banana since:2011-11-11" }', function (done) { | ||
| var params = { q: 'banana since:2011-11-11', count: 100 } | ||
| it('GET `search/tweets` { q: "fun since:2011-11-11" }', function (done) { | ||
| var params = { q: 'fun since:2011-11-11', count: 100 } | ||
| twit.get('search/tweets', params, function (err, reply, response) { | ||
@@ -180,3 +184,3 @@ checkReply(err, reply) | ||
| console.log('\nnumber of banana statuses:', reply.statuses.length) | ||
| console.log('\nnumber of fun statuses:', reply.statuses.length) | ||
@@ -479,3 +483,3 @@ checkResponse(response) | ||
| */ | ||
| function checkTweet (tweet) { | ||
| var checkTweet = exports.checkTweet = function (tweet) { | ||
| assert.ok(tweet) | ||
@@ -514,1 +518,5 @@ assert.equal('string', typeof tweet.id_str, 'id_str wasnt string:'+tweet.id_str) | ||
| } | ||
| exports.assertTweetHasText = function (tweet, text) { | ||
| assert(tweet.text.toLowerCase().indexOf(text) !== -1, 'expected to find '+text+' in text: '+tweet.text); | ||
| } |
+22
-11
@@ -10,5 +10,2 @@ var assert = require('assert') | ||
| var twit = new Twit(config1); | ||
| var twit2 = new Twit(config2) | ||
| /** | ||
@@ -22,6 +19,6 @@ * Stop the stream and check the tweet we got back. | ||
| exports.checkStream = function (stream, done) { | ||
| stream.on('connect', function () { | ||
| stream.once('connected', function () { | ||
| console.log('\nconnected'.grey) | ||
| stream.on('tweet', function (tweet) { | ||
| stream.once('tweet', function (tweet) { | ||
| assert.equal(null, stream.abortedBy) | ||
@@ -46,2 +43,3 @@ | ||
| it('statuses/sample', function (done) { | ||
| var twit = new Twit(config1); | ||
| var stream = twit.stream('statuses/sample') | ||
@@ -53,2 +51,3 @@ | ||
| it('statuses/filter using `track`', function (done) { | ||
| var twit = new Twit(config1); | ||
| var stream = twit.stream('statuses/filter', { track: 'apple' }) | ||
@@ -60,2 +59,3 @@ | ||
| it('statuses/filter using `location`', function (done) { | ||
| var twit = new Twit(config1); | ||
| var stream = twit.stream('statuses/filter', { locations: '-122.75,36.8,121.75,37.8,-74,40,73,41' }) | ||
@@ -67,2 +67,3 @@ | ||
| it('statuses/filter using `location` array for San Francisco', function (done) { | ||
| var twit = new Twit(config1); | ||
| var sanFrancisco = [ '-122.75', '36.8', '-121.75', '37.8' ] | ||
@@ -76,2 +77,3 @@ | ||
| it('statuses/filter using `location` array for San Francisco and New York', function (done) { | ||
| var twit = new Twit(config1); | ||
| var params = { | ||
@@ -87,4 +89,5 @@ locations: [ '-122.75', '36.8', '121.75', '37.8', '-74', '40', '73', '41' ] | ||
| it('statuses/filter using `track` array', function (done) { | ||
| var twit = new Twit(config1); | ||
| var params = { | ||
| track: [ 'spring', 'summer', 'fall', 'winter' ] | ||
| track: [ 'spring', 'summer', 'fall', 'winter', 'weather', 'joy', 'laugh', 'sleep' ] | ||
| } | ||
@@ -98,4 +101,5 @@ | ||
| it('statuses/filter using `track` and `language`', function (done) { | ||
| var twit = new Twit(config1); | ||
| var params = { | ||
| track: '#apple', | ||
| track: [ '#apple', 'google', 'twitter', 'facebook', 'happy', 'party', ':)' ], | ||
| language: 'en' | ||
@@ -110,2 +114,3 @@ } | ||
| it('stopping & restarting the stream works', function (done) { | ||
| var twit = new Twit(config1); | ||
| var stream = twit.stream('statuses/sample') | ||
@@ -123,3 +128,3 @@ | ||
| setTimeout(function () { | ||
| stream.on('connect', function (req) { | ||
| stream.once('connected', function (req) { | ||
| util.puts('\nrestarted stream') | ||
@@ -138,2 +143,3 @@ stream.stop() | ||
| it('stopping & restarting stream emits to previously assigned callbacks', function (done) { | ||
| var twit = new Twit(config1); | ||
| var stream = twit.stream('statuses/sample') | ||
@@ -191,2 +197,3 @@ | ||
| var dmId | ||
| var twit, twit2 | ||
@@ -196,2 +203,4 @@ before(function (done) { | ||
| // has to follow the sender | ||
| twit = new Twit(config1); | ||
| twit2 = new Twit(config2); | ||
@@ -252,5 +261,6 @@ async.parallel({ | ||
| listenForDm: function (parNext) { | ||
| console.log('\nlistening for DMs') | ||
| // listen for direct_message event and check DM once it's received | ||
| receiverStream.on('direct_message', function (directMsg) { | ||
| receiverStream.once('direct_message', function (directMsg) { | ||
| console.log('got DM') | ||
| restTest.checkDm(directMsg.direct_message) | ||
@@ -268,2 +278,3 @@ | ||
| // post a direct message from the sender's account | ||
| console.log('posting DM') | ||
| twit.post('direct_messages/new', dmParams, function (err, reply) { | ||
@@ -274,2 +285,3 @@ assert(!err, err) | ||
| dmId = reply.id_str | ||
| assert(dmId) | ||
@@ -279,3 +291,2 @@ restTest.checkDm(reply) | ||
| assert.equal(reply.text, dmParams.text) | ||
| assert(dmId) | ||
@@ -282,0 +293,0 @@ return parNext() |
@@ -16,4 +16,8 @@ var assert = require('assert') | ||
| describe('user events', function () { | ||
| var twit = new Twit(config1) | ||
| var twit; | ||
| before(function () { | ||
| twit = new Twit(config1); | ||
| }); | ||
| it('friends', function (done) { | ||
@@ -20,0 +24,0 @@ var ustream = twit.stream('user') |
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
57543
3.29%1375
3.31%427
3.14%