From 07f71a66f5372c4d799e6656433726c0c7a19c48 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Fri, 11 Sep 2009 21:28:22 +0000 Subject: Extremely nascent RSSCloud plugin --- plugins/RSSCloud/RSSCloudPlugin.php | 169 ++++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 plugins/RSSCloud/RSSCloudPlugin.php (limited to 'plugins/RSSCloud/RSSCloudPlugin.php') diff --git a/plugins/RSSCloud/RSSCloudPlugin.php b/plugins/RSSCloud/RSSCloudPlugin.php new file mode 100644 index 000000000..816046ffb --- /dev/null +++ b/plugins/RSSCloud/RSSCloudPlugin.php @@ -0,0 +1,169 @@ +. + * + * @category Plugin + * @package StatusNet + * @author Zach Copley + * @copyright 2009 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +define('RSSCLOUDPLUGIN_VERSION', '0.1'); + +class RSSCloudPlugin extends Plugin +{ + function __construct() + { + parent::__construct(); + } + + function onInitializePlugin(){ + $this->domain = common_config('rsscloud', 'domain'); + $this->port = common_config('rsscloud', 'port'); + $this->path = common_config('rsscloud', 'path'); + $this->funct = common_config('rsscloud', 'function'); + $this->protocol = common_config('rsscloud', 'protocol'); + + // set defaults + + if (empty($this->domain)) { + $this->domain = 'rpc.rsscloud.org'; + } + + if (empty($this->port)) { + $this->port = '5337'; + } + + if (empty($this->path)) { + $this->path = '/rsscloud/pleaseNotify'; + } + + if (empty($this->funct)) { + $this->funct = ''; + } + + if (empty($this->protocol)) { + $this->protocol = 'http-post'; + } + } + + function onStartApiRss($action){ + + $attrs = array('domain' => $this->domain, + 'port' => $this->port, + 'path' => $this->path, + 'registerProcedure' => $this->funct, + 'protocol' => $this->protocol); + + // Dipping into XMLWriter to avoid a full end element (). + + $action->xw->startElement('cloud'); + foreach ($attrs as $name => $value) { + $action->xw->writeAttribute($name, $value); + } + $action->xw->endElement('cloud'); + + } + + function onEndNoticeSave($notice){ + + $user = User::staticGet('id', $notice->profile_id); + $rss = common_local_url('api', array('apiaction' => 'statuses', + 'method' => 'user_timeline', + 'argument' => $user->nickname . '.rss')); + + $notifier = new CloudNotifier(); + $notifier->notify($rss); + } + + +} + + +class CloudNotifier { + + + function notify($feed) { + common_debug("CloudNotifier->notify: $feed"); + + $params = 'url=' . urlencode($feed); + + $result = $this->httpPost('http://rpc.rsscloud.org:5337/rsscloud/ping', + $params); + + if ($result) { + common_debug('success notifying cloud'); + } else { + common_debug('failure notifying cloud'); + } + + } + + function userAgent() + { + return 'rssCloudPlugin/' . RSSCLOUDPLUGIN_VERSION . + ' StatusNet/' . STATUSNET_VERSION; + } + + + private function httpPost($url, $params) { + + + common_debug('params: ' . var_export($params, true)); + + $options = array(CURLOPT_URL => $url, + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => $params, + CURLOPT_USERAGENT => $this->userAgent(), + CURLOPT_RETURNTRANSFER => true, + CURLOPT_FAILONERROR => true, + CURLOPT_HEADER => false, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_CONNECTTIMEOUT => 5, + CURLOPT_TIMEOUT => 5); + + $ch = curl_init(); + curl_setopt_array($ch, $options); + + $response = curl_exec($ch); + + + + $info = curl_getinfo($ch); + + curl_close($ch); + + common_debug('curl response: ' . var_export($response, true)); + common_debug('curl info: ' . var_export($info, true)); + + if ($info['http_code'] == 200) { + return true; + } else { + return false; + } + } + +} \ No newline at end of file -- cgit v1.2.3-54-g00ecf From 391003c3c65572dd156244390d8eedd2dfd96f90 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 16 Sep 2009 19:20:25 +0000 Subject: Some foundational work. Not much to see here. Move along. --- plugins/RSSCloud/RSSCloudNotifier.php | 93 ++++++++++++++++++ plugins/RSSCloud/RSSCloudPlugin.php | 141 ++++++++++++---------------- plugins/RSSCloud/RSSCloudRequestNotify.php | 145 +++++++++++++++++++++++++++++ 3 files changed, 299 insertions(+), 80 deletions(-) create mode 100644 plugins/RSSCloud/RSSCloudNotifier.php create mode 100644 plugins/RSSCloud/RSSCloudRequestNotify.php (limited to 'plugins/RSSCloud/RSSCloudPlugin.php') diff --git a/plugins/RSSCloud/RSSCloudNotifier.php b/plugins/RSSCloud/RSSCloudNotifier.php new file mode 100644 index 000000000..65bfd032e --- /dev/null +++ b/plugins/RSSCloud/RSSCloudNotifier.php @@ -0,0 +1,93 @@ +. + * + * @category Plugin + * @package StatusNet + * @author Zach Copley + * @copyright 2009 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +class RSSCloudNotifier { + + function postUpdate($endpoint, $feed) { + common_debug("CloudNotifier->notify: $feed"); + + $params = 'url=' . urlencode($feed); + + $result = $this->httpPost($endpoint, $params); + + if ($result) { + common_debug('success notifying cloud'); + } else { + common_debug('failure notifying cloud'); + } + + } + + function userAgent() + { + return 'rssCloudPlugin/' . RSSCLOUDPLUGIN_VERSION . + ' StatusNet/' . STATUSNET_VERSION; + } + + private function httpPost($url, $params) { + + common_debug('params: ' . var_export($params, true)); + + $options = array(CURLOPT_URL => $url, + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => $params, + CURLOPT_USERAGENT => $this->userAgent(), + CURLOPT_RETURNTRANSFER => true, + CURLOPT_FAILONERROR => true, + CURLOPT_HEADER => false, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_CONNECTTIMEOUT => 5, + CURLOPT_TIMEOUT => 5); + + $ch = curl_init(); + curl_setopt_array($ch, $options); + + $response = curl_exec($ch); + + $info = curl_getinfo($ch); + + curl_close($ch); + + common_debug('curl response: ' . var_export($response, true)); + common_debug('curl info: ' . var_export($info, true)); + + if ($info['http_code'] == 200) { + return true; + } else { + return false; + } + } + +} + + diff --git a/plugins/RSSCloud/RSSCloudPlugin.php b/plugins/RSSCloud/RSSCloudPlugin.php index 816046ffb..50d9060ef 100644 --- a/plugins/RSSCloud/RSSCloudPlugin.php +++ b/plugins/RSSCloud/RSSCloudPlugin.php @@ -33,30 +33,33 @@ if (!defined('STATUSNET')) { define('RSSCLOUDPLUGIN_VERSION', '0.1'); -class RSSCloudPlugin extends Plugin +class RSSCloudPlugin extends Plugin { function __construct() { parent::__construct(); } - + function onInitializePlugin(){ + + common_debug("RSSCloudPlugin onInitializePlugin()"); + $this->domain = common_config('rsscloud', 'domain'); $this->port = common_config('rsscloud', 'port'); $this->path = common_config('rsscloud', 'path'); $this->funct = common_config('rsscloud', 'function'); $this->protocol = common_config('rsscloud', 'protocol'); - + // set defaults - + if (empty($this->domain)) { $this->domain = 'rpc.rsscloud.org'; } - + if (empty($this->port)) { $this->port = '5337'; } - + if (empty($this->path)) { $this->path = '/rsscloud/pleaseNotify'; } @@ -69,9 +72,47 @@ class RSSCloudPlugin extends Plugin $this->protocol = 'http-post'; } } - + + /** + * Add RSSCloud-related paths to the router table + * + * Hook for RouterInitialized event. + * + * @return boolean hook return + */ + + function onRouterInitialized(&$m) + { + $m->connect('rsscloud/request_notify', array('action' => 'RSSCloudRequestNotify')); + $m->connect('rsscloud/notify', array('action' => 'LoggingAggregator')); + + return true; + } + + function onAutoload($cls) + { + common_debug("onAutoload() $cls"); + + switch ($cls) + { + + case 'RSSCloudNotifier': + require_once(INSTALLDIR . '/plugins/RSSCloud/RSSCloudNotifier.php'); + return false; + case 'RSSCloudRequestNotifyAction': + case 'LoggingAggregatorAction': + common_debug(mb_substr($cls, 0, -6) . '.php'); + require_once(INSTALLDIR . '/plugins/RSSCloud/' . mb_substr($cls, 0, -6) . '.php'); + return false; + default: + return true; + } + } + function onStartApiRss($action){ - + + // XXX: No sure we want every feed to be cloud enabled + $attrs = array('domain' => $this->domain, 'port' => $this->port, 'path' => $this->path, @@ -79,91 +120,31 @@ class RSSCloudPlugin extends Plugin 'protocol' => $this->protocol); // Dipping into XMLWriter to avoid a full end element (). - + $action->xw->startElement('cloud'); foreach ($attrs as $name => $value) { $action->xw->writeAttribute($name, $value); } $action->xw->endElement('cloud'); - + } function onEndNoticeSave($notice){ + common_debug("RSSCloudPlugin oneEndNoticeSave()"); + $user = User::staticGet('id', $notice->profile_id); - $rss = common_local_url('api', array('apiaction' => 'statuses', + $feed = common_local_url('api', array('apiaction' => 'statuses', 'method' => 'user_timeline', 'argument' => $user->nickname . '.rss')); - - $notifier = new CloudNotifier(); - $notifier->notify($rss); - } - - -} + // XXX: Dave's hub for testing -class CloudNotifier { - - - function notify($feed) { - common_debug("CloudNotifier->notify: $feed"); - - $params = 'url=' . urlencode($feed); - - $result = $this->httpPost('http://rpc.rsscloud.org:5337/rsscloud/ping', - $params); - - if ($result) { - common_debug('success notifying cloud'); - } else { - common_debug('failure notifying cloud'); - } + $endpoint = 'http://rpc.rsscloud.org:5337/rsscloud/ping'; + $notifier = new RSSCloudNotifier(); + $notifier->postUpdate($endpoint, $feed); } - - function userAgent() - { - return 'rssCloudPlugin/' . RSSCLOUDPLUGIN_VERSION . - ' StatusNet/' . STATUSNET_VERSION; - } - - - private function httpPost($url, $params) { - - - common_debug('params: ' . var_export($params, true)); - - $options = array(CURLOPT_URL => $url, - CURLOPT_POST => true, - CURLOPT_POSTFIELDS => $params, - CURLOPT_USERAGENT => $this->userAgent(), - CURLOPT_RETURNTRANSFER => true, - CURLOPT_FAILONERROR => true, - CURLOPT_HEADER => false, - CURLOPT_FOLLOWLOCATION => true, - CURLOPT_CONNECTTIMEOUT => 5, - CURLOPT_TIMEOUT => 5); - - $ch = curl_init(); - curl_setopt_array($ch, $options); - - $response = curl_exec($ch); - - - - $info = curl_getinfo($ch); - - curl_close($ch); - - common_debug('curl response: ' . var_export($response, true)); - common_debug('curl info: ' . var_export($info, true)); - - if ($info['http_code'] == 200) { - return true; - } else { - return false; - } - } - -} \ No newline at end of file + +} + diff --git a/plugins/RSSCloud/RSSCloudRequestNotify.php b/plugins/RSSCloud/RSSCloudRequestNotify.php new file mode 100644 index 000000000..1d4087334 --- /dev/null +++ b/plugins/RSSCloud/RSSCloudRequestNotify.php @@ -0,0 +1,145 @@ + + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://status.net/ + * + * StatusNet - the distributed open-source microblogging tool + * Copyright (C) 2009, 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 . + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +class RSSCloudRequestNotifyAction extends Action +{ + + /** + * Initialization. + * + * @param array $args Web and URL arguments + * + * @return boolean false if user doesn't exist + */ + function prepare($args) + { + parent::prepare($args); + return true; + } + + function handle($args) + { + parent::handle($args); + + if ($_SERVER['REQUEST_METHOD'] != 'POST') { + showResult(false, 'Request must be POST.'); + } + + $ip = $_SERVER['REMOTE_ADDR']; + $missing = array(); + $port = $this->arg('port'); + + if (empty($this->port)) { + $missing[] = 'port'; + } + + $path = $this->arg('path'); + + if (empty($this->path)) { + $missing[] = 'path'; + } + + $protocol = $this->arg('protocol'); + + if (empty($this->protocol)) { + $missing[] = 'protocol'; + } + + if (empty($this->notifyProcedure)) { + $missing[] = 'notifyProcedure'; + } + + if (!empty($missing)) { + $msg = 'The following parameters were missing from the request body: ' . + implode(',', $missing) . '.'; + $this->showResult(false, $msg); + } + + $feeds = $this->getFeeds(); + + if (empty($feeds)) { + $this->showResult(false, + 'You must provide at least one feed url (url1, url2, url3 ... urlN).'); + } + + $endpoint = $ip . ':' . $port . $path; + + foreach ($feeds as $feed) { + + } + + + } + + + function getFeeds() + { + $feeds = array(); + + foreach ($this->args as $key => $feed ) { + if (preg_match('|url\d+|', $key)) { + + // XXX: validate feeds somehow and kick bad ones out + + $feeds[] = $feed; + } + } + + return $feeds; + } + + + function checkNotifyHandler() + { + + } + + function validateFeed() + { + } + + function showResult($success, $msg) + { + $this->startXML(); + $this->elementStart('notifyResult', array('success' => ($success) ? 'true' : 'false', + 'msg' => $msg)); + $this->endXML(); + + } + + +} + + + -- cgit v1.2.3-54-g00ecf From 51ac7439e1875e7703c7aaeba91d19838b860032 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 21 Sep 2009 00:54:56 -0700 Subject: /rsscloud/request_notify should work now --- plugins/RSSCloud/RSSCloudNotifier.php | 14 +-- plugins/RSSCloud/RSSCloudPlugin.php | 53 ++++---- plugins/RSSCloud/RSSCloudRequestNotify.php | 187 ++++++++++++++++++++++------- 3 files changed, 175 insertions(+), 79 deletions(-) (limited to 'plugins/RSSCloud/RSSCloudPlugin.php') diff --git a/plugins/RSSCloud/RSSCloudNotifier.php b/plugins/RSSCloud/RSSCloudNotifier.php index 65bfd032e..c2130b7b8 100644 --- a/plugins/RSSCloud/RSSCloudNotifier.php +++ b/plugins/RSSCloud/RSSCloudNotifier.php @@ -2,7 +2,7 @@ /** * StatusNet, the distributed open-source microblogging tool * - * Class to ping an rssCloud hub when a feed has been updated + * Class to ping an rssCloud endpoint when a feed has been updated * * PHP version 5 * @@ -40,12 +40,15 @@ class RSSCloudNotifier { $result = $this->httpPost($endpoint, $params); + // XXX: Make all this use CurlClient (lib/curlclient.php) + if ($result) { - common_debug('success notifying cloud'); + common_debug('RSSCloud plugin - success notifying cloud endpoint!'); } else { - common_debug('failure notifying cloud'); + common_debug('RSSClous plugin - failure notifying cloud endpoint!'); } + return $result; } function userAgent() @@ -56,8 +59,6 @@ class RSSCloudNotifier { private function httpPost($url, $params) { - common_debug('params: ' . var_export($params, true)); - $options = array(CURLOPT_URL => $url, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $params, @@ -78,9 +79,6 @@ class RSSCloudNotifier { curl_close($ch); - common_debug('curl response: ' . var_export($response, true)); - common_debug('curl info: ' . var_export($info, true)); - if ($info['http_code'] == 200) { return true; } else { diff --git a/plugins/RSSCloud/RSSCloudPlugin.php b/plugins/RSSCloud/RSSCloudPlugin.php index 50d9060ef..a971c3156 100644 --- a/plugins/RSSCloud/RSSCloudPlugin.php +++ b/plugins/RSSCloud/RSSCloudPlugin.php @@ -40,10 +40,8 @@ class RSSCloudPlugin extends Plugin parent::__construct(); } - function onInitializePlugin(){ - - common_debug("RSSCloudPlugin onInitializePlugin()"); - + function onInitializePlugin() + { $this->domain = common_config('rsscloud', 'domain'); $this->port = common_config('rsscloud', 'port'); $this->path = common_config('rsscloud', 'path'); @@ -52,16 +50,18 @@ class RSSCloudPlugin extends Plugin // set defaults + $local_server = parse_url(common_path('rsscloud/request_notify')); + if (empty($this->domain)) { - $this->domain = 'rpc.rsscloud.org'; + $this->domain = $local_server['host']; } if (empty($this->port)) { - $this->port = '5337'; + $this->port = '80'; } if (empty($this->path)) { - $this->path = '/rsscloud/pleaseNotify'; + $this->path = '/rsscloud/request_notify'; } if (empty($this->funct)) { @@ -84,6 +84,8 @@ class RSSCloudPlugin extends Plugin function onRouterInitialized(&$m) { $m->connect('rsscloud/request_notify', array('action' => 'RSSCloudRequestNotify')); + + // XXX: This is just for end-to-end testing $m->connect('rsscloud/notify', array('action' => 'LoggingAggregator')); return true; @@ -91,8 +93,6 @@ class RSSCloudPlugin extends Plugin function onAutoload($cls) { - common_debug("onAutoload() $cls"); - switch ($cls) { @@ -111,22 +111,26 @@ class RSSCloudPlugin extends Plugin function onStartApiRss($action){ - // XXX: No sure we want every feed to be cloud enabled + // XXX: we want to only cloud enable the user_timeline so we need + // to be even more specific than this... FIXME - $attrs = array('domain' => $this->domain, - 'port' => $this->port, - 'path' => $this->path, - 'registerProcedure' => $this->funct, - 'protocol' => $this->protocol); + if (get_class($action) == 'TwitapistatusesAction') { - // Dipping into XMLWriter to avoid a full end element (). + $attrs = array('domain' => $this->domain, + 'port' => $this->port, + 'path' => $this->path, + 'registerProcedure' => $this->funct, + 'protocol' => $this->protocol); - $action->xw->startElement('cloud'); - foreach ($attrs as $name => $value) { - $action->xw->writeAttribute($name, $value); - } - $action->xw->endElement('cloud'); + // Dipping into XMLWriter to avoid a full end element (). + + $action->xw->startElement('cloud'); + foreach ($attrs as $name => $value) { + $action->xw->writeAttribute($name, $value); + } + $action->xw->endElement(); + } } function onEndNoticeSave($notice){ @@ -139,11 +143,10 @@ class RSSCloudPlugin extends Plugin 'argument' => $user->nickname . '.rss')); // XXX: Dave's hub for testing + // $endpoint = 'http://rpc.rsscloud.org:5337/rsscloud/ping'; - $endpoint = 'http://rpc.rsscloud.org:5337/rsscloud/ping'; - - $notifier = new RSSCloudNotifier(); - $notifier->postUpdate($endpoint, $feed); + // $notifier = new RSSCloudNotifier(); + // $notifier->postUpdate($endpoint, $feed); } } diff --git a/plugins/RSSCloud/RSSCloudRequestNotify.php b/plugins/RSSCloud/RSSCloudRequestNotify.php index 1d4087334..48bd3fb27 100644 --- a/plugins/RSSCloud/RSSCloudRequestNotify.php +++ b/plugins/RSSCloud/RSSCloudRequestNotify.php @@ -1,7 +1,8 @@ ip = $_SERVER['REMOTE_ADDR']; + $this->port = $this->arg('port'); + $this->path = $this->arg('path'); + $this->protocol = $this->arg('protocol'); + $this->procedure = $this->arg('notifyProcedure'); + $this->feeds = $this->getFeeds(); + + $this->subscriber_url = 'http://' . $this->ip . ':' . $this->port . $this->path; + return true; } function handle($args) { parent::handle($args); - + if ($_SERVER['REQUEST_METHOD'] != 'POST') { - showResult(false, 'Request must be POST.'); + $this->showResult(false, 'Request must be POST.'); + return; } - - $ip = $_SERVER['REMOTE_ADDR']; + $missing = array(); - $port = $this->arg('port'); - + if (empty($this->port)) { $missing[] = 'port'; } - + $path = $this->arg('path'); if (empty($this->path)) { $missing[] = 'path'; } - + $protocol = $this->arg('protocol'); if (empty($this->protocol)) { $missing[] = 'protocol'; } - - if (empty($this->notifyProcedure)) { + + if (!isset($this->procedure)) { $missing[] = 'notifyProcedure'; } - + if (!empty($missing)) { $msg = 'The following parameters were missing from the request body: ' . - implode(',', $missing) . '.'; + implode(', ', $missing) . '.'; $this->showResult(false, $msg); + return; } - - $feeds = $this->getFeeds(); - - if (empty($feeds)) { - $this->showResult(false, - 'You must provide at least one feed url (url1, url2, url3 ... urlN).'); + + if (empty($this->feeds)) { + $this->showResult(false, + 'You must provide at least one valid profile feed url (url1, url2, url3 ... urlN).'); + return; } - + $endpoint = $ip . ':' . $port . $path; - - foreach ($feeds as $feed) { - + + foreach ($this->feeds as $feed) { + $this->saveSubscription($feed); } - - + + // XXX: What to do about deleting stale subscriptions? 25 hours seems harsh. + // WordPress doesn't ever remove subscriptions. + + $msg = 'Thanks for the registration. It worked. When the feed(s) update(s) we\'ll notify you. ' . + ' Don\'t forget to re-register after 24 hours, your subscription will expire in 25.'; + + $this->showResult(true, $msg); } - - + function getFeeds() { $feeds = array(); - + foreach ($this->args as $key => $feed ) { if (preg_match('|url\d+|', $key)) { - - // XXX: validate feeds somehow and kick bad ones out - - $feeds[] = $feed; + + if ($this->testFeed($feed)) { + $feeds[] = $feed; + } else { + $msg = 'RSSCloud Plugin - ' . $this->ip . ' tried to subscribe ' . + 'to a non-existent feed: ' . $feed; + common_log(LOG_WARN, $msg); + } } } - + return $feeds; } - - - function checkNotifyHandler() + + function testNotificationHandler($feed) + { + $notifier = new RSSCloudNotifier(); + return $notifier->postUpdate($endpoint, $feed); + } + + // returns valid user or false + function testFeed($feed) + { + $user = $this->userFromFeed($feed); + + if (!empty($user)) { + + common_debug("Valid feed: $feed"); + + // OK, so this is a valid profile feed url, now let's see if the + // other system reponds to our notifications before we + // add the sub... + + if ($this->testNotificationHandler($feed)) { + return true; + } + } + + return false; + } + + // this actually does the validating and figuring out the + // user, which it returns + function userFromFeed($feed) { - + // We only do profile feeds + + $path = common_path('api/statuses/user_timeline/'); + $valid = '%^' . $path . '(?.*)\.rss$%'; + + if (preg_match($valid, $feed, $matches)) { + $user = User::staticGet('nickname', $matches['nickname']); + if (!empty($user)) { + return $user; + } + } + + return false; } - - function validateFeed() + + function saveSubscription($feed) { + // check to see if we already have a profile for this subscriber + + $other = Remote_profile::staticGet('uri', $this->subscriber_url); + + if ($other === false) { + $other->saveProfile(); + } + + $user = userFromFeed($feed); + + $result = subs_subscribe_to($user, $other); + + if ($result != true) { + $msg = "RSSPlugin - got '$result' trying to subscribe " . + "$this->subscriber_url to $user->nickname" . "'s profile feed."; + common_log(LOG_WARN, $msg); + } else { + $msg = 'RSSCloud plugin - subscribe: ' . $this->subscriber_url . + ' subscribed to ' . $feed; + + common_log(LOG_INFO, $msg); + } + } + + function saveProfile() + { + common_debug("Saving remote profile for $this->subscriber_url"); + + // XXX: We need to add a field to Remote_profile to indicate the kind + // of remote profile? i.e: OMB, RSSCloud, PuSH, Twitter + + $remote = new Remote_profile(); + $remote->uri = $this->subscriber_url; + $remote->postnoticeurl = $this->subscriber_url; + $remote->created = DB_DataObject_Cast::dateTime(); + + if (!$remote->insert()) { + throw new Exception(_('RSSCloud plugin - Error inserting remote profile!')); + } } - - function showResult($success, $msg) + + function showResult($success, $msg) { $this->startXML(); $this->elementStart('notifyResult', array('success' => ($success) ? 'true' : 'false', 'msg' => $msg)); $this->endXML(); - } - - + } -- cgit v1.2.3-54-g00ecf From 46ac99cf4dc58b4e92a9b2397658ad8a093ee02f Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 3 Nov 2009 16:51:40 -0800 Subject: Only add rssCloud link to user timeline --- plugins/RSSCloud/RSSCloudPlugin.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'plugins/RSSCloud/RSSCloudPlugin.php') diff --git a/plugins/RSSCloud/RSSCloudPlugin.php b/plugins/RSSCloud/RSSCloudPlugin.php index a971c3156..a86c153f1 100644 --- a/plugins/RSSCloud/RSSCloudPlugin.php +++ b/plugins/RSSCloud/RSSCloudPlugin.php @@ -111,10 +111,7 @@ class RSSCloudPlugin extends Plugin function onStartApiRss($action){ - // XXX: we want to only cloud enable the user_timeline so we need - // to be even more specific than this... FIXME - - if (get_class($action) == 'TwitapistatusesAction') { + if (get_class($action) == 'ApiTimelineUserAction') { $attrs = array('domain' => $this->domain, 'port' => $this->port, -- cgit v1.2.3-54-g00ecf From aa9f81193e9f623dec136c6c5b7ddd6ebb948ab0 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 3 Nov 2009 17:53:17 -0800 Subject: Queue notices for rssCloud --- plugins/RSSCloud/RSSCloudPlugin.php | 57 ++++++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 13 deletions(-) (limited to 'plugins/RSSCloud/RSSCloudPlugin.php') diff --git a/plugins/RSSCloud/RSSCloudPlugin.php b/plugins/RSSCloud/RSSCloudPlugin.php index a86c153f1..816739889 100644 --- a/plugins/RSSCloud/RSSCloudPlugin.php +++ b/plugins/RSSCloud/RSSCloudPlugin.php @@ -130,21 +130,52 @@ class RSSCloudPlugin extends Plugin } } - function onEndNoticeSave($notice){ - - common_debug("RSSCloudPlugin oneEndNoticeSave()"); - - $user = User::staticGet('id', $notice->profile_id); - $feed = common_local_url('api', array('apiaction' => 'statuses', - 'method' => 'user_timeline', - 'argument' => $user->nickname . '.rss')); - - // XXX: Dave's hub for testing - // $endpoint = 'http://rpc.rsscloud.org:5337/rsscloud/ping'; + /** + * Add an RSSCloud queue item for each notice + * + * @param Notice $notice the notice + * @param array &$transports the list of transports (queues) + * + * @return boolean hook return + */ + function onStartEnqueueNotice($notice, &$transports) + { + array_push($transports, 'rsscloud'); + return true; + } - // $notifier = new RSSCloudNotifier(); - // $notifier->postUpdate($endpoint, $feed); + /** + * broadcast the message when not using queuehandler + * + * @param Notice &$notice the notice + * @param array $queue destination queue + * + * @return boolean hook return + */ + function onUnqueueHandleNotice(&$notice, $queue) + { + if (($queue == 'rsscloud') && ($this->_isLocal($notice))) { + + // broadcast the notice here + common_debug('broadcasting rssCloud bound notice ' . $notice->id); + + return false; + } + return true; } + /** + * Determine whether the notice was locally created + * + * @param Notice $notice + * + * @return boolean locality + */ + function _isLocal($notice) + { + return ($notice->is_local == Notice::LOCAL_PUBLIC || + $notice->is_local == Notice::LOCAL_NONPUBLIC); + } + } -- cgit v1.2.3-54-g00ecf From 8980bebcb38eaaca934141b1828e243609577a51 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 4 Nov 2009 17:32:17 -0800 Subject: Add a table and DB_DataObject class for storing cloud subscriptions --- plugins/RSSCloud/RSSCloudPlugin.php | 33 ++++-- plugins/RSSCloud/RSSCloudRequestNotify.php | 167 ++++++++++++++++------------- plugins/RSSCloud/RSSCloudSubscription.php | 82 ++++++++++++++ 3 files changed, 200 insertions(+), 82 deletions(-) create mode 100644 plugins/RSSCloud/RSSCloudSubscription.php (limited to 'plugins/RSSCloud/RSSCloudPlugin.php') diff --git a/plugins/RSSCloud/RSSCloudPlugin.php b/plugins/RSSCloud/RSSCloudPlugin.php index 816739889..10f81b8dd 100644 --- a/plugins/RSSCloud/RSSCloudPlugin.php +++ b/plugins/RSSCloud/RSSCloudPlugin.php @@ -95,14 +95,15 @@ class RSSCloudPlugin extends Plugin { switch ($cls) { - + case 'RSSCloudSubscription': + include_once(INSTALLDIR . '/plugins/RSSCloud/RSSCloudSubscription.php'); + return false; case 'RSSCloudNotifier': - require_once(INSTALLDIR . '/plugins/RSSCloud/RSSCloudNotifier.php'); + include_once(INSTALLDIR . '/plugins/RSSCloud/RSSCloudNotifier.php'); return false; case 'RSSCloudRequestNotifyAction': case 'LoggingAggregatorAction': - common_debug(mb_substr($cls, 0, -6) . '.php'); - require_once(INSTALLDIR . '/plugins/RSSCloud/' . mb_substr($cls, 0, -6) . '.php'); + include_once(INSTALLDIR . '/plugins/RSSCloud/' . mb_substr($cls, 0, -6) . '.php'); return false; default: return true; @@ -155,10 +156,10 @@ class RSSCloudPlugin extends Plugin function onUnqueueHandleNotice(&$notice, $queue) { if (($queue == 'rsscloud') && ($this->_isLocal($notice))) { - + // broadcast the notice here common_debug('broadcasting rssCloud bound notice ' . $notice->id); - + return false; } return true; @@ -176,6 +177,24 @@ class RSSCloudPlugin extends Plugin return ($notice->is_local == Notice::LOCAL_PUBLIC || $notice->is_local == Notice::LOCAL_NONPUBLIC); } - + + + function onCheckSchema() { + $schema = Schema::get(); + $schema->ensureTable('rsscloud_subscription', + array(new ColumnDef('subscribed', 'integer', + null, false, 'PRI'), + new ColumnDef('url', 'varchar', + '255', false, 'PRI'), + new ColumnDef('failures', 'integer', + null, false, 'MUL'), + new ColumnDef('created', 'datetime', + null, false), + new ColumnDef('modified', 'timestamp') + ) + ); + return true; + } + } diff --git a/plugins/RSSCloud/RSSCloudRequestNotify.php b/plugins/RSSCloud/RSSCloudRequestNotify.php index 48bd3fb27..8b5deb136 100644 --- a/plugins/RSSCloud/RSSCloudRequestNotify.php +++ b/plugins/RSSCloud/RSSCloudRequestNotify.php @@ -51,10 +51,10 @@ class RSSCloudRequestNotifyAction extends Action $this->path = $this->arg('path'); $this->protocol = $this->arg('protocol'); $this->procedure = $this->arg('notifyProcedure'); + $this->domain = $this->arg('domain'); + $this->feeds = $this->getFeeds(); - $this->subscriber_url = 'http://' . $this->ip . ':' . $this->port . $this->path; - return true; } @@ -102,70 +102,93 @@ class RSSCloudRequestNotifyAction extends Action return; } - $endpoint = $ip . ':' . $port . $path; + // We have to validate everything before saving anything. + // We only return one success or failure no matter how + // many feeds the subscriber is trying to subscribe to foreach ($this->feeds as $feed) { - $this->saveSubscription($feed); + + if (!$this->validateFeed($feed)) { + $msg = 'Feed subscription failed - Not a valid feed.'; + $this->showResult(false, $msg); + return; + } + + if (!$this->testNotificationHandler($feed)) { + $msg = 'Feed subscription failed - ' . + 'notification handler doesn\'t respond correctly.'; + $this->showResult(false, $msg); + return; + } + } + foreach ($this->feeds as $feed) { + $this->saveSubscription($feed); + } + // XXX: What to do about deleting stale subscriptions? 25 hours seems harsh. // WordPress doesn't ever remove subscriptions. $msg = 'Thanks for the registration. It worked. When the feed(s) update(s) we\'ll notify you. ' . ' Don\'t forget to re-register after 24 hours, your subscription will expire in 25.'; - $this->showResult(true, $msg); + $this->showResult(true, $msg); } - function getFeeds() + function validateFeed($feed) { - $feeds = array(); - - foreach ($this->args as $key => $feed ) { - if (preg_match('|url\d+|', $key)) { + $user = $this->userFromFeed($feed); - if ($this->testFeed($feed)) { - $feeds[] = $feed; - } else { - $msg = 'RSSCloud Plugin - ' . $this->ip . ' tried to subscribe ' . - 'to a non-existent feed: ' . $feed; - common_log(LOG_WARN, $msg); - } - } + if (empty($user)) { + return false; } - return $feeds; + return true; } - function testNotificationHandler($feed) - { - $notifier = new RSSCloudNotifier(); - return $notifier->postUpdate($endpoint, $feed); - } - // returns valid user or false - function testFeed($feed) + function getFeeds() { - $user = $this->userFromFeed($feed); + $feeds = array(); + + while (list($key, $feed) = each ($this->args)) { + if (preg_match('/^url\d*$/', $key)) { + $feeds[] = $feed; + } + } - if (!empty($user)) { + return $feeds; + } - common_debug("Valid feed: $feed"); + function testNotificationHandler($feed) + { + common_debug("RSSCloudPlugin - testNotificationHandler()"); + + $notifier = new RSSCloudNotifier(); + + if (isset($this->domain)) { + + //get + + $this->url = 'http://' . $this->domain . ':' . $this->port . '/' . $this->path; + + common_debug('domain set need to send challenge'); + + } else { + + //post + + $this->url = 'http://' . $this->ip . ':' . $this->port . '/' . $this->path; + + //return $notifier->postUpdate($endpoint, $feed); - // OK, so this is a valid profile feed url, now let's see if the - // other system reponds to our notifications before we - // add the sub... + } - if ($this->testNotificationHandler($feed)) { - return true; - } - } + return true; - return false; } - // this actually does the validating and figuring out the - // user, which it returns function userFromFeed($feed) { // We only do profile feeds @@ -185,45 +208,39 @@ class RSSCloudRequestNotifyAction extends Action function saveSubscription($feed) { - // check to see if we already have a profile for this subscriber - - $other = Remote_profile::staticGet('uri', $this->subscriber_url); - - if ($other === false) { - $other->saveProfile(); - } - - $user = userFromFeed($feed); - - $result = subs_subscribe_to($user, $other); - - if ($result != true) { - $msg = "RSSPlugin - got '$result' trying to subscribe " . - "$this->subscriber_url to $user->nickname" . "'s profile feed."; - common_log(LOG_WARN, $msg); + $user = $this->userFromFeed($feed); + + common_debug('user = ' . $user->id); + + $sub = RSSCloudSubscription::getSubscription($user->id, $this->url); + + if ($sub) { + common_debug("already subscribed to that!"); } else { - $msg = 'RSSCloud plugin - subscribe: ' . $this->subscriber_url . - ' subscribed to ' . $feed; - - common_log(LOG_INFO, $msg); + common_debug('No feed for user ' . $user->id . ' notify: ' . $this->url); } - } - - function saveProfile() - { - common_debug("Saving remote profile for $this->subscriber_url"); - - // XXX: We need to add a field to Remote_profile to indicate the kind - // of remote profile? i.e: OMB, RSSCloud, PuSH, Twitter - - $remote = new Remote_profile(); - $remote->uri = $this->subscriber_url; - $remote->postnoticeurl = $this->subscriber_url; - $remote->created = DB_DataObject_Cast::dateTime(); - - if (!$remote->insert()) { - throw new Exception(_('RSSCloud plugin - Error inserting remote profile!')); + + common_debug('RSSPlugin - saveSubscription'); + // turn debugging high + DB_DataObject::debugLevel(5); + + $sub = new RSSCloudSubscription(); + + $sub->subscribed = $user->id; + $sub->url = $this->url; + $sub->created = common_sql_now(); + + // auto timestamp doesn't seem to work for me + + $sub->modified = common_sql_now(); + + if (!$sub->insert()) { + common_log_db_error($sub, 'INSERT', __FILE__); + return false; } + DB_DataObject::debugLevel(); + + return true; } function showResult($success, $msg) diff --git a/plugins/RSSCloud/RSSCloudSubscription.php b/plugins/RSSCloud/RSSCloudSubscription.php new file mode 100644 index 000000000..0b102e2e6 --- /dev/null +++ b/plugins/RSSCloud/RSSCloudSubscription.php @@ -0,0 +1,82 @@ +. + */ + +if (!defined('STATUSNET') && !defined('LACONICA')) { + exit(1); +} + +/** + * Table Definition for rsscloud_subscription + */ + +require_once INSTALLDIR . '/classes/Memcached_DataObject.php'; + +class RSSCloudSubscription extends Memcached_DataObject { + + var $__table='rsscloud_subscription'; // table name + var $subscribed; // int primary key user id + var $url; // string primary key + var $failures; // int + var $created; // datestamp() + var $modified; // timestamp() not_null default_CURRENT_TIMESTAMP + + function staticGet($k,$v=NULL) { return DB_DataObject::staticGet('DataObjects_Grp',$k,$v); } + + function table() + { + global $_DB_DATAOBJECT; + $dbtype = $_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]->dsn['phptype']; + + $cols = array( + 'subscribed' => DB_DATAOBJECT_INT, + 'url' => DB_DATAOBJECT_STR, + 'failures' => DB_DATAOBJECT_INT, + 'created' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME, + 'modified' => ($dbtype == 'mysql') ? + DB_DATAOBJECT_MYSQLTIMESTAMP : + DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + ); + + + // common_debug(var_export($cols, true)); + return $cols; + } + + function keys() + { + return array('subscribed', 'url'); + } + + static function getSubscription($subscribed, $url) + { + $sub = new RSSCloudSubscription(); + $sub->whereAdd("subscribed = $subscribed"); + $sub->whereAdd("url = $url"); + $sub->limit(1); + + if ($sub->find()) { + $sub->fetch(); + return $sub; + } + + return false; + } + +} +?> \ No newline at end of file -- cgit v1.2.3-54-g00ecf From 7638e2713d91a829646358fbac5ab8d6ad08d6f6 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 1 Dec 2009 01:24:39 +0000 Subject: Set modified column correctly. --- plugins/RSSCloud/RSSCloudPlugin.php | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'plugins/RSSCloud/RSSCloudPlugin.php') diff --git a/plugins/RSSCloud/RSSCloudPlugin.php b/plugins/RSSCloud/RSSCloudPlugin.php index 10f81b8dd..8e57b4a3e 100644 --- a/plugins/RSSCloud/RSSCloudPlugin.php +++ b/plugins/RSSCloud/RSSCloudPlugin.php @@ -50,7 +50,7 @@ class RSSCloudPlugin extends Plugin // set defaults - $local_server = parse_url(common_path('rsscloud/request_notify')); + $local_server = parse_url(common_path('/main/rsscloud/request_notify')); if (empty($this->domain)) { $this->domain = $local_server['host']; @@ -61,7 +61,7 @@ class RSSCloudPlugin extends Plugin } if (empty($this->path)) { - $this->path = '/rsscloud/request_notify'; + $this->path = '/main/rsscloud/request_notify'; } if (empty($this->funct)) { @@ -83,10 +83,10 @@ class RSSCloudPlugin extends Plugin function onRouterInitialized(&$m) { - $m->connect('rsscloud/request_notify', array('action' => 'RSSCloudRequestNotify')); + $m->connect('/main/rsscloud/request_notify', array('action' => 'RSSCloudRequestNotify')); // XXX: This is just for end-to-end testing - $m->connect('rsscloud/notify', array('action' => 'LoggingAggregator')); + $m->connect('/main/rsscloud/notify', array('action' => 'LoggingAggregator')); return true; } @@ -110,8 +110,8 @@ class RSSCloudPlugin extends Plugin } } - function onStartApiRss($action){ - + function onStartApiRss($action) + { if (get_class($action) == 'ApiTimelineUserAction') { $attrs = array('domain' => $this->domain, @@ -126,8 +126,8 @@ class RSSCloudPlugin extends Plugin foreach ($attrs as $name => $value) { $action->xw->writeAttribute($name, $value); } - $action->xw->endElement(); + $action->xw->endElement(); } } @@ -178,7 +178,6 @@ class RSSCloudPlugin extends Plugin $notice->is_local == Notice::LOCAL_NONPUBLIC); } - function onCheckSchema() { $schema = Schema::get(); $schema->ensureTable('rsscloud_subscription', @@ -187,10 +186,13 @@ class RSSCloudPlugin extends Plugin new ColumnDef('url', 'varchar', '255', false, 'PRI'), new ColumnDef('failures', 'integer', - null, false, 'MUL'), + null, false, null, 0), new ColumnDef('created', 'datetime', null, false), - new ColumnDef('modified', 'timestamp') + new ColumnDef('modified', 'timestamp', + null, false, null, + 'CURRENT_TIMESTAMP', + 'on update CURRENT_TIMESTAMP') ) ); return true; -- cgit v1.2.3-54-g00ecf From 61804bb7bbd0cea92ba2bbcce15e37a35195341a Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 7 Dec 2009 09:10:04 +0000 Subject: Plugin now checks notify handlers before registering subscriptions --- plugins/RSSCloud/LoggingAggregator.php | 5 +- plugins/RSSCloud/RSSCloudNotifier.php | 90 +++++++++++++---------- plugins/RSSCloud/RSSCloudPlugin.php | 2 + plugins/RSSCloud/RSSCloudRequestNotify.php | 112 ++++++++++++++--------------- 4 files changed, 110 insertions(+), 99 deletions(-) (limited to 'plugins/RSSCloud/RSSCloudPlugin.php') diff --git a/plugins/RSSCloud/LoggingAggregator.php b/plugins/RSSCloud/LoggingAggregator.php index cbdefc36b..02175f43a 100644 --- a/plugins/RSSCloud/LoggingAggregator.php +++ b/plugins/RSSCloud/LoggingAggregator.php @@ -1,5 +1,4 @@ challenge . "' />\n"; + echo $this->challenge; } else { @@ -92,7 +90,6 @@ class LoggingAggregatorAction extends Action header('Content-Type: text/xml'); echo '' . "\n"; - } $this->ip = $_SERVER['REMOTE_ADDR']; diff --git a/plugins/RSSCloud/RSSCloudNotifier.php b/plugins/RSSCloud/RSSCloudNotifier.php index c2130b7b8..eb3198b5a 100644 --- a/plugins/RSSCloud/RSSCloudNotifier.php +++ b/plugins/RSSCloud/RSSCloudNotifier.php @@ -33,59 +33,77 @@ if (!defined('STATUSNET')) { class RSSCloudNotifier { - function postUpdate($endpoint, $feed) { - common_debug("CloudNotifier->notify: $feed"); + function challenge($endpoint, $feed) + { + $code = common_confirmation_code(128); + $params = array('url' => $feed, 'challenge' => $code); + $url = $endpoint . '?' . http_build_query($params); + + try { + $client = new HTTPClient(); + $response = $client->get($url); + } catch (HTTP_Request2_Exception $e) { + common_log(LOG_INFO, 'RSSCloud plugin - failure testing notify handler ' . + $endpoint . ' - ' . $e->getMessage()); + return false; + } - $params = 'url=' . urlencode($feed); + // Check response is betweet 200 and 299 and body contains challenge data - $result = $this->httpPost($endpoint, $params); + $status = $response->getStatus(); + $body = $response->getBody(); - // XXX: Make all this use CurlClient (lib/curlclient.php) + if ($status >= 200 && $status < 300) { - if ($result) { - common_debug('RSSCloud plugin - success notifying cloud endpoint!'); + if (strpos($body, $code) !== false) { + common_log(LOG_INFO, 'RSSCloud plugin - ' . + "success testing notify handler: $endpoint"); + return true; + } else { + common_log(LOG_INFO, 'RSSCloud plugin - ' . + 'challenge/repsonse failed for notify handler ' . + $endpoint); + common_debug('body = ' . var_export($body, true)); + return false; + } } else { - common_debug('RSSClous plugin - failure notifying cloud endpoint!'); + common_log(LOG_INFO, 'RSSCloud plugin - ' . + "failure testing notify handler: $endpoint " . + ' - got HTTP ' . $status); + common_debug('body = ' . var_export($body, true)); + return false; } - - return $result; } - function userAgent() - { - return 'rssCloudPlugin/' . RSSCLOUDPLUGIN_VERSION . - ' StatusNet/' . STATUSNET_VERSION; - } - - private function httpPost($url, $params) { - - $options = array(CURLOPT_URL => $url, - CURLOPT_POST => true, - CURLOPT_POSTFIELDS => $params, - CURLOPT_USERAGENT => $this->userAgent(), - CURLOPT_RETURNTRANSFER => true, - CURLOPT_FAILONERROR => true, - CURLOPT_HEADER => false, - CURLOPT_FOLLOWLOCATION => true, - CURLOPT_CONNECTTIMEOUT => 5, - CURLOPT_TIMEOUT => 5); - - $ch = curl_init(); - curl_setopt_array($ch, $options); + function postUpdate($endpoint, $feed) { - $response = curl_exec($ch); + $headers = array(); + $postdata = array('url' => $feed); - $info = curl_getinfo($ch); + try { + $client = new HTTPClient(); + $response = $client->post($endpoint, $headers, $postdata); + } catch (HTTP_Request2_Exception $e) { + common_log(LOG_INFO, 'RSSCloud plugin - failure notifying ' . + $endpoint . ' that feed ' . $feed . + ' has changed: ' . $e->getMessage()); + return false; + } - curl_close($ch); + $status = $response->getStatus(); - if ($info['http_code'] == 200) { + if ($status >= 200 && $status < 300) { + common_log(LOG_INFO, 'RSSCloud plugin - success notifying ' . + $endpoint . ' that feed ' . $feed . ' has changed.'); return true; } else { + common_log(LOG_INFO, 'RSSCloud plugin - failure notifying ' . + $endpoint . ' that feed ' . $feed . + ' has changed: got HTTP ' . $status); + common_debug('body = ' . var_export($response->getBody(), true)); return false; } } } - diff --git a/plugins/RSSCloud/RSSCloudPlugin.php b/plugins/RSSCloud/RSSCloudPlugin.php index 8e57b4a3e..402fbec2d 100644 --- a/plugins/RSSCloud/RSSCloudPlugin.php +++ b/plugins/RSSCloud/RSSCloudPlugin.php @@ -112,6 +112,8 @@ class RSSCloudPlugin extends Plugin function onStartApiRss($action) { + // XXX: Add RSS 1.0 user feeds + if (get_class($action) == 'ApiTimelineUserAction') { $attrs = array('domain' => $this->domain, diff --git a/plugins/RSSCloud/RSSCloudRequestNotify.php b/plugins/RSSCloud/RSSCloudRequestNotify.php index 8b5deb136..135c316f7 100644 --- a/plugins/RSSCloud/RSSCloudRequestNotify.php +++ b/plugins/RSSCloud/RSSCloudRequestNotify.php @@ -52,7 +52,7 @@ class RSSCloudRequestNotifyAction extends Action $this->protocol = $this->arg('protocol'); $this->procedure = $this->arg('notifyProcedure'); $this->domain = $this->arg('domain'); - + $this->feeds = $this->getFeeds(); return true; @@ -103,29 +103,29 @@ class RSSCloudRequestNotifyAction extends Action } // We have to validate everything before saving anything. - // We only return one success or failure no matter how + // We only return one success or failure no matter how // many feeds the subscriber is trying to subscribe to foreach ($this->feeds as $feed) { - + if (!$this->validateFeed($feed)) { $msg = 'Feed subscription failed - Not a valid feed.'; $this->showResult(false, $msg); return; } - + if (!$this->testNotificationHandler($feed)) { $msg = 'Feed subscription failed - ' . 'notification handler doesn\'t respond correctly.'; $this->showResult(false, $msg); - return; + return; } - + } foreach ($this->feeds as $feed) { $this->saveSubscription($feed); - } + } // XXX: What to do about deleting stale subscriptions? 25 hours seems harsh. // WordPress doesn't ever remove subscriptions. @@ -133,7 +133,7 @@ class RSSCloudRequestNotifyAction extends Action $msg = 'Thanks for the registration. It worked. When the feed(s) update(s) we\'ll notify you. ' . ' Don\'t forget to re-register after 24 hours, your subscription will expire in 25.'; - $this->showResult(true, $msg); + $this->showResult(true, $msg); } function validateFeed($feed) @@ -147,45 +147,45 @@ class RSSCloudRequestNotifyAction extends Action return true; } - function getFeeds() { $feeds = array(); - - while (list($key, $feed) = each ($this->args)) { + + while (list($key, $feed) = each ($this->args)) { if (preg_match('/^url\d*$/', $key)) { $feeds[] = $feed; - } + } } return $feeds; } function testNotificationHandler($feed) - { + { common_debug("RSSCloudPlugin - testNotificationHandler()"); - + $notifier = new RSSCloudNotifier(); - + if (isset($this->domain)) { - - //get - - $this->url = 'http://' . $this->domain . ':' . $this->port . '/' . $this->path; - - common_debug('domain set need to send challenge'); - + + // 'domain' param set, so we have to use GET and send a challenge + + $endpoint = 'http://' . $this->domain . ':' . $this->port . '/' . $this->path; + + common_log(LOG_INFO, 'Testing notification handler with challenge: ' . + $endpoint); + + return $notifier->challenge($endpoint, $feed); + } else { - - //post - - $this->url = 'http://' . $this->ip . ':' . $this->port . '/' . $this->path; - - //return $notifier->postUpdate($endpoint, $feed); - } + $endpoint = 'http://' . $this->ip . ':' . $this->port . '/' . $this->path; - return true; + common_log(LOG_INFO, 'Testing notification handler: ' . + $endpoint); + + return $notifier->postUpdate($endpoint, $feed); + } } @@ -193,6 +193,8 @@ class RSSCloudRequestNotifyAction extends Action { // We only do profile feeds + // XXX: Add cloud element to RSS 1.0 feeds + $path = common_path('api/statuses/user_timeline/'); $valid = '%^' . $path . '(?.*)\.rss$%'; @@ -209,37 +211,31 @@ class RSSCloudRequestNotifyAction extends Action function saveSubscription($feed) { $user = $this->userFromFeed($feed); - - common_debug('user = ' . $user->id); - + $sub = RSSCloudSubscription::getSubscription($user->id, $this->url); - + if ($sub) { - common_debug("already subscribed to that!"); + common_debug("Already subscribed to that!"); } else { - common_debug('No feed for user ' . $user->id . ' notify: ' . $this->url); - } - - common_debug('RSSPlugin - saveSubscription'); - // turn debugging high - DB_DataObject::debugLevel(5); - - $sub = new RSSCloudSubscription(); - - $sub->subscribed = $user->id; - $sub->url = $this->url; - $sub->created = common_sql_now(); - - // auto timestamp doesn't seem to work for me - - $sub->modified = common_sql_now(); - - if (!$sub->insert()) { - common_log_db_error($sub, 'INSERT', __FILE__); - return false; + + $sub = new RSSCloudSubscription(); + + $sub->subscribed = $user->id; + $sub->url = $this->url; + $sub->created = common_sql_now(); + + // auto timestamp doesn't seem to work for me + + // $sub->modified = common_sql_now(); + + if (!$sub->insert()) { + common_log_db_error($sub, 'INSERT', __FILE__); + return false; + } + + DB_DataObject::debugLevel(); } - DB_DataObject::debugLevel(); - + return true; } @@ -253,5 +249,3 @@ class RSSCloudRequestNotifyAction extends Action } - - -- cgit v1.2.3-54-g00ecf From d091d061151749feddd3751f953f9bec48e382f2 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 8 Dec 2009 06:26:11 +0000 Subject: Notifier works, and bad subscriptions are deleted properly now. --- plugins/RSSCloud/RSSCloudNotifier.php | 78 +++++++++++++++++++++++++++++- plugins/RSSCloud/RSSCloudPlugin.php | 7 ++- plugins/RSSCloud/RSSCloudRequestNotify.php | 58 +++++++++++----------- 3 files changed, 113 insertions(+), 30 deletions(-) (limited to 'plugins/RSSCloud/RSSCloudPlugin.php') diff --git a/plugins/RSSCloud/RSSCloudNotifier.php b/plugins/RSSCloud/RSSCloudNotifier.php index eb3198b5a..67bd000f0 100644 --- a/plugins/RSSCloud/RSSCloudNotifier.php +++ b/plugins/RSSCloud/RSSCloudNotifier.php @@ -33,6 +33,8 @@ if (!defined('STATUSNET')) { class RSSCloudNotifier { + const MAX_FAILURES = 3; + function challenge($endpoint, $feed) { $code = common_confirmation_code(128); @@ -55,6 +57,11 @@ class RSSCloudNotifier { if ($status >= 200 && $status < 300) { + // NOTE: the spec says that the body must contain the string + // challenge. It doesn't say that the body must contain the + // challenge string ONLY, although that seems to be the way + // the other implementations have interpreted it. + if (strpos($body, $code) !== false) { common_log(LOG_INFO, 'RSSCloud plugin - ' . "success testing notify handler: $endpoint"); @@ -100,10 +107,79 @@ class RSSCloudNotifier { common_log(LOG_INFO, 'RSSCloud plugin - failure notifying ' . $endpoint . ' that feed ' . $feed . ' has changed: got HTTP ' . $status); - common_debug('body = ' . var_export($response->getBody(), true)); return false; } } + function notify($profile) + { + $feed = common_path('api/statuses/user_timeline/') . + $profile->nickname . '.rss'; + + $cloudSub = new RSSCloudSubscription(); + $cloudSub->subscribed = $profile->id; + + if ($cloudSub->find()) { + while ($cloudSub->fetch()) { + $result = $this->postUpdate($cloudSub->url, $feed); + if ($result == false) { + $this->handleFailure($cloudSub); + } + } + } + } + + function handleFailure($cloudSub) + { + $failCnt = $cloudSub->failures + 1; + + if ($failCnt == self::MAX_FAILURES) { + + common_log(LOG_INFO, + 'Deleting RSSCloud subcription (max failure count reached), profile: ' . + $cloudSub->subscribed . + ' handler: ' . + $cloudSub->url); + + // XXX: WTF! ->delete() doesn't work. Clearly, there are some issues with + // the DB_DataObject, or my understanding of it. Have to drop into SQL. + + // $result = $cloudSub->delete(); + + $qry = 'DELETE from rsscloud_subscription' . + ' WHERE subscribed = ' . $cloudSub->subscribed . + ' AND url = \'' . $cloudSub->url . '\''; + + $result = $cloudSub->query($qry); + + if (!$result) { + common_log_db_error($cloudSub, 'DELETE', __FILE__); + common_log(LOG_ERR, 'Could not delete RSSCloud subscription.'); + } + + } else { + + common_debug('Updating failure count on RSSCloud subscription. ' . $failCnt); + + $failCnt = $cloudSub->failures + 1; + + // XXX: ->update() not working either, gar! + + $qry = 'UPDATE rsscloud_subscription' . + ' SET failures = ' . $failCnt . + ' WHERE subscribed = ' . $cloudSub->subscribed . + ' AND url = \'' . $cloudSub->url . '\''; + + common_debug($qry); + + $result = $cloudSub->query($qry); + + if (!$result) { + common_log_db_error($cloudsub, 'UPDATE', __FILE__); + common_log(LOG_ERR, 'Could not update failure count on RSSCloud subscription'); + } + } + } + } diff --git a/plugins/RSSCloud/RSSCloudPlugin.php b/plugins/RSSCloud/RSSCloudPlugin.php index 402fbec2d..b9187d86c 100644 --- a/plugins/RSSCloud/RSSCloudPlugin.php +++ b/plugins/RSSCloud/RSSCloudPlugin.php @@ -159,11 +159,16 @@ class RSSCloudPlugin extends Plugin { if (($queue == 'rsscloud') && ($this->_isLocal($notice))) { - // broadcast the notice here common_debug('broadcasting rssCloud bound notice ' . $notice->id); + $profile = $notice->getProfile(); + + $notifier = new RSSCloudNotifier(); + $notifier->notify($profile); + return false; } + return true; } diff --git a/plugins/RSSCloud/RSSCloudRequestNotify.php b/plugins/RSSCloud/RSSCloudRequestNotify.php index 135c316f7..36959755a 100644 --- a/plugins/RSSCloud/RSSCloudRequestNotify.php +++ b/plugins/RSSCloud/RSSCloudRequestNotify.php @@ -1,5 +1,4 @@ ip = $_SERVER['REMOTE_ADDR']; $this->port = $this->arg('port'); $this->path = $this->arg('path'); + + if ($this->path[0] != '/') { + $this->path = '/' . $this->path; + } + $this->protocol = $this->arg('protocol'); $this->procedure = $this->arg('notifyProcedure'); $this->domain = $this->arg('domain'); @@ -73,14 +77,10 @@ class RSSCloudRequestNotifyAction extends Action $missing[] = 'port'; } - $path = $this->arg('path'); - if (empty($this->path)) { $missing[] = 'path'; } - $protocol = $this->arg('protocol'); - if (empty($this->protocol)) { $missing[] = 'protocol'; } @@ -127,11 +127,12 @@ class RSSCloudRequestNotifyAction extends Action $this->saveSubscription($feed); } - // XXX: What to do about deleting stale subscriptions? 25 hours seems harsh. - // WordPress doesn't ever remove subscriptions. + // XXX: What to do about deleting stale subscriptions? + // 25 hours seems harsh. WordPress doesn't ever remove + // subscriptions. - $msg = 'Thanks for the registration. It worked. When the feed(s) update(s) we\'ll notify you. ' . - ' Don\'t forget to re-register after 24 hours, your subscription will expire in 25.'; + $msg = 'Thanks for the subscription. ' . + 'When the feed(s) update(s) we\'ll notify you.'; $this->showResult(true, $msg); } @@ -164,36 +165,40 @@ class RSSCloudRequestNotifyAction extends Action { common_debug("RSSCloudPlugin - testNotificationHandler()"); + $notifyUrl = $this->getNotifyUrl(); + $notifier = new RSSCloudNotifier(); if (isset($this->domain)) { // 'domain' param set, so we have to use GET and send a challenge - $endpoint = 'http://' . $this->domain . ':' . $this->port . '/' . $this->path; - common_log(LOG_INFO, 'Testing notification handler with challenge: ' . - $endpoint); - - return $notifier->challenge($endpoint, $feed); + $notifyUrl); + return $notifier->challenge($notifyUrl, $feed); } else { - - $endpoint = 'http://' . $this->ip . ':' . $this->port . '/' . $this->path; - common_log(LOG_INFO, 'Testing notification handler: ' . - $endpoint); + $notifyUrl); - return $notifier->postUpdate($endpoint, $feed); + return $notifier->postUpdate($notifyUrl, $feed); } - } + function getNotifyUrl() + { + if (isset($this->domain)) { + return 'http://' . $this->domain . ':' . $this->port . $this->path; + } else { + return 'http://' . $this->ip . ':' . $this->port . $this->path; + } + } + function userFromFeed($feed) { // We only do profile feeds - // XXX: Add cloud element to RSS 1.0 feeds + // XXX: Add cloud element to RSS 1.0 feeds? $path = common_path('api/statuses/user_timeline/'); $valid = '%^' . $path . '(?.*)\.rss$%'; @@ -212,7 +217,9 @@ class RSSCloudRequestNotifyAction extends Action { $user = $this->userFromFeed($feed); - $sub = RSSCloudSubscription::getSubscription($user->id, $this->url); + $notifyUrl = $this->getNotifyUrl(); + + $sub = RSSCloudSubscription::getSubscription($user->id, $notifyUrl); if ($sub) { common_debug("Already subscribed to that!"); @@ -221,19 +228,14 @@ class RSSCloudRequestNotifyAction extends Action $sub = new RSSCloudSubscription(); $sub->subscribed = $user->id; - $sub->url = $this->url; + $sub->url = $notifyUrl; $sub->created = common_sql_now(); - // auto timestamp doesn't seem to work for me - - // $sub->modified = common_sql_now(); - if (!$sub->insert()) { common_log_db_error($sub, 'INSERT', __FILE__); return false; } - DB_DataObject::debugLevel(); } return true; -- cgit v1.2.3-54-g00ecf From ff26b8d88b9e3d185afa83fd2b08c0d67cd4f78d Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 8 Dec 2009 21:04:26 +0000 Subject: Add an RSSCloud queue handler daemon --- plugins/RSSCloud/RSSCloudNotifier.php | 2 + plugins/RSSCloud/RSSCloudPlugin.php | 7 +++ plugins/RSSCloud/RSSCloudQueueHandler.php | 78 +++++++++++++++++++++++++++++++ scripts/stopdaemons.sh | 2 +- 4 files changed, 88 insertions(+), 1 deletion(-) create mode 100755 plugins/RSSCloud/RSSCloudQueueHandler.php (limited to 'plugins/RSSCloud/RSSCloudPlugin.php') diff --git a/plugins/RSSCloud/RSSCloudNotifier.php b/plugins/RSSCloud/RSSCloudNotifier.php index 67bd000f0..909cf5c9f 100644 --- a/plugins/RSSCloud/RSSCloudNotifier.php +++ b/plugins/RSSCloud/RSSCloudNotifier.php @@ -127,6 +127,8 @@ class RSSCloudNotifier { } } } + + return true; } function handleFailure($cloudSub) diff --git a/plugins/RSSCloud/RSSCloudPlugin.php b/plugins/RSSCloud/RSSCloudPlugin.php index b9187d86c..fcd468f55 100644 --- a/plugins/RSSCloud/RSSCloudPlugin.php +++ b/plugins/RSSCloud/RSSCloudPlugin.php @@ -205,5 +205,12 @@ class RSSCloudPlugin extends Plugin return true; } + function onGetValidDaemons($daemons) + { + array_push($daemons, INSTALLDIR . + '/plugins/RSSCloud/RSSCloudQueueHandler.php'); + return true; + } + } diff --git a/plugins/RSSCloud/RSSCloudQueueHandler.php b/plugins/RSSCloud/RSSCloudQueueHandler.php new file mode 100755 index 000000000..693dd27c1 --- /dev/null +++ b/plugins/RSSCloud/RSSCloudQueueHandler.php @@ -0,0 +1,78 @@ +#!/usr/bin/env php +. + */ + +define('INSTALLDIR', realpath(dirname(__FILE__) . '/../..')); + +$shortoptions = 'i::'; +$longoptions = array('id::'); + +$helptext = <<log(LOG_INFO, "INITIALIZE"); + $this->notifier = new RSSCloudNotifier(); + return true; + } + + function handle_notice($notice) + { + $profile = $notice->getProfile(); + return $this->notifier->notify($profile); + } + + function finish() + { + } + +} + +if (have_option('i')) { + $id = get_option_value('i'); +} else if (have_option('--id')) { + $id = get_option_value('--id'); +} else if (count($args) > 0) { + $id = $args[0]; +} else { + $id = null; +} + +$handler = new RSSCloudQueueHandler($id); + +$handler->runOnce(); diff --git a/scripts/stopdaemons.sh b/scripts/stopdaemons.sh index 90e7331ca..c790f1f34 100755 --- a/scripts/stopdaemons.sh +++ b/scripts/stopdaemons.sh @@ -25,7 +25,7 @@ DIR=`php $SDIR/getpiddir.php` for f in jabberhandler ombhandler publichandler smshandler pinghandler \ xmppconfirmhandler xmppdaemon twitterhandler facebookhandler \ - twitterstatusfetcher synctwitterfriends pluginhandler; do + twitterstatusfetcher synctwitterfriends pluginhandler rsscloudhandler; do FILES="$DIR/$f.*.pid" for ff in "$FILES" ; do -- cgit v1.2.3-54-g00ecf From 48af79dbb4cf1b4f915bf0d3d05e9fe3770664df Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Fri, 11 Dec 2009 17:50:10 -0800 Subject: Added a bunch of function commment blocks --- plugins/RSSCloud/LoggingAggregator.php | 30 +++++++++++ plugins/RSSCloud/RSSCloudNotifier.php | 52 ++++++++++++++++-- plugins/RSSCloud/RSSCloudPlugin.php | 63 ++++++++++++++++++++-- plugins/RSSCloud/RSSCloudRequestNotify.php | 85 +++++++++++++++++++++++++++++- 4 files changed, 222 insertions(+), 8 deletions(-) (limited to 'plugins/RSSCloud/RSSCloudPlugin.php') diff --git a/plugins/RSSCloud/LoggingAggregator.php b/plugins/RSSCloud/LoggingAggregator.php index 02175f43a..c81a987f7 100644 --- a/plugins/RSSCloud/LoggingAggregator.php +++ b/plugins/RSSCloud/LoggingAggregator.php @@ -32,6 +32,19 @@ if (!defined('STATUSNET')) { exit(1); } +/** + * Dummy aggregator that acts as a proper notification handler. It + * doesn't do anything but respond correctly when notified via + * REST. Mostly, this is just and action I used to develop the plugin + * and easily test things end-to-end. I'm leaving it in here as it + * may be useful for developing the plugin further. + * + * @category Plugin + * @package StatusNet + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + **/ class LoggingAggregatorAction extends Action { @@ -45,6 +58,7 @@ class LoggingAggregatorAction extends Action * * @return boolean false if user doesn't exist */ + function prepare($args) { parent::prepare($args); @@ -58,6 +72,14 @@ class LoggingAggregatorAction extends Action return true; } + /** + * Handle the request + * + * @param array $args $_REQUEST data (unused) + * + * @return void + */ + function handle($args) { parent::handle($args); @@ -98,6 +120,14 @@ class LoggingAggregatorAction extends Action $this->url . ' has been updated.'); } + /** + * Show an XML error when things go badly + * + * @param string $msg the error message + * + * @return void + */ + function showError($msg) { header('HTTP/1.1 400 Bad Request'); diff --git a/plugins/RSSCloud/RSSCloudNotifier.php b/plugins/RSSCloud/RSSCloudNotifier.php index 909cf5c9f..485c4dcdf 100644 --- a/plugins/RSSCloud/RSSCloudNotifier.php +++ b/plugins/RSSCloud/RSSCloudNotifier.php @@ -31,10 +31,29 @@ if (!defined('STATUSNET')) { exit(1); } +/** + * Class for notifying cloud-enabled RSS aggregators that StatusNet + * feeds have been updated. + * + * @category Plugin + * @package StatusNet + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + **/ class RSSCloudNotifier { const MAX_FAILURES = 3; + /** + * Send an HTTP GET to the notification handler with a + * challenge string to see if it repsonds correctly. + * + * @param String $endpoint URL of the notification handler + * @param String $feed the feed being subscribed to + * + * @return boolean success + */ function challenge($endpoint, $feed) { $code = common_confirmation_code(128); @@ -60,7 +79,7 @@ class RSSCloudNotifier { // NOTE: the spec says that the body must contain the string // challenge. It doesn't say that the body must contain the // challenge string ONLY, although that seems to be the way - // the other implementations have interpreted it. + // the other implementors have interpreted it. if (strpos($body, $code) !== false) { common_log(LOG_INFO, 'RSSCloud plugin - ' . @@ -82,6 +101,15 @@ class RSSCloudNotifier { } } + /** + * HTTP POST a notification that a feed has been updated + * ('ping the cloud'). + * + * @param String $endpoint URL of the notification handler + * @param String $feed the feed being subscribed to + * + * @return boolean success + */ function postUpdate($endpoint, $feed) { $headers = array(); @@ -111,6 +139,14 @@ class RSSCloudNotifier { } } + /** + * Notify all subscribers to a profile feed that it has changed. + * + * @param Profile $profile the profile whose feed has been + * updated + * + * @return boolean success + */ function notify($profile) { $feed = common_path('api/statuses/user_timeline/') . @@ -131,6 +167,18 @@ class RSSCloudNotifier { return true; } + /** + * Handle problems posting cloud notifications. Increment the failure + * count, or delete the subscription if the maximum number of failures + * is exceeded. + * + * XXX: Redo with proper DB_DataObject methods once I figure out what + * what the problem is with pluginized DB_DataObjects. -Z + * + * @param RSSCloudSubscription $cloudSub the subscription in question + * + * @return boolean success + */ function handleFailure($cloudSub) { $failCnt = $cloudSub->failures + 1; @@ -172,8 +220,6 @@ class RSSCloudNotifier { ' WHERE subscribed = ' . $cloudSub->subscribed . ' AND url = \'' . $cloudSub->url . '\''; - common_debug($qry); - $result = $cloudSub->query($qry); if (!$result) { diff --git a/plugins/RSSCloud/RSSCloudPlugin.php b/plugins/RSSCloud/RSSCloudPlugin.php index fcd468f55..8c0bfa904 100644 --- a/plugins/RSSCloud/RSSCloudPlugin.php +++ b/plugins/RSSCloud/RSSCloudPlugin.php @@ -31,15 +31,35 @@ if (!defined('STATUSNET')) { exit(1); } -define('RSSCLOUDPLUGIN_VERSION', '0.1'); +/** + * Plugin class for adding RSSCloud capabilities to StatusNet + * + * @category Plugin + * @package StatusNet + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + **/ class RSSCloudPlugin extends Plugin { + /** + * Our friend, the constructor + * + * @return void + */ function __construct() { parent::__construct(); } + /** + * Setup the info for the subscription handler. Allow overriding + * to point at another cloud hub (not currently used). + * + * @return void + */ + function onInitializePlugin() { $this->domain = common_config('rsscloud', 'domain'); @@ -91,6 +111,16 @@ class RSSCloudPlugin extends Plugin return true; } + /** + * Automatically load the actions and libraries used by + * the RSSCloud plugin + * + * @param Class $cls the class + * + * @return boolean hook return + * + */ + function onAutoload($cls) { switch ($cls) @@ -110,10 +140,17 @@ class RSSCloudPlugin extends Plugin } } + /** + * Add a element to the RSS feed (after the rss + * element is started). + * + * @param Action $action + * + * @return void + */ + function onStartApiRss($action) { - // XXX: Add RSS 1.0 user feeds - if (get_class($action) == 'ApiTimelineUserAction') { $attrs = array('domain' => $this->domain, @@ -141,6 +178,7 @@ class RSSCloudPlugin extends Plugin * * @return boolean hook return */ + function onStartEnqueueNotice($notice, &$transports) { array_push($transports, 'rsscloud'); @@ -155,6 +193,7 @@ class RSSCloudPlugin extends Plugin * * @return boolean hook return */ + function onUnqueueHandleNotice(&$notice, $queue) { if (($queue == 'rsscloud') && ($this->_isLocal($notice))) { @@ -179,12 +218,20 @@ class RSSCloudPlugin extends Plugin * * @return boolean locality */ + function _isLocal($notice) { return ($notice->is_local == Notice::LOCAL_PUBLIC || $notice->is_local == Notice::LOCAL_NONPUBLIC); } + /** + * Create the rsscloud_subscription table if it's not + * already in the DB + * + * @return boolean hook return + */ + function onCheckSchema() { $schema = Schema::get(); $schema->ensureTable('rsscloud_subscription', @@ -205,6 +252,16 @@ class RSSCloudPlugin extends Plugin return true; } + /** + * Add RSSCloudQueueHandler to the list of valid daemons to + * start + * + * @param array $daemons the list of daemons to run + * + * @return boolean hook return + * + */ + function onGetValidDaemons($daemons) { array_push($daemons, INSTALLDIR . diff --git a/plugins/RSSCloud/RSSCloudRequestNotify.php b/plugins/RSSCloud/RSSCloudRequestNotify.php index 36959755a..4703ecd10 100644 --- a/plugins/RSSCloud/RSSCloudRequestNotify.php +++ b/plugins/RSSCloud/RSSCloudRequestNotify.php @@ -32,6 +32,16 @@ if (!defined('STATUSNET')) { exit(1); } +/** + * Action class to handle RSSCloud notification (subscription) requests + * + * @category Plugin + * @package StatusNet + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + **/ + class RSSCloudRequestNotifyAction extends Action { /** @@ -41,6 +51,7 @@ class RSSCloudRequestNotifyAction extends Action * * @return boolean false if user doesn't exist */ + function prepare($args) { parent::prepare($args); @@ -62,6 +73,18 @@ class RSSCloudRequestNotifyAction extends Action return true; } + /** + * Handle the request + * + * Checks for all the required parameters for a subscription, + * validates that the feed being subscribed to is real, and then + * saves the subsctiption. + * + * @param array $args $_REQUEST data (unused) + * + * @return void + */ + function handle($args) { parent::handle($args); @@ -137,6 +160,15 @@ class RSSCloudRequestNotifyAction extends Action $this->showResult(true, $msg); } + /** + * Validate that the requested feed is one we serve + * up via RSSCloud. + * + * @param string $feed the feed in question + * + * @return void + */ + function validateFeed($feed) { $user = $this->userFromFeed($feed); @@ -148,6 +180,13 @@ class RSSCloudRequestNotifyAction extends Action return true; } + /** + * Pull all of the urls (url1, url2, url3...urlN) that + * the subscriber wants to subscribe to. + * + * @return array $feeds the list of feeds + */ + function getFeeds() { $feeds = array(); @@ -161,6 +200,15 @@ class RSSCloudRequestNotifyAction extends Action return $feeds; } + /** + * Test that a notification handler is there and is reponding + * correctly. This is called before adding a subscription. + * + * @param string $feed the feed to verify + * + * @return boolean success result + */ + function testNotificationHandler($feed) { common_debug("RSSCloudPlugin - testNotificationHandler()"); @@ -185,6 +233,13 @@ class RSSCloudRequestNotifyAction extends Action } } + /** + * Build the URL for the notification handler based on the + * parameters passed in with the subscription request. + * + * @return string notification handler url + */ + function getNotifyUrl() { if (isset($this->domain)) { @@ -194,12 +249,20 @@ class RSSCloudRequestNotifyAction extends Action } } + /** + * Uses the nickname part of the subscribed feed URL to figure out + * whethere there's really a user with such a feed. Used to + * validate feeds before adding a subscription. + * + * @param string $feed the feed in question + * + * @return boolean success + */ + function userFromFeed($feed) { // We only do profile feeds - // XXX: Add cloud element to RSS 1.0 feeds? - $path = common_path('api/statuses/user_timeline/'); $valid = '%^' . $path . '(?.*)\.rss$%'; @@ -213,6 +276,14 @@ class RSSCloudRequestNotifyAction extends Action return false; } + /** + * Save an RSSCloud subscription + * + * @param $feed a valid profile feed + * + * @return boolean success result + */ + function saveSubscription($feed) { $user = $this->userFromFeed($feed); @@ -241,6 +312,16 @@ class RSSCloudRequestNotifyAction extends Action return true; } + /** + * Show an XML message indicating the subscription + * was successful or failed. + * + * @param boolean $success whether it was good or bad + * @param string $msg the message to output + * + * @return boolean success result + */ + function showResult($success, $msg) { $this->startXML(); -- cgit v1.2.3-54-g00ecf From 655dbcedb327c79c655b928ba36140519e3b6daf Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 14 Dec 2009 05:32:37 +0000 Subject: Comment out the LoggingAggregator business --- plugins/RSSCloud/RSSCloudPlugin.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'plugins/RSSCloud/RSSCloudPlugin.php') diff --git a/plugins/RSSCloud/RSSCloudPlugin.php b/plugins/RSSCloud/RSSCloudPlugin.php index 8c0bfa904..b1af9b59c 100644 --- a/plugins/RSSCloud/RSSCloudPlugin.php +++ b/plugins/RSSCloud/RSSCloudPlugin.php @@ -105,8 +105,9 @@ class RSSCloudPlugin extends Plugin { $m->connect('/main/rsscloud/request_notify', array('action' => 'RSSCloudRequestNotify')); - // XXX: This is just for end-to-end testing - $m->connect('/main/rsscloud/notify', array('action' => 'LoggingAggregator')); + // XXX: This is just for end-to-end testing. Uncomment if you need to pretend + // to be a cloud hub for some reason. + // $m->connect('/main/rsscloud/notify', array('action' => 'LoggingAggregator')); return true; } -- cgit v1.2.3-54-g00ecf From 3e6b80d3e99eee4fc916a714f34e7b95ad0455a6 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Mon, 14 Dec 2009 21:24:49 +0000 Subject: Some phpcs cleanup --- plugins/RSSCloud/LoggingAggregator.php | 5 +++-- plugins/RSSCloud/RSSCloudNotifier.php | 35 ++++++++++++++++++------------ plugins/RSSCloud/RSSCloudPlugin.php | 35 +++++++++++++++++------------- plugins/RSSCloud/RSSCloudRequestNotify.php | 24 ++++++++++---------- 4 files changed, 57 insertions(+), 42 deletions(-) (limited to 'plugins/RSSCloud/RSSCloudPlugin.php') diff --git a/plugins/RSSCloud/LoggingAggregator.php b/plugins/RSSCloud/LoggingAggregator.php index c81a987f7..e37eed16a 100644 --- a/plugins/RSSCloud/LoggingAggregator.php +++ b/plugins/RSSCloud/LoggingAggregator.php @@ -111,12 +111,13 @@ class LoggingAggregatorAction extends Action } header('Content-Type: text/xml'); - echo '' . "\n"; + Echo "\n"; } $this->ip = $_SERVER['REMOTE_ADDR']; - common_log(LOG_INFO, 'RSSCloud Logging Aggregator - ' . $this->ip . ' claims the feed at ' . + common_log(LOG_INFO, 'RSSCloud Logging Aggregator - ' . + $this->ip . ' claims the feed at ' . $this->url . ' has been updated.'); } diff --git a/plugins/RSSCloud/RSSCloudNotifier.php b/plugins/RSSCloud/RSSCloudNotifier.php index 485c4dcdf..d454691c8 100644 --- a/plugins/RSSCloud/RSSCloudNotifier.php +++ b/plugins/RSSCloud/RSSCloudNotifier.php @@ -41,16 +41,16 @@ if (!defined('STATUSNET')) { * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @link http://status.net/ **/ -class RSSCloudNotifier { - +class RSSCloudNotifier +{ const MAX_FAILURES = 3; /** * Send an HTTP GET to the notification handler with a * challenge string to see if it repsonds correctly. * - * @param String $endpoint URL of the notification handler - * @param String $feed the feed being subscribed to + * @param string $endpoint URL of the notification handler + * @param string $feed the feed being subscribed to * * @return boolean success */ @@ -61,10 +61,11 @@ class RSSCloudNotifier { $url = $endpoint . '?' . http_build_query($params); try { - $client = new HTTPClient(); + $client = new HTTPClient(); $response = $client->get($url); } catch (HTTP_Request2_Exception $e) { - common_log(LOG_INFO, 'RSSCloud plugin - failure testing notify handler ' . + common_log(LOG_INFO, + 'RSSCloud plugin - failure testing notify handler ' . $endpoint . ' - ' . $e->getMessage()); return false; } @@ -105,18 +106,19 @@ class RSSCloudNotifier { * HTTP POST a notification that a feed has been updated * ('ping the cloud'). * - * @param String $endpoint URL of the notification handler - * @param String $feed the feed being subscribed to + * @param String $endpoint URL of the notification handler + * @param String $feed the feed being subscribed to * * @return boolean success */ - function postUpdate($endpoint, $feed) { + function postUpdate($endpoint, $feed) + { $headers = array(); $postdata = array('url' => $feed); try { - $client = new HTTPClient(); + $client = new HTTPClient(); $response = $client->post($endpoint, $headers, $postdata); } catch (HTTP_Request2_Exception $e) { common_log(LOG_INFO, 'RSSCloud plugin - failure notifying ' . @@ -153,6 +155,7 @@ class RSSCloudNotifier { $profile->nickname . '.rss'; $cloudSub = new RSSCloudSubscription(); + $cloudSub->subscribed = $profile->id; if ($cloudSub->find()) { @@ -186,7 +189,8 @@ class RSSCloudNotifier { if ($failCnt == self::MAX_FAILURES) { common_log(LOG_INFO, - 'Deleting RSSCloud subcription (max failure count reached), profile: ' . + 'Deleting RSSCloud subcription ' . + '(max failure count reached), profile: ' . $cloudSub->subscribed . ' handler: ' . $cloudSub->url); @@ -209,7 +213,8 @@ class RSSCloudNotifier { } else { - common_debug('Updating failure count on RSSCloud subscription. ' . $failCnt); + common_debug('Updating failure count on RSSCloud subscription. ' . + $failCnt); $failCnt = $cloudSub->failures + 1; @@ -224,9 +229,11 @@ class RSSCloudNotifier { if (!$result) { common_log_db_error($cloudsub, 'UPDATE', __FILE__); - common_log(LOG_ERR, 'Could not update failure count on RSSCloud subscription'); + common_log(LOG_ERR, + 'Could not update failure ' . + 'count on RSSCloud subscription'); } - } + } } } diff --git a/plugins/RSSCloud/RSSCloudPlugin.php b/plugins/RSSCloud/RSSCloudPlugin.php index b1af9b59c..db2cdd74d 100644 --- a/plugins/RSSCloud/RSSCloudPlugin.php +++ b/plugins/RSSCloud/RSSCloudPlugin.php @@ -98,16 +98,20 @@ class RSSCloudPlugin extends Plugin * * Hook for RouterInitialized event. * + * @param Mapper &$m URL parser and mapper + * * @return boolean hook return */ function onRouterInitialized(&$m) { - $m->connect('/main/rsscloud/request_notify', array('action' => 'RSSCloudRequestNotify')); + $m->connect('/main/rsscloud/request_notify', + array('action' => 'RSSCloudRequestNotify')); // XXX: This is just for end-to-end testing. Uncomment if you need to pretend // to be a cloud hub for some reason. - // $m->connect('/main/rsscloud/notify', array('action' => 'LoggingAggregator')); + //$m->connect('/main/rsscloud/notify', + // array('action' => 'LoggingAggregator')); return true; } @@ -126,17 +130,18 @@ class RSSCloudPlugin extends Plugin { switch ($cls) { - case 'RSSCloudSubscription': - include_once(INSTALLDIR . '/plugins/RSSCloud/RSSCloudSubscription.php'); + case 'RSSCloudSubscription': + include_once INSTALLDIR . '/plugins/RSSCloud/RSSCloudSubscription.php'; return false; - case 'RSSCloudNotifier': - include_once(INSTALLDIR . '/plugins/RSSCloud/RSSCloudNotifier.php'); + case 'RSSCloudNotifier': + include_once INSTALLDIR . '/plugins/RSSCloud/RSSCloudNotifier.php'; return false; - case 'RSSCloudRequestNotifyAction': - case 'LoggingAggregatorAction': - include_once(INSTALLDIR . '/plugins/RSSCloud/' . mb_substr($cls, 0, -6) . '.php'); + case 'RSSCloudRequestNotifyAction': + case 'LoggingAggregatorAction': + include_once INSTALLDIR . '/plugins/RSSCloud/' . + mb_substr($cls, 0, -6) . '.php'; return false; - default: + default: return true; } } @@ -145,7 +150,7 @@ class RSSCloudPlugin extends Plugin * Add a element to the RSS feed (after the rss * element is started). * - * @param Action $action + * @param Action $action the ApiAction * * @return void */ @@ -215,7 +220,7 @@ class RSSCloudPlugin extends Plugin /** * Determine whether the notice was locally created * - * @param Notice $notice + * @param Notice $notice the notice in question * * @return boolean locality */ @@ -233,7 +238,8 @@ class RSSCloudPlugin extends Plugin * @return boolean hook return */ - function onCheckSchema() { + function onCheckSchema() + { $schema = Schema::get(); $schema->ensureTable('rsscloud_subscription', array(new ColumnDef('subscribed', 'integer', @@ -248,8 +254,7 @@ class RSSCloudPlugin extends Plugin null, false, null, 'CURRENT_TIMESTAMP', 'on update CURRENT_TIMESTAMP') - ) - ); + )); return true; } diff --git a/plugins/RSSCloud/RSSCloudRequestNotify.php b/plugins/RSSCloud/RSSCloudRequestNotify.php index 9643bf432..a648efff1 100644 --- a/plugins/RSSCloud/RSSCloudRequestNotify.php +++ b/plugins/RSSCloud/RSSCloudRequestNotify.php @@ -56,9 +56,9 @@ class RSSCloudRequestNotifyAction extends Action { parent::prepare($args); - $this->ip = $_SERVER['REMOTE_ADDR']; - $this->port = $this->arg('port'); - $this->path = $this->arg('path'); + $this->ip = $_SERVER['REMOTE_ADDR']; + $this->port = $this->arg('port'); + $this->path = $this->arg('path'); if ($this->path[0] != '/') { $this->path = '/' . $this->path; @@ -68,7 +68,7 @@ class RSSCloudRequestNotifyAction extends Action $this->procedure = $this->arg('notifyProcedure'); $this->domain = $this->arg('domain'); - $this->feeds = $this->getFeeds(); + $this->feeds = $this->getFeeds(); return true; } @@ -124,7 +124,8 @@ class RSSCloudRequestNotifyAction extends Action } if (empty($this->feeds)) { - $msg = 'You must provide at least one valid profile feed url (url1, url2, url3 ... urlN).'; + $msg = 'You must provide at least one valid profile feed url ' . + '(url1, url2, url3 ... urlN).'; $this->showResult(false, $msg); return; } @@ -195,7 +196,7 @@ class RSSCloudRequestNotifyAction extends Action { $feeds = array(); - while (list($key, $feed) = each ($this->args)) { + while (list($key, $feed) = each($this->args)) { if (preg_match('/^url\d*$/', $key)) { $feeds[] = $feed; } @@ -251,7 +252,7 @@ class RSSCloudRequestNotifyAction extends Action } else { return 'http://' . $this->ip . ':' . $this->port . $this->path; } - } + } /** * Uses the nickname part of the subscribed feed URL to figure out @@ -267,7 +268,7 @@ class RSSCloudRequestNotifyAction extends Action { // We only do profile feeds - $path = common_path('api/statuses/user_timeline/'); + $path = common_path('api/statuses/user_timeline/'); $valid = '%^' . $path . '(?.*)\.rss$%'; if (preg_match($valid, $feed, $matches)) { @@ -283,7 +284,7 @@ class RSSCloudRequestNotifyAction extends Action /** * Save an RSSCloud subscription * - * @param $feed a valid profile feed + * @param string $feed a valid profile feed * * @return boolean success result */ @@ -329,8 +330,9 @@ class RSSCloudRequestNotifyAction extends Action function showResult($success, $msg) { $this->startXML(); - $this->elementStart('notifyResult', array('success' => ($success) ? 'true' : 'false', - 'msg' => $msg)); + $this->elementStart('notifyResult', + array('success' => ($success) ? 'true' : 'false', + 'msg' => $msg)); $this->endXML(); } -- cgit v1.2.3-54-g00ecf From fd33865258644d5f41341e8efa239e2e4d064897 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 29 Dec 2009 03:52:02 +0000 Subject: Fix subscription path in link element --- plugins/RSSCloud/RSSCloudPlugin.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'plugins/RSSCloud/RSSCloudPlugin.php') diff --git a/plugins/RSSCloud/RSSCloudPlugin.php b/plugins/RSSCloud/RSSCloudPlugin.php index db2cdd74d..4b9812a47 100644 --- a/plugins/RSSCloud/RSSCloudPlugin.php +++ b/plugins/RSSCloud/RSSCloudPlugin.php @@ -70,7 +70,7 @@ class RSSCloudPlugin extends Plugin // set defaults - $local_server = parse_url(common_path('/main/rsscloud/request_notify')); + $local_server = parse_url(common_path('main/rsscloud/request_notify')); if (empty($this->domain)) { $this->domain = $local_server['host']; @@ -81,7 +81,7 @@ class RSSCloudPlugin extends Plugin } if (empty($this->path)) { - $this->path = '/main/rsscloud/request_notify'; + $this->path = $local_server['path']; } if (empty($this->funct)) { -- cgit v1.2.3-54-g00ecf From 20af83d316d8a89c3c9a34d17c252425433fc54f Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Fri, 8 Jan 2010 00:09:23 -0800 Subject: Add version info for Facebook, TwitterBridge and RSSCloud plugins --- plugins/Facebook/FacebookPlugin.php | 15 +++++++++++++++ plugins/RSSCloud/RSSCloudPlugin.php | 16 ++++++++++++++++ plugins/TwitterBridge/TwitterBridgePlugin.php | 15 +++++++++++++++ 3 files changed, 46 insertions(+) (limited to 'plugins/RSSCloud/RSSCloudPlugin.php') diff --git a/plugins/Facebook/FacebookPlugin.php b/plugins/Facebook/FacebookPlugin.php index 39b2ef287..de91bf24a 100644 --- a/plugins/Facebook/FacebookPlugin.php +++ b/plugins/Facebook/FacebookPlugin.php @@ -32,6 +32,7 @@ if (!defined('STATUSNET')) { } define("FACEBOOK_CONNECT_SERVICE", 3); +define('FACEBOOKPLUGIN_VERSION', '0.9'); require_once INSTALLDIR . '/plugins/Facebook/facebookutil.php'; @@ -554,4 +555,18 @@ class FacebookPlugin extends Plugin return true; } + function onPluginVersion(&$versions) + { + $versions[] = array('name' => 'Facebook', + 'version' => FACEBOOKPLUGIN_VERSION, + 'author' => 'Zach Copley', + 'homepage' => 'http://status.net/wiki/Plugin:Facebook', + 'rawdescription' => + _m('The Facebook plugin allows you to integrate ' . + 'your StatusNet instance with ' . + 'Facebook ' . + 'and Facebook Connect.')); + return true; + } + } diff --git a/plugins/RSSCloud/RSSCloudPlugin.php b/plugins/RSSCloud/RSSCloudPlugin.php index 4b9812a47..2de162628 100644 --- a/plugins/RSSCloud/RSSCloudPlugin.php +++ b/plugins/RSSCloud/RSSCloudPlugin.php @@ -31,6 +31,8 @@ if (!defined('STATUSNET')) { exit(1); } +define('RSSCLOUDPLUGIN_VERSION', '0.1'); + /** * Plugin class for adding RSSCloud capabilities to StatusNet * @@ -275,5 +277,19 @@ class RSSCloudPlugin extends Plugin return true; } + function onPluginVersion(&$versions) + { + $versions[] = array('name' => 'RSSCloud', + 'version' => RSSCLOUDPLUGIN_VERSION, + 'author' => 'Zach Copley', + 'homepage' => 'http://status.net/wiki/Plugin:RSSCloud', + 'rawdescription' => + _m('The RSSCloud plugin enables your StatusNet instance to publish ' . + 'real-time updates for profile RSS feeds using the ' . + 'RSSCloud protocol".')); + + return true; + } + } diff --git a/plugins/TwitterBridge/TwitterBridgePlugin.php b/plugins/TwitterBridge/TwitterBridgePlugin.php index de1181903..a87ee2894 100644 --- a/plugins/TwitterBridge/TwitterBridgePlugin.php +++ b/plugins/TwitterBridge/TwitterBridgePlugin.php @@ -31,6 +31,8 @@ if (!defined('STATUSNET')) { require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php'; +define('TWITTERBRIDGEPLUGIN_VERSION', '0.9'); + /** * Plugin for sending and importing Twitter statuses * @@ -189,4 +191,17 @@ class TwitterBridgePlugin extends Plugin return true; } + function onPluginVersion(&$versions) + { + $versions[] = array('name' => 'TwitterBridge', + 'version' => TWITTERBRIDGEPLUGIN_VERSION, + 'author' => 'Zach Copley', + 'homepage' => 'http://status.net/wiki/Plugin:TwitterBridge', + 'rawdescription' => + _m('The Twitter "bridge" plugin allows you to integrate ' . + 'your StatusNet instance with ' . + 'Twitter.')); + return true; + } + } -- cgit v1.2.3-54-g00ecf