diff --git a/plugins/OStatus/OStatusPlugin.php b/plugins/OStatus/OStatusPlugin.php index 3b073a5d13..6fef20d6f5 100644 --- a/plugins/OStatus/OStatusPlugin.php +++ b/plugins/OStatus/OStatusPlugin.php @@ -28,6 +28,15 @@ set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__) . '/ext class FeedSubException extends Exception { + function __construct($msg=null) + { + $type = get_class($this); + if ($msg) { + parent::__construct("$type: $msg"); + } else { + parent::__construct($type); + } + } } class OStatusPlugin extends Plugin diff --git a/plugins/OStatus/README b/plugins/OStatus/README index 3a98b7b256..ea5dfc055f 100644 --- a/plugins/OStatus/README +++ b/plugins/OStatus/README @@ -1,18 +1,42 @@ -Plugin to support importing updates from external RSS and Atom feeds into your timeline. +Plugin to support importing and exporting notices through Atom and RSS feeds. +The OStatus plugin concentrates on user-to-user cases for federating StatusNet +and similar social networking / microblogging / blogging sites, but includes +low-level feed subscription systems which are used by some other plugins. + +Uses PubSubHubbub for push feed updates; currently non-PuSH feeds cannot be +subscribed unless an external PuSH hub proxy is used. -Uses PubSubHubbub for push feed updates; currently non-PuSH feeds cannot be subscribed. Configuration options available: $config['ostatus']['hub'] (default internal hub) - Set to URL of an external PuSH hub to use it instead of our internal hub. + Set to URL of an external PuSH hub to use it instead of our internal hub + for sending outgoing updates in user and group feeds. $config['ostatus']['hub_retries'] (default 0) Number of times to retry a PuSH send to consumers if using internal hub +Settings controlling incoming feed subscription: + +$config['feedsub']['fallback_hub'] + To subscribe to feeds that don't have a hub, an external PuSH proxy hub + such as Superfeedr may be used. Any feed without a hub of its own will + be subscribed through the specified hub URL instead. If the external hub + has usage charges, be aware that there is no restriction placed to how + many feeds may be subscribed! + + $config['feedsub']['fallback_hub'] = 'https://superfeedr.com/hubbub'; + +$config['feedsub']['hub_user'] +$config['feedsub']['hub_password'] + If using the fallback hub mode, these settings may be used to provide + HTTP authentication credentials for contacting the hub. Default hubs + specified from feeds are assumed to not require + + For testing, shouldn't be used in production: $config['ostatus']['skip_signatures'] @@ -23,12 +47,11 @@ $config['feedsub']['nohub'] (default require hub) Allow low-level feed subscription setup for feeds without hubs. Not actually usable at this stage, OStatus will check for hubs too - and we have no polling backend. + and we have no polling backend. (The fallback hub option can be used + with a 3rd-party service to provide such polling.) Todo: -* fully functional l10n -* redo non-OStatus feed support -** rssCloud support? -** possibly a polling daemon to support non-PuSH feeds? +* better support for feeds that aren't natively oriented at social networking * make use of tags/categories from feeds +* better repeat handling diff --git a/plugins/OStatus/classes/FeedSub.php b/plugins/OStatus/classes/FeedSub.php index 9cd35e29c9..dd1968db12 100644 --- a/plugins/OStatus/classes/FeedSub.php +++ b/plugins/OStatus/classes/FeedSub.php @@ -207,8 +207,8 @@ class FeedSub extends Memcached_DataObject $discover = new FeedDiscovery(); $discover->discoverFromFeedURL($feeduri); - $huburi = $discover->getAtomLink('hub'); - if (!$huburi) { + $huburi = $discover->getHubLink(); + if (!$huburi && !common_config('feedsub', 'fallback_hub')) { throw new FeedSubNoHubException(); } @@ -241,8 +241,12 @@ class FeedSub extends Memcached_DataObject common_log(LOG_WARNING, "Attempting to (re)start PuSH subscription to $this->uri in unexpected state $this->sub_state"); } if (empty($this->huburi)) { - if (common_config('feedsub', 'nohub')) { + if (common_config('feedsub', 'fallback_hub')) { + // No native hub on this feed? + // Use our fallback hub, which handles polling on our behalf. + } else if (common_config('feedsub', 'nohub')) { // Fake it! We're just testing remote feeds w/o hubs. + // We'll never actually get updates in this mode. return true; } else { throw new ServerException("Attempting to start PuSH subscription for feed with no hub"); @@ -267,8 +271,12 @@ class FeedSub extends Memcached_DataObject common_log(LOG_WARNING, "Attempting to (re)end PuSH subscription to $this->uri in unexpected state $this->sub_state"); } if (empty($this->huburi)) { - if (common_config('feedsub', 'nohub')) { + if (common_config('feedsub', 'fallback_hub')) { + // No native hub on this feed? + // Use our fallback hub, which handles polling on our behalf. + } else if (common_config('feedsub', 'nohub')) { // Fake it! We're just testing remote feeds w/o hubs. + // We'll never actually get updates in this mode. return true; } else { throw new ServerException("Attempting to end PuSH subscription for feed with no hub"); @@ -326,7 +334,21 @@ class FeedSub extends Memcached_DataObject 'hub.secret' => $this->secret, 'hub.topic' => $this->uri); $client = new HTTPClient(); - $response = $client->post($this->huburi, $headers, $post); + if ($this->huburi) { + $hub = $this->huburi; + } else { + if (common_config('feedsub', 'fallback_hub')) { + $hub = common_config('feedsub', 'fallback_hub'); + if (common_config('feedsub', 'hub_user')) { + $u = common_config('feedsub', 'hub_user'); + $p = common_config('feedsub', 'hub_pass'); + $client->setAuth($u, $p); + } + } else { + throw new FeedSubException('WTF?'); + } + } + $response = $client->post($hub, $headers, $post); $status = $response->getStatus(); if ($status == 202) { common_log(LOG_INFO, __METHOD__ . ': sub req ok, awaiting verification callback'); diff --git a/plugins/OStatus/classes/Ostatus_profile.php b/plugins/OStatus/classes/Ostatus_profile.php index 2d7c632e63..77a5e22cc0 100644 --- a/plugins/OStatus/classes/Ostatus_profile.php +++ b/plugins/OStatus/classes/Ostatus_profile.php @@ -493,8 +493,14 @@ class Ostatus_profile extends Memcached_DataObject // OK here! assume the default } else if ($actor->id == $this->uri || $actor->link == $this->uri) { $this->updateFromActivityObject($actor); - } else { + } else if ($actor->id) { + // We have an ActivityStreams actor with an explicit ID that doesn't match the feed owner. + // This isn't what we expect from mainline OStatus person feeds! + // Group feeds go down another path, with different validation. throw new Exception("Got an actor '{$actor->title}' ({$actor->id}) on single-user feed for {$this->uri}"); + } else { + // Plain without ActivityStreams actor info. + // We'll just ignore this info for now and save the update under the feed's identity. } $oprofile = $this; @@ -869,12 +875,12 @@ class Ostatus_profile extends Memcached_DataObject $feeduri = $discover->discoverFromFeedURL($feed_url); $hints['feedurl'] = $feeduri; - $huburi = $discover->getAtomLink('hub'); + $huburi = $discover->getHubLink(); $hints['hub'] = $huburi; $salmonuri = $discover->getAtomLink(Salmon::NS_REPLIES); $hints['salmon'] = $salmonuri; - if (!$huburi) { + if (!$huburi && !common_config('feedsub', 'fallback_hub')) { // We can only deal with folks with a PuSH hub throw new FeedSubNoHubException(); } @@ -1270,10 +1276,10 @@ class Ostatus_profile extends Memcached_DataObject $discover = new FeedDiscovery(); $discover->discoverFromFeedURL($hints['feedurl']); } - $huburi = $discover->getAtomLink('hub'); + $huburi = $discover->getHubLink(); } - if (!$huburi) { + if (!$huburi && !common_config('feedsub', 'fallback_hub')) { // We can only deal with folks with a PuSH hub throw new FeedSubNoHubException(); } diff --git a/plugins/OStatus/lib/feeddiscovery.php b/plugins/OStatus/lib/feeddiscovery.php index 4ac2438326..a55399d7c8 100644 --- a/plugins/OStatus/lib/feeddiscovery.php +++ b/plugins/OStatus/lib/feeddiscovery.php @@ -87,6 +87,16 @@ class FeedDiscovery return ActivityUtils::getLink($this->root, $rel, $type); } + /** + * Get the referenced PuSH hub link from an Atom feed. + * + * @return mixed string or false + */ + public function getHubLink() + { + return $this->getAtomLink('hub'); + } + /** * @param string $url * @param bool $htmlOk pass false here if you don't want to follow web pages. diff --git a/plugins/OStatus/scripts/update-profile.php b/plugins/OStatus/scripts/update-profile.php index d06de4f903..64afa0f356 100644 --- a/plugins/OStatus/scripts/update-profile.php +++ b/plugins/OStatus/scripts/update-profile.php @@ -55,7 +55,7 @@ print "Re-running feed discovery for profile URL $oprofile->uri\n"; // @fixme will bork where the URI isn't the profile URL for now $discover = new FeedDiscovery(); $feedurl = $discover->discoverFromURL($oprofile->uri); -$huburi = $discover->getAtomLink('hub'); +$huburi = $discover->getHubLink(); $salmonuri = $discover->getAtomLink(Salmon::NS_REPLIES); print " Feed URL: $feedurl\n";