X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=plugins%2FRealtime%2FRealtimePlugin.php;h=25fa921ffec9709047f8f555d84b13a040be9879;hb=1111187d845ecd34eba1c03473f6adbc08f6ca15;hp=108a6c3b60ff60b8e284f98f4d037ec9eeaa8701;hpb=31c1177970124cee31823cab3a11542c23b4126d;p=quix0rs-gnu-social.git diff --git a/plugins/Realtime/RealtimePlugin.php b/plugins/Realtime/RealtimePlugin.php index 108a6c3b60..25fa921ffe 100644 --- a/plugins/Realtime/RealtimePlugin.php +++ b/plugins/Realtime/RealtimePlugin.php @@ -22,14 +22,14 @@ * @category Plugin * @package StatusNet * @author Evan Prodromou + * @author Mikael Nordfeldth * @copyright 2009 StatusNet, Inc. + * @copyright 2014 Free Software Foundation, 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') && !defined('LACONICA')) { - exit(1); -} +if (!defined('GNUSOCIAL')) { exit(1); } /** * Superclass for plugin to do realtime updates @@ -37,6 +37,8 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { * Based on experience with the Comet and Meteor plugins, * this superclass extracts out some of the common functionality * + * Currently depends on Favorite plugin. + * * @category Plugin * @package StatusNet * @author Evan Prodromou @@ -51,7 +53,6 @@ class RealtimePlugin extends Plugin * When it's time to initialize the plugin, calculate and * pass the URLs we need. */ - function onInitializePlugin() { // FIXME: need to find a better way to pass this pattern in @@ -60,9 +61,39 @@ class RealtimePlugin extends Plugin return true; } + function onCheckSchema() + { + $schema = Schema::get(); + $schema->ensureTable('realtime_channel', Realtime_channel::schemaDef()); + return true; + } + + /** + * Hook for RouterInitialized event. + * + * @param URLMapper $m path-to-action mapper + * @return boolean hook return + */ + public function onRouterInitialized(URLMapper $m) + { + $m->connect('main/channel/:channelkey/keepalive', + array('action' => 'keepalivechannel'), + array('channelkey' => '[a-z0-9]{32}')); + $m->connect('main/channel/:channelkey/close', + array('action' => 'closechannel'), + array('channelkey' => '[a-z0-9]{32}')); + return true; + } + function onEndShowScripts($action) { - $timeline = $this->_getTimeline($action); + $channel = $this->_getChannel($action); + + if (empty($channel)) { + return true; + } + + $timeline = $this->_pathToChannel(array($channel->channel_key)); // If there's not a timeline on this page, // just return true @@ -97,43 +128,54 @@ class RealtimePlugin extends Plugin } else { $pluginPath = common_path('plugins/Realtime/'); - $realtimeUI = ' RealtimeUpdate.initActions("'.$url.'", "'.$timeline.'", "'. $pluginPath .'");'; + $keepalive = common_local_url('keepalivechannel', array('channelkey' => $channel->channel_key)); + $close = common_local_url('closechannel', array('channelkey' => $channel->channel_key)); + $realtimeUI = ' RealtimeUpdate.initActions('.json_encode($url).', '.json_encode($timeline).', '.json_encode($pluginPath).', '.json_encode($keepalive).', '.json_encode($close).'); '; } $script = ' $(document).ready(function() { '. $realtimeUI. - $this->_updateInitialize($timeline, $user_id). + $this->_updateInitialize($timeline, $user_id). '}); '; $action->inlineScript($script); return true; } - function onEndShowStatusNetStyles($action) + public function onEndShowStylesheets(Action $action) { - $action->cssLink(Plugin::staticPath('Realtime', 'realtimeupdate.css'), - null, - 'screen, projection, tv'); + $urlpath = self::staticPath(str_replace('Plugin','',__CLASS__), + 'css/realtimeupdate.css'); + $action->cssLink($urlpath, null, 'screen, projection, tv'); return true; } - function onHandleQueuedNotice($notice) + public function onHandleQueuedNotice(Notice $notice) { $paths = array(); // Add to the author's timeline - $user = User::staticGet('id', $notice->profile_id); + try { + $profile = $notice->getProfile(); + } catch (Exception $e) { + $this->log(LOG_ERR, $e->getMessage()); + return true; + } - if (!empty($user)) { - $paths[] = array('showstream', $user->nickname); + try { + $user = $profile->getUser(); + $paths[] = array('showstream', $user->nickname, null); + } catch (NoSuchUserException $e) { + // We really should handle the remote profile views too + $user = null; } // Add to the public timeline if ($notice->is_local == Notice::LOCAL_PUBLIC || - ($notice->is_local == Notice::REMOTE_OMB && !common_config('public', 'localonly'))) { - $paths[] = array('public'); + ($notice->is_local == Notice::REMOTE && !common_config('public', 'localonly'))) { + $paths[] = array('public', null, null); } // Add to the tags timeline @@ -142,7 +184,7 @@ class RealtimePlugin extends Plugin if (!empty($tags)) { foreach ($tags as $tag) { - $paths[] = array('tag', $tag); + $paths[] = array('tag', $tag, null); } } @@ -152,8 +194,8 @@ class RealtimePlugin extends Plugin $ni = $notice->whoGets(); foreach (array_keys($ni) as $user_id) { - $user = User::staticGet('id', $user_id); - $paths[] = array('all', $user->nickname); + $user = User::getKV('id', $user_id); + $paths[] = array('all', $user->nickname, null); } // Add to the replies timeline @@ -163,9 +205,9 @@ class RealtimePlugin extends Plugin if ($reply->find()) { while ($reply->fetch()) { - $user = User::staticGet('id', $reply->profile_id); + $user = User::getKV('id', $reply->profile_id); if (!empty($user)) { - $paths[] = array('replies', $user->nickname); + $paths[] = array('replies', $user->nickname, null); } } } @@ -178,8 +220,8 @@ class RealtimePlugin extends Plugin if ($gi->find()) { while ($gi->fetch()) { - $ug = User_group::staticGet('id', $gi->group_id); - $paths[] = array('showgroup', $ug->nickname); + $ug = User_group::getKV('id', $gi->group_id); + $paths[] = array('showgroup', $ug->nickname, null); } } @@ -189,9 +231,40 @@ class RealtimePlugin extends Plugin $this->_connect(); + // XXX: We should probably fan-out here and do a + // new queue item for each path + foreach ($paths as $path) { - $timeline = $this->_pathToChannel($path); - $this->_publish($timeline, $json); + + list($action, $arg1, $arg2) = $path; + + $channels = Realtime_channel::getAllChannels($action, $arg1, $arg2); + $this->log(LOG_INFO, sprintf(_("%d candidate channels for notice %d"), + count($channels), + $notice->id)); + + foreach ($channels as $channel) { + + // XXX: We should probably fan-out here and do a + // new queue item for each user/path combo + + if (is_null($channel->user_id)) { + $profile = null; + } else { + $profile = Profile::getKV('id', $channel->user_id); + } + if ($notice->inScope($profile)) { + $this->log(LOG_INFO, + sprintf(_("Delivering notice %d to channel (%s, %s, %s) for user '%s'"), + $notice->id, + $channel->action, + $channel->arg1, + $channel->arg2, + ($profile) ? ($profile->nickname) : "")); + $timeline = $this->_pathToChannel(array($channel->channel_key)); + $this->_publish($timeline, $json); + } + } } $this->_disconnect(); @@ -217,14 +290,19 @@ class RealtimePlugin extends Plugin // root url from page output $action->elementStart('address'); + + if (common_config('singleuser', 'enabled')) { + $user = User::singleUser(); + $url = common_local_url('showstream', array('nickname' => $user->nickname)); + } else { + $url = common_local_url('public'); + } + $action->element('a', array('class' => 'url', - 'href' => common_local_url('public')), + 'href' => $url), ''); - $action->elementEnd('address'); - if (common_logged_in()) { - $action->showNoticeForm(); - } + $action->elementEnd('address'); $action->showContentBlock(); $action->showScripts(); @@ -242,10 +320,10 @@ class RealtimePlugin extends Plugin $act = new ApiAction('/dev/null'); $arr = $act->twitterStatusArray($notice, true); - $arr['url'] = $notice->bestUrl(); + $arr['url'] = $notice->getUrl(); $arr['html'] = htmlspecialchars($notice->rendered); $arr['source'] = htmlspecialchars($arr['source']); - $arr['conversation_url'] = $this->getConversationUrl($notice); + $arr['conversation_url'] = $notice->getConversationUrl(); $profile = $notice->getProfile(); $arr['user']['profile_url'] = $profile->profileurl; @@ -253,16 +331,16 @@ class RealtimePlugin extends Plugin // Add needed repeat data if (!empty($notice->repeat_of)) { - $original = Notice::staticGet('id', $notice->repeat_of); - if (!empty($original)) { - $arr['retweeted_status']['url'] = $original->bestUrl(); + $original = Notice::getKV('id', $notice->repeat_of); + if ($original instanceof Notice) { + $arr['retweeted_status']['url'] = $original->getUrl(); $arr['retweeted_status']['html'] = htmlspecialchars($original->rendered); $arr['retweeted_status']['source'] = htmlspecialchars($original->source); $originalProfile = $original->getProfile(); $arr['retweeted_status']['user']['profile_url'] = $originalProfile->profileurl; - $arr['retweeted_status']['conversation_url'] = $this->getConversationUrl($original); + $arr['retweeted_status']['conversation_url'] = $original->getConversationUrl(); } - $original = null; + unset($original); } return $arr; @@ -288,42 +366,11 @@ class RealtimePlugin extends Plugin return $tags; } - function getConversationUrl($notice) - { - $convurl = null; - - if ($notice->hasConversation()) { - $conv = Conversation::staticGet( - 'id', - $notice->conversation - ); - $convurl = $conv->uri; - - if(empty($convurl)) { - $msg = sprintf( - "Couldn't find Conversation ID %d to make 'in context'" - . "link for Notice ID %d", - $notice->conversation, - $notice->id - ); - - common_log(LOG_WARNING, $msg); - } else { - $convurl .= '#notice-' . $notice->id; - } - } - - return $convurl; - } - function _getScripts() { - if (common_config('site', 'minify')) { - $js = 'realtimeupdate.min.js'; - } else { - $js = 'realtimeupdate.js'; - } - return array(Plugin::staticPath('Realtime', $js)); + $urlpath = self::staticPath(str_replace('Plugin','',__CLASS__), + 'js/realtimeupdate.js'); + return array($urlpath); } /** @@ -374,21 +421,40 @@ class RealtimePlugin extends Plugin return ''; } + function _getTimeline($action) { - $path = null; + $channel = $this->_getChannel($action); + if (empty($channel)) { + return null; + } + + return $this->_pathToChannel(array($channel->channel_key)); + } + + function _getChannel($action) + { $timeline = null; + $arg1 = null; + $arg2 = null; $action_name = $action->trimmed('action'); + // FIXME: lists + // FIXME: search (!) + // FIXME: profile + tag + switch ($action_name) { case 'public': - $path = array('public'); + // no arguments break; case 'tag': $tag = $action->trimmed('tag'); if (!empty($tag)) { - $path = array('tag', $tag); + $arg1 = $tag; + } else { + $this->log(LOG_NOTICE, "Unexpected 'tag' action without tag argument"); + return null; } break; case 'showstream': @@ -397,17 +463,31 @@ class RealtimePlugin extends Plugin case 'showgroup': $nickname = common_canonical_nickname($action->trimmed('nickname')); if (!empty($nickname)) { - $path = array($action_name, $nickname); + $arg1 = $nickname; + } else { + $this->log(LOG_NOTICE, "Unexpected $action_name action without nickname argument."); + return null; } break; default: - break; + return null; } - if (!empty($path)) { - $timeline = $this->_pathToChannel($path); - } + $user = common_current_user(); + + $user_id = (!empty($user)) ? $user->id : null; - return $timeline; + $channel = Realtime_channel::getChannel($user_id, + $action_name, + $arg1, + $arg2); + + return $channel; + } + + function onStartReadWriteTables(&$alwaysRW, &$rwdb) + { + $alwaysRW[] = 'realtime_channel'; + return true; } }