]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
OStatus PuSH fixes:
authorBrion Vibber <brion@pobox.com>
Wed, 10 Feb 2010 22:58:39 +0000 (22:58 +0000)
committerBrion Vibber <brion@pobox.com>
Wed, 10 Feb 2010 22:58:39 +0000 (22:58 +0000)
* HMAC now calculated correctly - confirmed interop with Google's public hub
* Can optionally use an external PuSH hub, set URL in $config['ostatus']['hub']
  (may have issues in replication environment, and will ping the hub for every
  update rather than just those with subscribers) Internal hub will still function
  when this is set, but won't be advertised. Warning: setting this, then turning
  it off later will break subscriptions as that hub will no longer receive pings.

plugins/OStatus/OStatusPlugin.php
plugins/OStatus/classes/Feedinfo.php
plugins/OStatus/classes/HubSub.php
plugins/OStatus/lib/hubdistribqueuehandler.php

index 62ecaf6310cb842cc75d30ed24fc95d478236567..4b9b4d2c32e54075c65f1ce8ca0911017db37f15 100644 (file)
@@ -114,10 +114,15 @@ class OStatusPlugin extends Plugin
         if ($action instanceof ApiTimelineUserAction || $action instanceof ApiTimelineGroupAction) {
             $id = $action->arg('id');
             if (strval(intval($id)) === strval($id)) {
-                // Canonical form of id in URL?
-                // Updates will be handled for our internal PuSH hub.
+                // Canonical form of id in URL? These are used for OStatus syndication.
+
+                $hub = common_config('ostatus', 'hub');
+                if (empty($hub)) {
+                    // Updates will be handled through our internal PuSH hub.
+                    $hub = common_local_url('pushhub');
+                }
                 $action->element('link', array('rel' => 'hub',
-                                               'href' => common_local_url('pushhub')));
+                                               'href' => $hub));
 
                 // Also, we'll add in the salmon link
                 $action->element('link', array('rel' => 'salmon',
index b4e55c364376287e07c284db54c9e41cc2e0faa6..2344a4a0eed480cb750f23ff407f12ba02b9a641 100644 (file)
@@ -160,7 +160,7 @@ class Feedinfo extends Memcached_DataObject
 
     function keyTypes()
     {
-        return array('id' => 'K'); // @fixme we'll need a profile_id key at least
+        return array('id' => 'K', 'feeduri' => 'U'); // @fixme we'll need a profile_id key at least
     }
 
     function sequenceKey()
@@ -323,7 +323,7 @@ class Feedinfo extends Memcached_DataObject
         if ($this->secret) {
             if (preg_match('/^sha1=([0-9a-fA-F]{40})$/', $hmac, $matches)) {
                 $their_hmac = strtolower($matches[1]);
-                $our_hmac = sha1($xml . $this->secret);
+                $our_hmac = hash_hmac('sha1', $xml, $this->secret);
                 if ($their_hmac !== $our_hmac) {
                     common_log(LOG_ERR, __METHOD__ . ": ignoring PuSH with bad SHA-1 HMAC: got $their_hmac, expected $our_hmac");
                     return;
index 1769f6c9417f0c213c00fc9ebe8180d2676b343f..7071ee5b4f82e9933973b7a3afc705ef58934233 100644 (file)
@@ -242,7 +242,7 @@ class HubSub extends Memcached_DataObject
     {
         $headers = array('Content-Type: application/atom+xml');
         if ($this->secret) {
-            $hmac = sha1($atom . $this->secret);
+            $hmac = hash_hmac('sha1', $atom, $this->secret);
             $headers[] = "X-Hub-Signature: sha1=$hmac";
         } else {
             $hmac = '(none)';
index a35b8874c5c572087ca6cff9be0b4aba974a07f9..245a57f7200dac1e321d3aefe98661d9edaec724 100644 (file)
@@ -49,15 +49,7 @@ class HubDistribQueueHandler extends QueueHandler
         $feed = common_local_url('ApiTimelineUser',
                                  array('id' => $notice->profile_id,
                                        'format' => 'atom'));
-        $sub = new HubSub();
-        $sub->topic = $feed;
-        if ($sub->find()) {
-            $atom = $this->userFeedForNotice($notice);
-            $this->pushFeeds($atom, $sub);
-        } else {
-            common_log(LOG_INFO, "No PuSH subscribers for $feed");
-        }
-        return true;
+        $this->pushFeed($feed, array($this, 'userFeedForNotice'), $notice);
     }
 
     function pushGroup($notice, $group_id)
@@ -65,19 +57,69 @@ class HubDistribQueueHandler extends QueueHandler
         $feed = common_local_url('ApiTimelineGroup',
                                  array('id' => $group_id,
                                        'format' => 'atom'));
+        $this->pushFeed($feed, array($this, 'groupFeedForNotice'), $group_id, $notice);
+    }
+
+    /**
+     * @param string $feed URI to the feed
+     * @param callable $callback function to generate Atom feed update if needed
+     *        any additional params are passed to the callback.
+     */
+    function pushFeed($feed, $callback)
+    {
+        $hub = common_config('ostatus', 'hub');
+        if ($hub) {
+            $this->pushFeedExternal($feed, $hub);
+        }
+
         $sub = new HubSub();
         $sub->topic = $feed;
         if ($sub->find()) {
-            common_log(LOG_INFO, "Building PuSH feed for $feed");
-            $atom = $this->groupFeedForNotice($group_id, $notice);
-            $this->pushFeeds($atom, $sub);
+            $args = array_slice(func_get_args(), 2);
+            $atom = call_user_func_array($callback, $args);
+            $this->pushFeedInternal($atom, $sub);
         } else {
             common_log(LOG_INFO, "No PuSH subscribers for $feed");
         }
+        return true;
     }
 
-    
-    function pushFeeds($atom, $sub)
+    /**
+     * Ping external hub about this update.
+     * The hub will pull the feed and check for new items later.
+     * Not guaranteed safe in an environment with database replication.
+     *
+     * @param string $feed feed topic URI
+     * @param string $hub PuSH hub URI
+     * @fixme can consolidate pings for user & group posts
+     */
+    function pushFeedExternal($feed, $hub)
+    {
+        $client = new HTTPClient();
+        try {
+            $data = array('hub.mode' => 'publish',
+                          'hub.url' => $feed);
+            $response = $client->post($hub, array(), $data);
+            if ($response->getStatus() == 204) {
+                common_log(LOG_INFO, "PuSH ping to hub $hub for $feed ok");
+                return true;
+            } else {
+                common_log(LOG_ERR, "PuSH ping to hub $hub for $feed failed with HTTP " .
+                                    $response->getStatus() . ': ' .
+                                    $response->getBody());
+            }
+        } catch (Exception $e) {
+            common_log(LOG_ERR, "PuSH ping to hub $hub for $feed failed: " . $e->getMessage());
+            return false;
+        }
+    }
+
+    /**
+     * Queue up direct feed update pushes to subscribers on our internal hub.
+     * @param string $atom update feed, containing only new/changed items
+     * @param HubSub $sub open query of subscribers
+     */
+    function pushFeedInternal($atom, $sub)
     {
         common_log(LOG_INFO, "Preparing $sub->N PuSH distribution(s) for $sub->topic");
         $qm = QueueManager::get();