Commit 68af74be authored by Iván Sánchez Ortega's avatar Iván Sánchez Ortega

timelocks, 280 char limit, some sanity checks around

parent 9b4cad5b
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -7,6 +7,7 @@ import chalk from 'chalk256';
import Mastodon from 'mastodon-api';
import striptags from 'striptags';
import he from 'he';
import TimeLock from '../timelock';
// 🍂class MastodonAccount
......@@ -16,7 +17,12 @@ import he from 'he';
class MastodonAccount extends Account {
constructor(callback, vorpal, accountNumber, opts) {
super.constructor(callback, opts);
// this._timers = {};
/// FIXME: DEBUG!!!!
// return;
this._opts = Object.assign({
// colour: 'grey'
......@@ -30,6 +36,9 @@ class MastodonAccount extends Account {
this._vorpal = vorpal;
this._accountNumber = accountNumber;
let initialTimeLock = new TimeLock();
this.emit(-Infinity, initialTimeLock.promise);
this._masto.get('accounts/verify_credentials')
/*.then(response=>response.json()).*/
.then(json=> {
......@@ -52,11 +61,17 @@ class MastodonAccount extends Account {
vorpal.log(chalk.red.bold(err));
});
let homeTimeLock = new TimeLock();
this.emit(-Infinity, homeTimeLock.promise);
let notificationsTimeLock = new TimeLock();
this.emit(-Infinity, notificationsTimeLock.promise);
this._masto.get('timelines/home', (err, msgs, response) =>{
for (let i=msgs.length-1; i>=0; i--) {
this._normalizeAndEmitUpdate('home', msgs[i]);
// vorpal.log('timelines/home', msgs);
}
homeTimeLock.unlock();
});
this._masto.get('notifications', (err, msgs, response) =>{
......@@ -67,6 +82,7 @@ class MastodonAccount extends Account {
this._normalizeAndEmitNotification('notifications', msgs[i]);
// vorpal.log('timelines/notifications', msgs);
}
notificationsTimeLock.unlock();
});
// let publicListener = this._masto.stream('streaming/public');
......@@ -75,11 +91,8 @@ class MastodonAccount extends Account {
// vorpal.log(chalk.red.bold(err));
// });
initialTimeLock.unlock();
});
return super.constructor(callback, opts);
}
listen(channel) {
......
File mode changed from 100644 to 100755
......@@ -119,6 +119,7 @@ class TwitterAccount extends Account {
// });
this.listen('home');
this.listen('mentions');
// let searchTimelineLock = new TimeLock();
// this.emit(-Infinity, searchTimelineLock.promise);
......@@ -183,12 +184,20 @@ class TwitterAccount extends Account {
endpoint = 'statuses/home_timeline';
opts.count = 100;
// This not-clearly-documented option makes the tweets have the full text,
// and never be truncated.
opts.tweet_mode = 'extended';
} else if (channel === 'mentions') {
rateLimitGroup = 'statuses';
endpoint = 'statuses/mentions_timeline';
opts.count = 100;
// This not-clearly-documented option makes the tweets have the full text,
// and never be truncated.
opts.tweet_mode = 'extended';
} else if (channel.match(/^search\//)) {
rateLimitGroup = 'statuses';
endpoint = 'statuses/home_timeline';
endpoint = 'statuses/mentions_timeline';
opts.count = 100;
// This not-clearly-documented option makes the tweets have the full text,
......@@ -215,33 +224,47 @@ class TwitterAccount extends Account {
this._tw.get(endpoint, opts, (err, msgs, response)=>{
if (err) {
this._vorpal.log(chalk.red(err));
this._vorpal.log(chalk.red('Error while requesting ' + endpoint + ':' + err));
}
// Update rate limits based on HTTP headers from the API server
if (response.headers['x-rate-limit-remaining']) {
this._rateLimits.resources[rateLimitGroup]['/' + endpoint].remaining = response.headers['x-rate-limit-remaining'];
}
if (response.headers['x-rate-limit-reset']) {
this._rateLimits.resources[rateLimitGroup]['/' + endpoint].reset = response.headers['x-rate-limit-reset'];
}
if (msgs.statuses) {msgs = msgs.statuses;}
for (let i=msgs.length-1; i>=0; i--) {
// console.log(msgs[i]);
this._normalizeAndEmitUpdate(msgs[i], 'home');
// this._vorpal.log('timelines/home', msgs);
}
if (response) {
// Update rate limits based on HTTP headers from the API server
// TODO: Check if this equals the expected limit, and if not,
// agressively throttle down the expected remaining limit.
if (response.headers['x-rate-limit-remaining']) {
this._rateLimits.resources[rateLimitGroup]['/' + endpoint].remaining = Number(response.headers['x-rate-limit-remaining']);
}
if (response.headers['x-rate-limit-reset']) {
this._rateLimits.resources[rateLimitGroup]['/' + endpoint].reset = Number(response.headers['x-rate-limit-reset']);
}
// this._vorpal.log(
// chalk.purple('>>> Got data at'),
// chalk.cyan(this._formatTimestamp(Date.now())),
// chalk.purple(', updated rate limit is '),
// chalk.cyan(this._rateLimits.resources[rateLimitGroup]['/' + endpoint].remaining)
// );
if (msgs.statuses) {msgs = msgs.statuses;}
for (let i=msgs.length-1; i>=0; i--) {
// console.log(msgs[i]);
this._normalizeAndEmitUpdate(msgs[i], channel);
// this._vorpal.log('timelines/home', msgs);
}
if (msgs[0]) {
this._lastStatusesPerChannel[channel] = msgs[0].id_str;
if (msgs[0]) {
this._lastStatusesPerChannel[channel] = msgs[0].id_str;
}
this._requestChannelOnce(channel);
} else {
// No response? Maybe there's a network problem. Retry in 10 seconds.
setTimeout(()=>{this._requestChannelOnce(channel);}, 10000);
}
// console.log('TW removed home timeline lock');
timeLock.unlock();
// ...and loop ad aeterna.
this._requestChannelOnce(channel);
return;
});
});
......@@ -285,12 +308,12 @@ class TwitterAccount extends Account {
if (!this._rateLimitResets[ limit.reset ]){
this._rateLimitResets[ limit.reset ] = new Promise((resolve)=>{
let millisecondsToReset = (limit.reset * 1000 - Date.now()) + 2000;
this._vorpal.log(
chalk.purple('>>> Reset timestamp for rate limit on '),
chalk.cyan(endpoint),
chalk.purple('reached, will re-requesting all rate limits at'),
chalk.cyan(this._formatTimestamp(limit.reset * 1000))
);
// this._vorpal.log(
// chalk.purple('>>> Reset timestamp for rate limit on '),
// chalk.cyan(endpoint),
// chalk.purple('reached, will re-requesting all rate limits at'),
// chalk.cyan(this._formatTimestamp(limit.reset * 1000))
// );
setTimeout(()=>{
resolve(this._refreshRateLimits());
}, millisecondsToReset);
......@@ -334,29 +357,28 @@ class TwitterAccount extends Account {
return this._rateLimitResets[ limit.reset ].then(()=>this._waitRateLimit(group, endpoint));
} else if (limit.remaining === rateOffset) {
// Wait exactly until the next rate reset
this._vorpal.log(
chalk.purple('>>> Twitter rate limit exactly hit, waiting until next reset, at '),
chalk.cyan(this._formatTimestamp(Date.now() + millisecondsToReset))
);
// this._vorpal.log(
// chalk.purple('>>> Twitter rate limit exactly hit, waiting until next reset, at '),
// chalk.cyan(this._formatTimestamp(Date.now() + millisecondsToReset))
// );
this._decreaseRateLimits(group, endpoint);
return this._rateLimitResets[ limit.reset ];
} else if (!immediate) {
delay = millisecondsToReset / (limit.remaining - rateOffset);
}
this._vorpal.log(
chalk.purple('>>> Queueing request to endpoint '),
chalk.cyan(endpoint),
chalk.purple(', will wait '),
chalk.cyan((delay/1000).toFixed(2)),
chalk.purple(' seconds (until'),
chalk.cyan(this._formatTimestamp(Date.now() + delay)),
chalk.purple('), rate limits are: '),
chalk.cyan(limit),
chalk.purple(' next reset at: '),
chalk.cyan(this._formatTimestamp(limit.reset * 1000))
);
// this._vorpal.log(
// chalk.purple('>>> Queueing request to endpoint '),
// chalk.cyan(endpoint),
// chalk.purple(', will wait '),
// chalk.cyan((delay/1000).toFixed(2)),
// chalk.purple(' seconds (until'),
// chalk.cyan(this._formatTimestamp(Date.now() + delay)),
// chalk.purple('), rate limits are: '),
// chalk.cyan(limit),
// chalk.purple(' next reset at: '),
// chalk.cyan(this._formatTimestamp(limit.reset * 1000))
// );
return new Promise((resolve)=>{
setTimeout(resolve, delay);
......@@ -368,14 +390,14 @@ class TwitterAccount extends Account {
_refreshRateLimits() {
return this._getEndpointPromise('application/rate_limit_status').then((rateLimits=>{
this._rateLimits = rateLimits;
this._vorpal.log(
chalk.purple('>>> Rate limits for rate limits: '),
chalk.cyan(rateLimits.resources.application['/application/rate_limit_status'])
);
this._vorpal.log(
chalk.purple('>>> Rate limits for home timeline statuses: '),
chalk.cyan(rateLimits.resources.statuses['/statuses/home_timeline'])
);
// this._vorpal.log(
// chalk.purple('>>> Rate limits for rate limits: '),
// chalk.cyan(rateLimits.resources.application['/application/rate_limit_status'])
// );
// this._vorpal.log(
// chalk.purple('>>> Rate limits for home timeline statuses: '),
// chalk.cyan(rateLimits.resources.statuses['/statuses/home_timeline'])
// );
return rateLimits;
}));
}
......@@ -456,8 +478,13 @@ class TwitterAccount extends Account {
// Common to post, reply, replyall, echo
_post(payload) {
this._tw.post('statuses/update', payload, function(error, tweet, response) {
if(error) throw error;
payload.weighted_character_count = true; // Hackto enable 280chars
this._tw.post('statuses/update', payload, (error, tweet, response)=>{
if(error && error.length) {
this._vorpal.log(chalk.red('>>> Could not post to twitter: ' + error[0].message));
// throw error;
}
// console.log(tweet); // Tweet body.
// console.log(response); // Raw response object.
});
......
......@@ -116,7 +116,7 @@ function onItemReady(item) {
// https://stackoverflow.com/questions/10645994/node-js-how-to-format-a-date-string-in-utc
let timestampString =
new Date(item.timestamp)
(new Date(item.timestamp))
.toISOString()
.replace(/T/, ' ') // replace T with a space
.replace(/\..+/, ''); // delete the dot and everything after
......@@ -446,12 +446,15 @@ vorpal
.action((args, callback)=>{
if (args.id === undefined) {
this.log( chalk.red('>>> Specify item ID, e.g. "url ac7".'));
vorpal.log( chalk.red('>>> Specify item ID, e.g. "url ac7".'));
} else {
let item = circularBuffer.get(args.id);
if (!item) {
vorpal.log( chalk.red('>>> Specified item ID ' + args.id + ' does not exist'));
return;
}
let str = args.str.join(' ');
vorpal.log(chalk.green('Should reply with: ' + args.str.join(' ')));
// this.cancel();
......@@ -467,9 +470,13 @@ vorpal
.action((args, callback)=>{
if (args.id === undefined) {
this.log( chalk.red('>>> Specify item ID, e.g. "url ac7".'));
vorpal.log( chalk.red('>>> Specify item ID, e.g. "url ac7".'));
} else {
let item = circularBuffer.get(args.id);
if (!item) {
vorpal.log( chalk.red('>>> Specified item ID ' + args.id + ' does not exist'));
return;
}
let fallbackStr = activeAccounts[Number(item.accountNumber)].echoify(item);
vorpal.log(chalk.green('String for fallback echo is: ' + fallbackStr));
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment