const UNFAVORITE = 'http://ostatus.org/schema/1.0/unfavorite';
const UNFOLLOW = 'http://ostatus.org/schema/1.0/unfollow';
const LEAVE = 'http://ostatus.org/schema/1.0/leave';
+
+ // For simple profile-update pings; no content to share.
+ const UPDATE_PROFILE = 'http://ostatus.org/schema/1.0/update-profile';
}
class ActivityContext
--- /dev/null
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2010, StatusNet, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * @package QueueHandler
+ * @maintainer Brion Vibber <brion@status.net>
+ */
+
+class ProfileQueueHandler extends QueueHandler
+{
+
+ function transport()
+ {
+ return 'profile';
+ }
+
+ function handle($profile)
+ {
+ if (!($profile instanceof Profile)) {
+ common_log(LOG_ERR, "Got a bogus profile, not broadcasting");
+ return true;
+ }
+
+ if (Event::handle('StartBroadcastProfile', array($profile))) {
+ require_once(INSTALLDIR.'/lib/omb.php');
+ omb_broadcast_profile($profile);
+ }
+ Event::handle('EndBroadcastProfile', array($profile));
+ return true;
+ }
+
+}
$this->connect('sms', 'SmsQueueHandler');
}
+ // Broadcasting profile updates to OMB remote subscribers
+ $this->connect('profile', 'ProfileQueueHandler');
+
// XMPP output handlers...
if (common_config('xmpp', 'enabled')) {
// Delivery prep, read by queuedaemon.php:
return true;
}
-function common_broadcast_profile($profile)
+/**
+ * Broadcast profile updates to OMB and other remote subscribers.
+ *
+ * Since this may be slow with a lot of subscribers or bad remote sites,
+ * this is run through the background queues if possible.
+ */
+function common_broadcast_profile(Profile $profile)
{
- // XXX: optionally use a queue system like http://code.google.com/p/microapps/wiki/NQDQ
- require_once(INSTALLDIR.'/lib/omb.php');
- omb_broadcast_profile($profile);
- // XXX: Other broadcasts...?
+ $qm = QueueManager::get();
+ $qm->enqueue($profile, "profile");
return true;
}
$qm->connect('ostatus', 'OStatusQueueHandler');
// Outgoing from our internal PuSH hub
- $qm->connect('hubverify', 'HubVerifyQueueHandler');
+ $qm->connect('hubconf', 'HubConfQueueHandler');
$qm->connect('hubout', 'HubOutQueueHandler');
// Outgoing Salmon replies (when we don't need a return value)
- $qm->connect('salmonout', 'SalmonOutQueueHandler');
+ $qm->connect('salmon', 'SalmonQueueHandler');
// Incoming from a foreign PuSH hub
- $qm->connect('pushinput', 'PushInputQueueHandler');
+ $qm->connect('pushin', 'PushInQueueHandler');
return true;
}
return true;
}
+
+ /**
+ * Ping remote profiles with updates to this profile.
+ * Salmon pings are queued for background processing.
+ */
+ function onEndBroadcastProfile(Profile $profile)
+ {
+ $user = User::staticGet('id', $profile->id);
+
+ // Find foreign accounts I'm subscribed to that support Salmon pings.
+ //
+ // @fixme we could run updates through the PuSH feed too,
+ // in which case we can skip Salmon pings to folks who
+ // are also subscribed to me.
+ $sql = "SELECT * FROM ostatus_profile " .
+ "WHERE profile_id IN " .
+ "(SELECT subscribed FROM subscription WHERE subscriber=%d) " .
+ "OR group_id IN " .
+ "(SELECT group_id FROM group_member WHERE profile_id=%d)";
+ $oprofile = new Ostatus_profile();
+ $oprofile->query(sprintf($sql, $profile->id, $profile->id));
+
+ if ($oprofile->N == 0) {
+ common_log(LOG_DEBUG, "No OStatus remote subscribees for $profile->nickname");
+ return true;
+ }
+
+ $act = new Activity();
+
+ $act->verb = ActivityVerb::UPDATE_PROFILE;
+ $act->id = TagURI::mint('update-profile:%d:%s',
+ $profile->id,
+ common_date_iso8601(time()));
+ $act->time = time();
+ $act->title = _m("Profile update");
+ $act->content = sprintf(_m("%s has updated their profile page."),
+ $profile->getBestName());
+
+ $act->actor = ActivityObject::fromProfile($profile);
+ $act->object = $act->actor;
+
+ while ($oprofile->fetch()) {
+ $oprofile->notifyDeferred($act);
+ }
+
+ return true;
+ }
}
'post' => $post,
'hmac' => $hmac);
$qm = QueueManager::get();
- $qm->enqueue($data, 'pushinput');
+ $qm->enqueue($data, 'pushin');
}
/**
'token' => $token,
'retries' => $retries);
$qm = QueueManager::get();
- $qm->enqueue($data, 'hubverify');
+ $qm->enqueue($data, 'hubconf');
}
/**
return false;
}
- public function notifyActivity($activity)
+ /**
+ * Send a Salmon notification ping immediately, and confirm that we got
+ * an acceptable response from the remote site.
+ *
+ * @param mixed $entry XML string, Notice, or Activity
+ * @return boolean success
+ */
+ public function notifyActivity($entry)
{
if ($this->salmonuri) {
+ $salmon = new Salmon();
+ return $salmon->post($this->salmonuri, $this->notifyPrepXml($entry));
+ }
- $xml = '<?xml version="1.0" encoding="UTF-8" ?' . '>' .
- $activity->asString(true);
+ return false;
+ }
- $salmon = new Salmon(); // ?
+ /**
+ * Queue a Salmon notification for later. If queues are disabled we'll
+ * send immediately but won't get the return value.
+ *
+ * @param mixed $entry XML string, Notice, or Activity
+ * @return boolean success
+ */
+ public function notifyDeferred($entry)
+ {
+ if ($this->salmonuri) {
+ $data = array('salmonuri' => $this->salmonuri,
+ 'entry' => $this->notifyPrepXml($entry));
- return $salmon->post($this->salmonuri, $xml);
+ $qm = QueueManager::get();
+ return $qm->enqueue($data, 'salmon');
}
return false;
}
+ protected function notifyPrepXml($entry)
+ {
+ $preamble = '<?xml version="1.0" encoding="UTF-8" ?' . '>';
+ if (is_string($entry)) {
+ return $entry;
+ } else if ($entry instanceof Activity) {
+ return $preamble . $entry->asString(true);
+ } else if ($entry instanceof Notice) {
+ return $preamble . $entry->asAtomEntry(true, true);
+ } else {
+ throw new ServerException("Invalid type passed to Ostatus_profile::notify; must be XML string or Activity entry");
+ }
+ }
+
function getBestName()
{
if ($this->isGroup()) {
--- /dev/null
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2010, StatusNet, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * Send a PuSH subscription verification from our internal hub.
+ * @package Hub
+ * @author Brion Vibber <brion@status.net>
+ */
+class HubConfQueueHandler extends QueueHandler
+{
+ function transport()
+ {
+ return 'hubconf';
+ }
+
+ function handle($data)
+ {
+ $sub = $data['sub'];
+ $mode = $data['mode'];
+ $token = $data['token'];
+
+ assert($sub instanceof HubSub);
+ assert($mode === 'subscribe' || $mode === 'unsubscribe');
+
+ common_log(LOG_INFO, __METHOD__ . ": $mode $sub->callback $sub->topic");
+ try {
+ $sub->verify($mode, $token);
+ } catch (Exception $e) {
+ common_log(LOG_ERR, "Failed PuSH $mode verify to $sub->callback for $sub->topic: " .
+ $e->getMessage());
+ // @fixme schedule retry?
+ // @fixme just kill it?
+ }
+
+ return true;
+ }
+}
+
+++ /dev/null
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2010, StatusNet, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * Send a PuSH subscription verification from our internal hub.
- * @package Hub
- * @author Brion Vibber <brion@status.net>
- */
-class HubVerifyQueueHandler extends QueueHandler
-{
- function transport()
- {
- return 'hubverify';
- }
-
- function handle($data)
- {
- $sub = $data['sub'];
- $mode = $data['mode'];
- $token = $data['token'];
-
- assert($sub instanceof HubSub);
- assert($mode === 'subscribe' || $mode === 'unsubscribe');
-
- common_log(LOG_INFO, __METHOD__ . ": $mode $sub->callback $sub->topic");
- try {
- $sub->verify($mode, $token);
- } catch (Exception $e) {
- common_log(LOG_ERR, "Failed PuSH $mode verify to $sub->callback for $sub->topic: " .
- $e->getMessage());
- // @fixme schedule retry?
- // @fixme just kill it?
- }
-
- return true;
- }
-}
-
function pingReply($oprofile)
{
if ($this->user) {
- if (!empty($oprofile->salmonuri)) {
- // For local posts, send a Salmon ping to the mentioned
- // remote user or group.
- // @fixme as an optimization we can skip this if the
- // remote profile is subscribed to the author.
-
- common_log(LOG_INFO, "Prepping to send notice '{$this->notice->uri}' to remote profile '{$oprofile->uri}'.");
-
- $xml = '<?xml version="1.0" encoding="UTF-8" ?' . '>';
- $xml .= $this->notice->asAtomEntry(true, true);
-
- $data = array('salmonuri' => $oprofile->salmonuri,
- 'entry' => $xml);
-
- $qm = QueueManager::get();
- $qm->enqueue($data, 'salmonout');
- }
+ // For local posts, send a Salmon ping to the mentioned
+ // remote user or group.
+ // @fixme as an optimization we can skip this if the
+ // remote profile is subscribed to the author.
+ $oprofile->notifyDeferred($this->notice);
}
}
+++ /dev/null
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2010, StatusNet, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * Process a feed distribution POST from a PuSH hub.
- * @package FeedSub
- * @author Brion Vibber <brion@status.net>
- */
-
-class PushInputQueueHandler extends QueueHandler
-{
- function transport()
- {
- return 'pushinput';
- }
-
- function handle($data)
- {
- assert(is_array($data));
-
- $feedsub_id = $data['feedsub_id'];
- $post = $data['post'];
- $hmac = $data['hmac'];
-
- $feedsub = FeedSub::staticGet('id', $feedsub_id);
- if ($feedsub) {
- $feedsub->receive($post, $hmac);
- } else {
- common_log(LOG_ERR, "Discarding POST to unknown feed subscription id $feedsub_id");
- }
- return true;
- }
-}
--- /dev/null
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2010, StatusNet, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * Process a feed distribution POST from a PuSH hub.
+ * @package FeedSub
+ * @author Brion Vibber <brion@status.net>
+ */
+
+class PushInQueueHandler extends QueueHandler
+{
+ function transport()
+ {
+ return 'pushin';
+ }
+
+ function handle($data)
+ {
+ assert(is_array($data));
+
+ $feedsub_id = $data['feedsub_id'];
+ $post = $data['post'];
+ $hmac = $data['hmac'];
+
+ $feedsub = FeedSub::staticGet('id', $feedsub_id);
+ if ($feedsub) {
+ $feedsub->receive($post, $hmac);
+ } else {
+ common_log(LOG_ERR, "Discarding POST to unknown feed subscription id $feedsub_id");
+ }
+ return true;
+ }
+}
+++ /dev/null
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2010, StatusNet, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * Send a Salmon notification in the background.
- * @package OStatusPlugin
- * @author Brion Vibber <brion@status.net>
- */
-class SalmonOutQueueHandler extends QueueHandler
-{
- function transport()
- {
- return 'salmonout';
- }
-
- function handle($data)
- {
- assert(is_array($data));
- assert(is_string($data['salmonuri']));
- assert(is_string($data['entry']));
-
- $salmon = new Salmon();
- $salmon->post($data['salmonuri'], $data['entry']);
-
- // @fixme detect failure and attempt to resend
- return true;
- }
-}
--- /dev/null
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2010, StatusNet, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * Send a Salmon notification in the background.
+ * @package OStatusPlugin
+ * @author Brion Vibber <brion@status.net>
+ */
+class SalmonQueueHandler extends QueueHandler
+{
+ function transport()
+ {
+ return 'salmon';
+ }
+
+ function handle($data)
+ {
+ assert(is_array($data));
+ assert(is_string($data['salmonuri']));
+ assert(is_string($data['entry']));
+
+ $salmon = new Salmon();
+ $salmon->post($data['salmonuri'], $data['entry']);
+
+ // @fixme detect failure and attempt to resend
+ return true;
+ }
+}