#!/usr/bin/env php . */ define('INSTALLDIR', realpath(dirname(__FILE__) . '/../../..')); // Tune number of processes and how often to poll Twitter // XXX: Should these things be in config.php? define('MAXCHILDREN', 2); define('POLL_INTERVAL', 60); // in seconds $shortoptions = 'di::'; $longoptions = array('id::', 'debug'); $helptext = << * @author Evan Prodromou * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ */ class TwitterStatusFetcher extends ParallelizingDaemon { /** * Constructor * * @param string $id the name/id of this daemon * @param int $interval sleep this long before doing everything again * @param int $max_children maximum number of child processes at a time * @param boolean $debug debug output flag * * @return void * **/ function __construct($id = null, $interval = 60, $max_children = 2, $debug = null) { parent::__construct($id, $interval, $max_children, $debug); } /** * Name of this daemon * * @return string Name of the daemon. */ function name() { return ('twitterstatusfetcher.'.$this->_id); } /** * Find all the Twitter foreign links for users who have requested * importing of their friends' timelines * * @return array flinks an array of Foreign_link objects */ function getObjects() { global $_DB_DATAOBJECT; $flink = new Foreign_link(); $conn = &$flink->getDatabaseConnection(); $flink->service = TWITTER_SERVICE; $flink->orderBy('last_noticesync'); $flink->find(); $flinks = array(); while ($flink->fetch()) { if (($flink->noticesync & FOREIGN_NOTICE_RECV) == FOREIGN_NOTICE_RECV) { $flinks[] = clone($flink); common_log(LOG_INFO, "sync: foreign id $flink->foreign_id"); } else { common_log(LOG_INFO, "nothing to sync"); } } $flink->free(); unset($flink); $conn->disconnect(); unset($_DB_DATAOBJECT['CONNECTIONS']); return $flinks; } function childTask($flink) { // Each child ps needs its own DB connection // Note: DataObject::getDatabaseConnection() creates // a new connection if there isn't one already $conn = &$flink->getDatabaseConnection(); $this->getTimeline($flink); $flink->last_friendsync = common_sql_now(); $flink->update(); $conn->disconnect(); // XXX: Couldn't find a less brutal way to blow // away a cached connection global $_DB_DATAOBJECT; unset($_DB_DATAOBJECT['CONNECTIONS']); } function getTimeline($flink) { if (empty($flink)) { common_log(LOG_WARNING, $this->name() . " - Can't retrieve Foreign_link for foreign ID $fid"); return; } common_debug($this->name() . ' - Trying to get timeline for Twitter user ' . $flink->foreign_id); $client = null; if (TwitterOAuthClient::isPackedToken($flink->credentials)) { $token = TwitterOAuthClient::unpackToken($flink->credentials); $client = new TwitterOAuthClient($token->key, $token->secret); common_debug($this->name() . ' - Grabbing friends timeline with OAuth.'); } else { common_debug("Skipping friends timeline for $flink->foreign_id since not OAuth."); } $timeline = null; $lastId = Twitter_synch_status::getLastId($flink->foreign_id, 'home_timeline'); common_debug("Got lastId value '{$lastId}' for foreign id '{$flink->foreign_id}' and timeline 'home_timeline'"); try { $timeline = $client->statusesHomeTimeline($lastId); } catch (Exception $e) { common_log(LOG_WARNING, $this->name() . ' - Twitter client unable to get friends timeline for user ' . $flink->user_id . ' - code: ' . $e->getCode() . 'msg: ' . $e->getMessage()); } if (empty($timeline)) { common_log(LOG_WARNING, $this->name() . " - Empty timeline."); return; } common_debug(LOG_INFO, $this->name() . ' - Retrieved ' . sizeof($timeline) . ' statuses from Twitter.'); $importer = new TwitterImport(); // Reverse to preserve order foreach (array_reverse($timeline) as $status) { $notice = $importer->importStatus($status); if (!empty($notice)) { Inbox::insertNotice($flink->user_id, $notice->id); } } if (!empty($timeline)) { $lastId = twitter_id($timeline[0]); Twitter_synch_status::setLastId($flink->foreign_id, 'home_timeline', $lastId); common_debug("Set lastId value '$lastId' for foreign id '{$flink->foreign_id}' and timeline 'home_timeline'"); } // Okay, record the time we synced with Twitter for posterity $flink->last_noticesync = common_sql_now(); $flink->update(); } } $id = null; $debug = null; if (have_option('i')) { $id = get_option_value('i'); } else if (have_option('--id')) { $id = get_option_value('--id'); } else if (count($args) > 0) { $id = $args[0]; } else { $id = null; } if (have_option('d') || have_option('debug')) { $debug = true; } $fetcher = new TwitterStatusFetcher($id, 60, 2, $debug); $fetcher->runOnce();