-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Twitter error checks #2416
Twitter error checks #2416
Changes from all commits
afd0773
f866e75
e8305f9
f546a2b
de453e9
e7d5e07
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ class TwitterBridge extends BridgeAbstract { | |
const API_URI = 'https://api.twitter.com'; | ||
const GUEST_TOKEN_USES = 100; | ||
const GUEST_TOKEN_EXPIRY = 10800; // 3hrs | ||
const API_RETRIES = 3; | ||
const CACHE_TIMEOUT = 300; // 5min | ||
const DESCRIPTION = 'returns tweets'; | ||
const MAINTAINER = 'pmaziere'; | ||
|
@@ -481,7 +482,7 @@ private static function compareTweetId($tweet1, $tweet2) { | |
|
||
//The aim of this function is to get an API key and a guest token | ||
//This function takes 2 requests, and therefore is cached | ||
private function getApiKey() { | ||
private function getApiKey($dumpToken) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the purpose of dumpToken? Flag to ignore cache with api key and guest token? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is to invalidate the cached guest token. I could also delete the token before calling getApiKey() the second time in getApiContents(), and not pass a flag. |
||
|
||
$cacheFac = new CacheFactory(); | ||
$cacheFac->setWorkingDir(PATH_LIB_CACHES); | ||
|
@@ -506,7 +507,7 @@ private function getApiKey() { | |
$data = $cache->loadData(); | ||
|
||
$apiKey = null; | ||
if($data === null || (time() - $refresh) > self::GUEST_TOKEN_EXPIRY) { | ||
if($dumpToken || $data === null || (time() - $refresh) > self::GUEST_TOKEN_EXPIRY) { | ||
$twitterPage = getContents('https://twitter.com'); | ||
|
||
$jsLink = false; | ||
|
@@ -543,9 +544,9 @@ private function getApiKey() { | |
$guestTokenUses = $gt_cache->loadData(); | ||
|
||
$guestToken = null; | ||
if($guestTokenUses === null || !is_array($guestTokenUses) || count($guestTokenUses) != 2 | ||
if($dumpToken || $guestTokenUses === null || !is_array($guestTokenUses) || count($guestTokenUses) != 2 | ||
|| $guestTokenUses[0] <= 0 || (time() - $refresh) > self::GUEST_TOKEN_EXPIRY) { | ||
$guestToken = $this->getGuestToken(); | ||
$guestToken = $this->getGuestToken($apiKey); | ||
if ($guestToken === null) { | ||
if($guestTokenUses === null) { | ||
returnServerError('Could not parse guest token'); | ||
|
@@ -568,24 +569,55 @@ private function getApiKey() { | |
|
||
// Get a guest token. This is different to an API key, | ||
// and it seems to change more regularly than the API key. | ||
private function getGuestToken() { | ||
$pageContent = getContents('https://twitter.com', array(), array(), true); | ||
|
||
$guestTokenRegex = '/gt=([0-9]*)/m'; | ||
preg_match_all($guestTokenRegex, $pageContent['header'], $guestTokenMatches, PREG_SET_ORDER, 0); | ||
if (!$guestTokenMatches) | ||
preg_match_all($guestTokenRegex, $pageContent['content'], $guestTokenMatches, PREG_SET_ORDER, 0); | ||
if (!$guestTokenMatches) return null; | ||
$guestToken = $guestTokenMatches[0][1]; | ||
private function getGuestToken($apiKey) { | ||
$headers = array( | ||
'authorization: Bearer ' . $apiKey, | ||
); | ||
$opts = array( | ||
CURLOPT_POST => 1, | ||
); | ||
|
||
try { | ||
$pageContent = getContents('https://api.twitter.com/1.1/guest/activate.json', $headers, $opts, true); | ||
$guestToken = json_decode($pageContent['content'])->guest_token; | ||
} catch (Exception $e) { | ||
$guestToken = null; | ||
} | ||
return $guestToken; | ||
} | ||
|
||
private function getApiContents($uri) { | ||
$apiKeys = $this->getApiKey(); | ||
$headers = array('authorization: Bearer ' . $apiKeys[0], | ||
'x-guest-token: ' . $apiKeys[1], | ||
); | ||
return getContents($uri, $headers); | ||
$dump = false; | ||
$lastCode = 500; | ||
for ($i = 1; $i <= self::API_RETRIES; $i++) { | ||
$apiKeys = $this->getApiKey($dump); | ||
$headers = array('authorization: Bearer ' . $apiKeys[0], | ||
'x-guest-token: ' . $apiKeys[1], | ||
); | ||
try { | ||
$answer = getContents($uri, $headers); | ||
return $answer; | ||
} catch (Exception $e) { | ||
// Sometimes Twitter invalidates our cached guest token, | ||
// and returns 403. When this happens, dump the cached token, | ||
// and retry. | ||
$lastCode = $e->getCode(); | ||
if ($lastCode == 403) { | ||
$dump = true; | ||
} else { | ||
throw $e; | ||
} | ||
} | ||
} | ||
// If we reach here, either we never got a guestToken (500), or the token was invalid (403), | ||
// so return a meaningful error. | ||
if ($lastCode == 500) { | ||
returnError('Could not obtain a guest token', 503); | ||
} else if ($lastCode = 403) { | ||
returnError('Our guest token is not valid', 503); | ||
} else { | ||
returnServerError('Unable to obtain contents'); | ||
} | ||
} | ||
|
||
private function getRestId($username) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you explain, why do we need it here? And why 600 (10 minutes)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm trying to tell the RSS reader that the error is temporary.
All the Twitter 403 errors I've received over the last few weeks have been temporary, so I wanted a way to tell the RSS reader to try again soon. I don't know if any readers treat 500 different from 503.
The 10 minutes is just a guess.