3 * StatusNet - the distributed open-source microblogging tool
4 * Copyright (C) 2010, StatusNet, Inc.
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 * Send a PuSH subscription verification from our internal hub.
22 * Queue up final distribution for
24 * @author Brion Vibber <brion@status.net>
26 class HubDistribQueueHandler extends QueueHandler
33 function handle($notice)
35 assert($notice instanceof Notice);
37 $this->pushUser($notice);
38 foreach ($notice->getGroups() as $group) {
39 $this->pushGroup($notice, $group->group_id);
44 function pushUser($notice)
46 // See if there's any PuSH subscriptions, including OStatus clients.
47 // @fixme handle group subscriptions as well
48 // http://identi.ca/api/statuses/user_timeline/1.atom
49 $feed = common_local_url('ApiTimelineUser',
50 array('id' => $notice->profile_id,
52 $this->pushFeed($feed, array($this, 'userFeedForNotice'), $notice);
55 function pushGroup($notice, $group_id)
57 $feed = common_local_url('ApiTimelineGroup',
58 array('id' => $group_id,
60 $this->pushFeed($feed, array($this, 'groupFeedForNotice'), $group_id, $notice);
64 * @param string $feed URI to the feed
65 * @param callable $callback function to generate Atom feed update if needed
66 * any additional params are passed to the callback.
68 function pushFeed($feed, $callback)
70 $hub = common_config('ostatus', 'hub');
72 $this->pushFeedExternal($feed, $hub);
78 $args = array_slice(func_get_args(), 2);
79 $atom = call_user_func_array($callback, $args);
80 $this->pushFeedInternal($atom, $sub);
82 common_log(LOG_INFO, "No PuSH subscribers for $feed");
88 * Ping external hub about this update.
89 * The hub will pull the feed and check for new items later.
90 * Not guaranteed safe in an environment with database replication.
92 * @param string $feed feed topic URI
93 * @param string $hub PuSH hub URI
94 * @fixme can consolidate pings for user & group posts
96 function pushFeedExternal($feed, $hub)
98 $client = new HTTPClient();
100 $data = array('hub.mode' => 'publish',
102 $response = $client->post($hub, array(), $data);
103 if ($response->getStatus() == 204) {
104 common_log(LOG_INFO, "PuSH ping to hub $hub for $feed ok");
107 common_log(LOG_ERR, "PuSH ping to hub $hub for $feed failed with HTTP " .
108 $response->getStatus() . ': ' .
109 $response->getBody());
111 } catch (Exception $e) {
112 common_log(LOG_ERR, "PuSH ping to hub $hub for $feed failed: " . $e->getMessage());
118 * Queue up direct feed update pushes to subscribers on our internal hub.
119 * @param string $atom update feed, containing only new/changed items
120 * @param HubSub $sub open query of subscribers
122 function pushFeedInternal($atom, $sub)
124 common_log(LOG_INFO, "Preparing $sub->N PuSH distribution(s) for $sub->topic");
125 $qm = QueueManager::get();
126 while ($sub->fetch()) {
127 $sub->distribute($atom);
132 * Build a single-item version of the sending user's Atom feed.
133 * @param Notice $notice
136 function userFeedForNotice($notice)
138 // @fixme this feels VERY hacky...
139 // should probably be a cleaner way to do it
142 $api = new ApiTimelineUserAction();
143 $api->prepare(array('id' => $notice->profile_id,
145 'max_id' => $notice->id,
146 'since_id' => $notice->id - 1));
147 $api->showTimeline();
148 $feed = ob_get_clean();
150 // ...and override the content-type back to something normal... eww!
151 // hope there's no other headers that got set while we weren't looking.
152 header('Content-Type: text/html; charset=utf-8');
154 common_log(LOG_DEBUG, $feed);
158 function groupFeedForNotice($group_id, $notice)
160 // @fixme this feels VERY hacky...
161 // should probably be a cleaner way to do it
164 $api = new ApiTimelineGroupAction();
165 $args = array('id' => $group_id,
167 'max_id' => $notice->id,
168 'since_id' => $notice->id - 1);
169 $api->prepare($args);
171 $feed = ob_get_clean();
173 // ...and override the content-type back to something normal... eww!
174 // hope there's no other headers that got set while we weren't looking.
175 header('Content-Type: text/html; charset=utf-8');
177 common_log(LOG_DEBUG, $feed);