4 * StatusNet - the distributed open-source microblogging tool
5 * Copyright (C) 2008, 2009, StatusNet, Inc.
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
22 define('STATUSNET', true);
23 define('LACONICA', true); // compatibility
25 $shortoptions = 'di::';
26 $longoptions = array('id::', 'debug');
28 $helptext = <<<END_OF_TRIM_HELP
29 Batch script for synching local friends with Twitter friends.
30 -i --id Identity (default 'generic')
31 -d --debug Debug (lots of log output)
35 require_once INSTALLDIR . '/scripts/commandline.inc';
36 require_once INSTALLDIR . '/lib/parallelizingdaemon.php';
39 * Daemon to sync local friends with Twitter friends
43 * @author Zach Copley <zach@status.net>
44 * @author Evan Prodromou <evan@status.net>
45 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
46 * @link http://status.net/
49 $helptext = <<<END_OF_TWITTER_HELP
50 Batch script for synching local friends with Twitter friends.
54 require_once INSTALLDIR . '/scripts/commandline.inc';
55 require_once INSTALLDIR . '/lib/parallelizingdaemon.php';
57 class SyncTwitterFriendsDaemon extends ParallelizingDaemon
62 * @param string $id the name/id of this daemon
63 * @param int $interval sleep this long before doing everything again
64 * @param int $max_children maximum number of child processes at a time
65 * @param boolean $debug debug output flag
71 function __construct($id = null, $interval = 60,
72 $max_children = 2, $debug = null)
74 parent::__construct($id, $interval, $max_children, $debug);
80 * @return string Name of the daemon.
85 return ('synctwitterfriends.' . $this->_id);
89 * Find all the Twitter foreign links for users who have requested
90 * automatically subscribing to their Twitter friends locally.
92 * @return array flinks an array of Foreign_link objects
97 $flink = new Foreign_link();
99 $conn = &$flink->getDatabaseConnection();
101 $flink->service = TWITTER_SERVICE;
102 $flink->orderBy('last_friendsync');
103 $flink->limit(25); // sync this many users during this run
106 while ($flink->fetch()) {
107 if (($flink->friendsync & FOREIGN_FRIEND_RECV) == FOREIGN_FRIEND_RECV) {
108 $flinks[] = clone($flink);
114 global $_DB_DATAOBJECT;
115 unset($_DB_DATAOBJECT['CONNECTIONS']);
120 function childTask($flink) {
122 // Each child ps needs its own DB connection
124 // Note: DataObject::getDatabaseConnection() creates
125 // a new connection if there isn't one already
127 $conn = &$flink->getDatabaseConnection();
129 $this->subscribeTwitterFriends($flink);
131 $flink->last_friendsync = common_sql_now();
136 // XXX: Couldn't find a less brutal way to blow
137 // away a cached connection
139 global $_DB_DATAOBJECT;
140 unset($_DB_DATAOBJECT['CONNECTIONS']);
143 function fetchTwitterFriends($flink)
149 if (TwitterOAuthClient::isPackedToken($flink->credentials)) {
150 $token = TwitterOAuthClient::unpackToken($flink->credentials);
151 $client = new TwitterOAuthClient($token->key, $token->secret);
152 common_debug($this->name() . '- Grabbing friends IDs with OAuth.');
154 $client = new TwitterBasicAuthClient($flink);
155 common_debug($this->name() . '- Grabbing friends IDs with basic auth.');
159 $friends_ids = $client->friendsIds();
160 } catch (Exception $e) {
161 common_log(LOG_WARNING, $this->name() .
162 ' - cURL error getting friend ids ' .
163 $e->getCode() . ' - ' . $e->getMessage());
167 if (empty($friends_ids)) {
168 common_debug($this->name() .
169 " - Twitter user $flink->foreign_id " .
170 'doesn\'t have any friends!');
174 common_debug($this->name() . ' - Twitter\'s API says Twitter user id ' .
175 "$flink->foreign_id has " .
176 count($friends_ids) . ' friends.');
178 // Calculate how many pages to get...
179 $pages = ceil(count($friends_ids) / 100);
182 common_debug($this->name() . " - $user seems to have no friends.");
185 for ($i = 1; $i <= $pages; $i++) {
188 $more_friends = $client->statusesFriends(null, null, null, $i);
189 } catch (Exception $e) {
190 common_log(LOG_WARNING, $this->name() .
191 ' - cURL error getting Twitter statuses/friends ' .
192 "page $i - " . $e->getCode() . ' - ' .
196 if (empty($more_friends)) {
197 common_log(LOG_WARNING, $this->name() .
198 " - Couldn't retrieve page $i " .
199 "of Twitter user $flink->foreign_id friends.");
202 $friends = array_merge($friends, $more_friends);
209 function subscribeTwitterFriends($flink)
211 $friends = $this->fetchTwitterFriends($flink);
213 if (empty($friends)) {
214 common_debug($this->name() .
215 ' - Couldn\'t get friends from Twitter for ' .
216 "Twitter user $flink->foreign_id.");
220 $user = $flink->getUser();
222 foreach ($friends as $friend) {
224 $friend_name = $friend->screen_name;
225 $friend_id = (int) $friend->id;
227 // Update or create the Foreign_user record for each
230 if (!save_twitter_user($friend_id, $friend_name)) {
231 common_log(LOG_WARNING, $this-name() .
232 " - Couldn't save $screen_name's friend, $friend_name.");
236 // Check to see if there's a related local user
238 $friend_flink = Foreign_link::getByForeignID($friend_id,
241 if (!empty($friend_flink)) {
243 // Get associated user and subscribe her
245 $friend_user = User::staticGet('id', $friend_flink->user_id);
247 if (!empty($friend_user)) {
248 $result = subs_subscribe_to($user, $friend_user);
250 if ($result === true) {
252 $this->name() . ' - Subscribed ' .
253 "$friend_user->nickname to $user->nickname.");
255 common_debug($this->name() .
256 ' - Tried subscribing ' .
257 "$friend_user->nickname to $user->nickname - " .
272 if (have_option('i')) {
273 $id = get_option_value('i');
274 } else if (have_option('--id')) {
275 $id = get_option_value('--id');
276 } else if (count($args) > 0) {
282 if (have_option('d') || have_option('debug')) {
286 $syncer = new SyncTwitterFriendsDaemon($id, 60, 2, $debug);