OStatus: hooked up follow/unfollow events on Salmon endpoint to create/destroy remote subscriber relationships

This commit is contained in:
Brion Vibber 2010-02-19 12:08:07 -08:00
parent 114eb310ca
commit a1a3ab1c58
4 changed files with 81 additions and 24 deletions

View File

@ -253,17 +253,22 @@ class OStatusPlugin extends Plugin
*/ */
function onEndUnsubscribe($user, $other) function onEndUnsubscribe($user, $other)
{ {
if ($user instanceof Profile) {
$profile = $user;
} else if ($user instanceof Profile) {
$profile = $user->getProfile();
}
$oprofile = Ostatus_profile::staticGet('profile_id', $other->id); $oprofile = Ostatus_profile::staticGet('profile_id', $other->id);
if ($oprofile) { if ($oprofile) {
// Notify the remote server of the unsub, if supported. // Notify the remote server of the unsub, if supported.
$oprofile->notify($user->getProfile(), ActivityVerb::UNFOLLOW, $oprofile); $oprofile->notify($profile, ActivityVerb::UNFOLLOW, $oprofile);
// Drop the PuSH subscription if there are no other subscribers. // Drop the PuSH subscription if there are no other subscribers.
$sub = new Subscription(); $sub = new Subscription();
$sub->subscribed = $other->id; $sub->subscribed = $other->id;
$sub->limit(1); $sub->limit(1);
if (!$sub->find(true)) { if (!$sub->find(true)) {
common_log(LOG_INFO, "Unsubscribing from now-unused feed $oprofile->feeduri on hub $oprofile->huburi"); common_log(LOG_INFO, "Unsubscribing from now-unused feed $oprofile->feeduri");
$oprofile->unsubscribe(); $oprofile->unsubscribe();
} }
} }

View File

@ -68,14 +68,6 @@ class FeedSubSettingsAction extends ConnectSettingsAction
$profile = $user->getProfile(); $profile = $user->getProfile();
$fuser = null;
$flink = Foreign_link::getByUserID($user->id, FEEDSUB_SERVICE);
if (!empty($flink)) {
$fuser = $flink->getForeignUser();
}
$this->elementStart('form', array('method' => 'post', $this->elementStart('form', array('method' => 'post',
'id' => 'form_settings_feedsub', 'id' => 'form_settings_feedsub',
'class' => 'form_settings', 'class' => 'form_settings',

View File

@ -63,13 +63,17 @@ class SalmonAction extends Action
// XXX: check that document element is Atom entry // XXX: check that document element is Atom entry
// XXX: check the signature // XXX: check the signature
$this->act = new Activity($dom->documentElement); $entries = $dom->getElementsByTagNameNS(Activity::ATOM, 'entry');
if ($entries && $entries->length) {
// @fixme is it legit to have multiple entries?
$this->act = new Activity($entries->item(0), $dom->documentElement);
}
return true; return true;
} }
/** /**
* @fixme probably call Ostatus_profile::processFeed * Check the posted activity type and break out to appropriate processing.
*/ */
function handle($args) function handle($args)
@ -94,13 +98,19 @@ class SalmonAction extends Action
case ActivityVerb::FRIEND: case ActivityVerb::FRIEND:
$this->handleFollow(); $this->handleFollow();
break; break;
case ActivityVerb::UNFOLLOW:
$this->handleUnfollow();
break;
} }
Event::handle('EndHandleSalmon', array($this->user, $this->activity)); Event::handle('EndHandleSalmon', array($this->user, $this->activity));
} }
} }
/** /**
* @fixme probably call Ostatus_profile::processFeed * We've gotten a post event on the Salmon backchannel, probably a reply.
*
* @todo validate if we need to handle this post, then call into
* ostatus_profile's general incoming-post handling.
*/ */
function handlePost() function handlePost()
{ {
@ -116,43 +126,81 @@ class SalmonAction extends Action
} }
$profile = $this->ensureProfile(); $profile = $this->ensureProfile();
// @fixme do something with the post
} }
/** /**
* @fixme probably call Ostatus_profile::processFeed * We've gotten a follow/subscribe notification from a remote user.
* Save a subscription relationship for them.
*/ */
function handleFollow() function handleFollow()
{ {
$oprofile = $this->ensureProfile();
if ($oprofile) {
common_log(LOG_INFO, "Setting up subscription from remote {$oprofile->uri} to local {$this->user->nickname}");
$oprofile->subscribeRemoteToLocal($this->user);
} else {
common_log(LOG_INFO, "Can't set up subscription from remote; missing profile.");
}
} }
/** /**
* @fixme probably call Ostatus_profile::processFeed * We've gotten an unfollow/unsubscribe notification from a remote user.
* Check if we have a subscription relationship for them and kill it.
*
* @fixme probably catch exceptions on fail?
*/
function handleUnfollow()
{
$oprofile = $this->ensureProfile();
if ($oprofile) {
common_log(LOG_INFO, "Canceling subscription from remote {$oprofile->uri} to local {$this->user->nickname}");
Subscription::cancel($oprofile->localProfile(), $this->user->getProfile());
} else {
common_log(LOG_ERR, "Can't cancel subscription from remote, didn't find the profile");
}
}
/**
* Remote user likes one of our posts.
* Confirm the post is ours, and save a local favorite event.
*/ */
function handleFavorite() function handleFavorite()
{ {
} }
/** /**
* @fixme probably call Ostatus_profile::processFeed * Remote user doesn't like one of our posts after all!
* Confirm the post is ours, and save a local favorite event.
*/
function handleUnfavorite()
{
}
/**
* Hmmmm
*/ */
function handleShare() function handleShare()
{ {
} }
/**
* @return Ostatus_profile
*/
function ensureProfile() function ensureProfile()
{ {
$actor = $this->act->actor; $actor = $this->act->actor;
common_log(LOG_DEBUG, "Received salmon bit: " . var_export($this->act, true)); common_log(LOG_DEBUG, "Received salmon bit: " . var_export($this->act, true));
if (empty($actor->id)) { if (empty($actor->id)) {
common_log(LOG_ERR, "broken actor: " . var_export($actor, true));
throw new Exception("Received a salmon slap from unidentified actor."); throw new Exception("Received a salmon slap from unidentified actor.");
} }
$ostatusProfile = Ostatus_profile::ensureActorProfile($this->act); return Ostatus_profile::ensureActorProfile($this->act);
return $oprofile->localProfile();
} }
/** /**
* @fixme anything new in here probably should be merged into Ostatus_profile::ensureActorProfile and friends * @fixme merge into Ostatus_profile::ensureActorProfile and friends
*/ */
function createProfile() function createProfile()
{ {

View File

@ -310,8 +310,15 @@ class Ostatus_profile extends Memcached_DataObject
* @param $verb eg Activity::SUBSCRIBE or Activity::JOIN * @param $verb eg Activity::SUBSCRIBE or Activity::JOIN
* @param $object object of the action; if null, the remote entity itself is assumed * @param $object object of the action; if null, the remote entity itself is assumed
*/ */
public function notify(Profile $actor, $verb, $object=null) public function notify($actor, $verb, $object=null)
{ {
if (!($actor instanceof Profile)) {
$type = gettype($actor);
if ($type == 'object') {
$type = get_class($actor);
}
throw new ServerException("Invalid actor passed to " . __METHOD__ . ": " . $type);
}
if ($object == null) { if ($object == null) {
$object = $this; $object = $this;
} }
@ -340,7 +347,7 @@ class Ostatus_profile extends Memcached_DataObject
$feed->addEntry($entry); $feed->addEntry($entry);
$xml = $feed->getString(); $xml = $feed->getString();
common_log(LOG_INFO, "Posting to Salmon endpoint $salmon: $xml"); common_log(LOG_INFO, "Posting to Salmon endpoint $this->salmonuri: $xml");
$salmon = new Salmon(); // ? $salmon = new Salmon(); // ?
$salmon->post($this->salmonuri, $xml); $salmon->post($this->salmonuri, $xml);
@ -531,9 +538,14 @@ class Ostatus_profile extends Memcached_DataObject
$temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar'); $temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar');
copy($url, $temp_filename); copy($url, $temp_filename);
if ($this->isGroup()) {
$id = $this->group_id;
} else {
$id = $this->profile_id;
}
// @fixme should we be using different ids? // @fixme should we be using different ids?
$imagefile = new ImageFile($this->id, $temp_filename); $imagefile = new ImageFile($id, $temp_filename);
$filename = Avatar::filename($this->id, $filename = Avatar::filename($id,
image_type_to_extension($imagefile->type), image_type_to_extension($imagefile->type),
null, null,
common_timestamp()); common_timestamp());
@ -646,7 +658,7 @@ class Ostatus_profile extends Memcached_DataObject
$actor = $activity->actor; $actor = $activity->actor;
$homeuri = self::getActorProfileURI($activity); $homeuri = self::getActorProfileURI($activity);
$nickname = self::getAuthorNick($activity); $nickname = self::getAuthorNick($activity);
$avatar = self::getAvatar($actor, $feed); $avatar = self::getAvatar($actor, $activity->feed);
if (!$homeuri) { if (!$homeuri) {
common_log(LOG_DEBUG, __METHOD__ . " empty actor profile URI: " . var_export($activity, true)); common_log(LOG_DEBUG, __METHOD__ . " empty actor profile URI: " . var_export($activity, true));