[REALTIME] Reviewed both the superclass and its dist plugins
This commit is contained in:
parent
aab3584f93
commit
3b01aa31d3
@ -1,35 +1,31 @@
|
|||||||
<?php
|
<?php
|
||||||
|
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||||
|
//
|
||||||
|
// GNU social 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.
|
||||||
|
//
|
||||||
|
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* StatusNet, the distributed open-source microblogging tool
|
|
||||||
*
|
|
||||||
* Superclass for plugins that do "real time" updates of timelines using Ajax
|
* Superclass for plugins that do "real time" updates of timelines using Ajax
|
||||||
*
|
*
|
||||||
* PHP version 5
|
|
||||||
*
|
|
||||||
* LICENCE: 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* @category Plugin
|
* @category Plugin
|
||||||
* @package StatusNet
|
* @package GNUsocial
|
||||||
* @author Evan Prodromou <evan@status.net>
|
* @author Evan Prodromou <evan@status.net>
|
||||||
* @author Mikael Nordfeldth <mmn@hethane.se>
|
* @author Mikael Nordfeldth <mmn@hethane.se>
|
||||||
* @copyright 2009 StatusNet, Inc.
|
* @copyright 2009-2019 Free Software Foundation, Inc http://www.fsf.org
|
||||||
* @copyright 2014 Free Software Foundation, Inc.
|
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||||
* @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('GNUSOCIAL')) { exit(1); }
|
defined('GNUSOCIAL') || die();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Superclass for plugin to do realtime updates
|
* Superclass for plugin to do realtime updates
|
||||||
@ -37,13 +33,12 @@ if (!defined('GNUSOCIAL')) { exit(1); }
|
|||||||
* Based on experience with the Comet and Meteor plugins,
|
* Based on experience with the Comet and Meteor plugins,
|
||||||
* this superclass extracts out some of the common functionality
|
* this superclass extracts out some of the common functionality
|
||||||
*
|
*
|
||||||
* Currently depends on Favorite plugin.
|
* Currently depends on the Favorite module.
|
||||||
*
|
*
|
||||||
* @category Plugin
|
* @category Plugin
|
||||||
* @package StatusNet
|
* @package GNUsocial
|
||||||
* @author Evan Prodromou <evan@status.net>
|
* @author Evan Prodromou <evan@status.net>
|
||||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||||
* @link http://status.net/
|
|
||||||
*/
|
*/
|
||||||
class RealtimePlugin extends Plugin
|
class RealtimePlugin extends Plugin
|
||||||
{
|
{
|
||||||
@ -53,15 +48,17 @@ class RealtimePlugin extends Plugin
|
|||||||
* When it's time to initialize the plugin, calculate and
|
* When it's time to initialize the plugin, calculate and
|
||||||
* pass the URLs we need.
|
* pass the URLs we need.
|
||||||
*/
|
*/
|
||||||
function onInitializePlugin()
|
public function onInitializePlugin()
|
||||||
{
|
{
|
||||||
// FIXME: need to find a better way to pass this pattern in
|
// FIXME: need to find a better way to pass this pattern in
|
||||||
$this->showurl = common_local_url('shownotice',
|
$this->showurl = common_local_url(
|
||||||
array('notice' => '0000000000'));
|
'shownotice',
|
||||||
|
['notice' => '0000000000']
|
||||||
|
);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function onCheckSchema()
|
public function onCheckSchema()
|
||||||
{
|
{
|
||||||
$schema = Schema::get();
|
$schema = Schema::get();
|
||||||
$schema->ensureTable('realtime_channel', Realtime_channel::schemaDef());
|
$schema->ensureTable('realtime_channel', Realtime_channel::schemaDef());
|
||||||
@ -72,20 +69,25 @@ class RealtimePlugin extends Plugin
|
|||||||
* Hook for RouterInitialized event.
|
* Hook for RouterInitialized event.
|
||||||
*
|
*
|
||||||
* @param URLMapper $m path-to-action mapper
|
* @param URLMapper $m path-to-action mapper
|
||||||
* @return boolean hook return
|
* @return bool hook return
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function onRouterInitialized(URLMapper $m)
|
public function onRouterInitialized(URLMapper $m)
|
||||||
{
|
{
|
||||||
$m->connect('main/channel/:channelkey/keepalive',
|
$m->connect(
|
||||||
|
'main/channel/:channelkey/keepalive',
|
||||||
['action' => 'keepalivechannel'],
|
['action' => 'keepalivechannel'],
|
||||||
['channelkey' => '[a-z0-9]{32}']);
|
['channelkey' => '[a-z0-9]{32}']
|
||||||
$m->connect('main/channel/:channelkey/close',
|
);
|
||||||
|
$m->connect(
|
||||||
|
'main/channel/:channelkey/close',
|
||||||
['action' => 'closechannel'],
|
['action' => 'closechannel'],
|
||||||
['channelkey' => '[a-z0-9]{32}']);
|
['channelkey' => '[a-z0-9]{32}']
|
||||||
|
);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function onEndShowScripts($action)
|
public function onEndShowScripts(Action $action)
|
||||||
{
|
{
|
||||||
$channel = $this->_getChannel($action);
|
$channel = $this->_getChannel($action);
|
||||||
|
|
||||||
@ -93,7 +95,7 @@ class RealtimePlugin extends Plugin
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$timeline = $this->_pathToChannel(array($channel->channel_key));
|
$timeline = $this->_pathToChannel([$channel->channel_key]);
|
||||||
|
|
||||||
// If there's not a timeline on this page,
|
// If there's not a timeline on this page,
|
||||||
// just return true
|
// just return true
|
||||||
@ -125,11 +127,10 @@ class RealtimePlugin extends Plugin
|
|||||||
|
|
||||||
if ($action->boolean('realtime')) {
|
if ($action->boolean('realtime')) {
|
||||||
$realtimeUI = ' RealtimeUpdate.initPopupWindow();';
|
$realtimeUI = ' RealtimeUpdate.initPopupWindow();';
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
$pluginPath = common_path('plugins/Realtime/');
|
$pluginPath = common_path('plugins/Realtime/');
|
||||||
$keepalive = common_local_url('keepalivechannel', array('channelkey' => $channel->channel_key));
|
$keepalive = common_local_url('keepalivechannel', ['channelkey' => $channel->channel_key]);
|
||||||
$close = common_local_url('closechannel', array('channelkey' => $channel->channel_key));
|
$close = common_local_url('closechannel', ['channelkey' => $channel->channel_key]);
|
||||||
$realtimeUI = ' RealtimeUpdate.initActions('.json_encode($url).', '.json_encode($timeline).', '.json_encode($pluginPath).', '.json_encode($keepalive).', '.json_encode($close).'); ';
|
$realtimeUI = ' RealtimeUpdate.initActions('.json_encode($url).', '.json_encode($timeline).', '.json_encode($pluginPath).', '.json_encode($keepalive).', '.json_encode($close).'); ';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,15 +145,17 @@ class RealtimePlugin extends Plugin
|
|||||||
|
|
||||||
public function onEndShowStylesheets(Action $action)
|
public function onEndShowStylesheets(Action $action)
|
||||||
{
|
{
|
||||||
$urlpath = self::staticPath(str_replace('Plugin','',__CLASS__),
|
$urlpath = self::staticPath(
|
||||||
'css/realtimeupdate.css');
|
str_replace('Plugin', '', __CLASS__),
|
||||||
|
'css/realtimeupdate.css'
|
||||||
|
);
|
||||||
$action->cssLink($urlpath, null, 'screen, projection, tv');
|
$action->cssLink($urlpath, null, 'screen, projection, tv');
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function onHandleQueuedNotice(Notice $notice)
|
public function onHandleQueuedNotice(Notice $notice)
|
||||||
{
|
{
|
||||||
$paths = array();
|
$paths = [];
|
||||||
|
|
||||||
// Add to the author's timeline
|
// Add to the author's timeline
|
||||||
|
|
||||||
@ -165,7 +168,7 @@ class RealtimePlugin extends Plugin
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
$user = $profile->getUser();
|
$user = $profile->getUser();
|
||||||
$paths[] = array('showstream', $user->nickname, null);
|
$paths[] = ['showstream', $user->nickname, null];
|
||||||
} catch (NoSuchUserException $e) {
|
} catch (NoSuchUserException $e) {
|
||||||
// We really should handle the remote profile views too
|
// We really should handle the remote profile views too
|
||||||
$user = null;
|
$user = null;
|
||||||
@ -176,7 +179,7 @@ class RealtimePlugin extends Plugin
|
|||||||
$is_local = intval($notice->is_local);
|
$is_local = intval($notice->is_local);
|
||||||
if ($is_local === Notice::LOCAL_PUBLIC ||
|
if ($is_local === Notice::LOCAL_PUBLIC ||
|
||||||
($is_local === Notice::REMOTE && !common_config('public', 'localonly'))) {
|
($is_local === Notice::REMOTE && !common_config('public', 'localonly'))) {
|
||||||
$paths[] = array('public', null, null);
|
$paths[] = ['public', null, null];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add to the tags timeline
|
// Add to the tags timeline
|
||||||
@ -185,7 +188,7 @@ class RealtimePlugin extends Plugin
|
|||||||
|
|
||||||
if (!empty($tags)) {
|
if (!empty($tags)) {
|
||||||
foreach ($tags as $tag) {
|
foreach ($tags as $tag) {
|
||||||
$paths[] = array('tag', $tag, null);
|
$paths[] = ['tag', $tag, null];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,7 +199,7 @@ class RealtimePlugin extends Plugin
|
|||||||
|
|
||||||
foreach (array_keys($ni) as $user_id) {
|
foreach (array_keys($ni) as $user_id) {
|
||||||
$user = User::getKV('id', $user_id);
|
$user = User::getKV('id', $user_id);
|
||||||
$paths[] = array('all', $user->nickname, null);
|
$paths[] = ['all', $user->getNickname(), null];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add to the replies timeline
|
// Add to the replies timeline
|
||||||
@ -208,7 +211,7 @@ class RealtimePlugin extends Plugin
|
|||||||
while ($reply->fetch()) {
|
while ($reply->fetch()) {
|
||||||
$user = User::getKV('id', $reply->profile_id);
|
$user = User::getKV('id', $reply->profile_id);
|
||||||
if (!empty($user)) {
|
if (!empty($user)) {
|
||||||
$paths[] = array('replies', $user->nickname, null);
|
$paths[] = ['replies', $user->getNickname(), null];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -222,12 +225,11 @@ class RealtimePlugin extends Plugin
|
|||||||
if ($gi->find()) {
|
if ($gi->find()) {
|
||||||
while ($gi->fetch()) {
|
while ($gi->fetch()) {
|
||||||
$ug = User_group::getKV('id', $gi->group_id);
|
$ug = User_group::getKV('id', $gi->group_id);
|
||||||
$paths[] = array('showgroup', $ug->nickname, null);
|
$paths[] = ['showgroup', $ug->getNickname(), null];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($paths) > 0) {
|
if (count($paths) > 0) {
|
||||||
|
|
||||||
$json = $this->noticeAsJson($notice);
|
$json = $this->noticeAsJson($notice);
|
||||||
|
|
||||||
$this->_connect();
|
$this->_connect();
|
||||||
@ -236,13 +238,14 @@ class RealtimePlugin extends Plugin
|
|||||||
// new queue item for each path
|
// new queue item for each path
|
||||||
|
|
||||||
foreach ($paths as $path) {
|
foreach ($paths as $path) {
|
||||||
|
|
||||||
list($action, $arg1, $arg2) = $path;
|
list($action, $arg1, $arg2) = $path;
|
||||||
|
|
||||||
$channels = Realtime_channel::getAllChannels($action, $arg1, $arg2);
|
$channels = Realtime_channel::getAllChannels($action, $arg1, $arg2);
|
||||||
$this->log(LOG_INFO, sprintf(_("%d candidate channels for notice %d"),
|
$this->log(LOG_INFO, sprintf(
|
||||||
|
_("%d candidate channels for notice %d"),
|
||||||
count($channels),
|
count($channels),
|
||||||
$notice->id));
|
$notice->id
|
||||||
|
));
|
||||||
|
|
||||||
foreach ($channels as $channel) {
|
foreach ($channels as $channel) {
|
||||||
|
|
||||||
@ -255,14 +258,18 @@ class RealtimePlugin extends Plugin
|
|||||||
$profile = Profile::getKV('id', $channel->user_id);
|
$profile = Profile::getKV('id', $channel->user_id);
|
||||||
}
|
}
|
||||||
if ($notice->inScope($profile)) {
|
if ($notice->inScope($profile)) {
|
||||||
$this->log(LOG_INFO,
|
$this->log(
|
||||||
sprintf(_("Delivering notice %d to channel (%s, %s, %s) for user '%s'"),
|
LOG_INFO,
|
||||||
|
sprintf(
|
||||||
|
_m("Delivering notice %d to channel (%s, %s, %s) for user '%s'"),
|
||||||
$notice->id,
|
$notice->id,
|
||||||
$channel->action,
|
$channel->action,
|
||||||
$channel->arg1,
|
$channel->arg1,
|
||||||
$channel->arg2,
|
$channel->arg2,
|
||||||
($profile) ? ($profile->nickname) : "<public>"));
|
($profile ? $profile->getNickname() : '<public>')
|
||||||
$timeline = $this->_pathToChannel(array($channel->channel_key));
|
)
|
||||||
|
);
|
||||||
|
$timeline = $this->_pathToChannel([$channel->channel_key]);
|
||||||
$this->_publish($timeline, $json);
|
$this->_publish($timeline, $json);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -274,18 +281,23 @@ class RealtimePlugin extends Plugin
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function onStartShowBody($action)
|
public function onStartShowBody(Action $action)
|
||||||
{
|
{
|
||||||
$realtime = $action->boolean('realtime');
|
$realtime = $action->boolean('realtime');
|
||||||
if (!$realtime) {
|
if (!$realtime) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$action->elementStart('body',
|
$action->elementStart(
|
||||||
(common_current_user()) ? array('id' => $action->trimmed('action'),
|
'body',
|
||||||
'class' => 'user_in realtime-popup')
|
(common_current_user() ? [
|
||||||
: array('id' => $action->trimmed('action'),
|
'id' => $action->trimmed('action'),
|
||||||
'class'=> 'realtime-popup'));
|
'class' => 'user_in realtime-popup',
|
||||||
|
] : [
|
||||||
|
'id' => $action->trimmed('action'),
|
||||||
|
'class'=> 'realtime-popup',
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
// XXX hack to deal with JS that tries to get the
|
// XXX hack to deal with JS that tries to get the
|
||||||
// root url from page output
|
// root url from page output
|
||||||
@ -294,14 +306,17 @@ class RealtimePlugin extends Plugin
|
|||||||
|
|
||||||
if (common_config('singleuser', 'enabled')) {
|
if (common_config('singleuser', 'enabled')) {
|
||||||
$user = User::singleUser();
|
$user = User::singleUser();
|
||||||
$url = common_local_url('showstream', array('nickname' => $user->nickname));
|
$url = common_local_url('showstream', ['nickname' => $user->nickname]);
|
||||||
} else {
|
} else {
|
||||||
$url = common_local_url('public');
|
$url = common_local_url('public');
|
||||||
}
|
}
|
||||||
|
|
||||||
$action->element('a', array('class' => 'url',
|
$action->element(
|
||||||
'href' => $url),
|
'a',
|
||||||
'');
|
['class' => 'url',
|
||||||
|
'href' => $url],
|
||||||
|
''
|
||||||
|
);
|
||||||
|
|
||||||
$action->elementEnd('address');
|
$action->elementEnd('address');
|
||||||
|
|
||||||
@ -311,7 +326,7 @@ class RealtimePlugin extends Plugin
|
|||||||
return false; // No default processing
|
return false; // No default processing
|
||||||
}
|
}
|
||||||
|
|
||||||
function noticeAsJson(Notice $notice)
|
public function noticeAsJson(Notice $notice)
|
||||||
{
|
{
|
||||||
// FIXME: this code should be abstracted to a neutral third
|
// FIXME: this code should be abstracted to a neutral third
|
||||||
// party, like Notice::asJson(). I'm not sure of the ethics
|
// party, like Notice::asJson(). I'm not sure of the ethics
|
||||||
@ -347,7 +362,7 @@ class RealtimePlugin extends Plugin
|
|||||||
return $arr;
|
return $arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNoticeTags(Notice $notice)
|
public function getNoticeTags(Notice $notice)
|
||||||
{
|
{
|
||||||
$tags = null;
|
$tags = null;
|
||||||
|
|
||||||
@ -355,7 +370,7 @@ class RealtimePlugin extends Plugin
|
|||||||
$nt->notice_id = $notice->id;
|
$nt->notice_id = $notice->id;
|
||||||
|
|
||||||
if ($nt->find()) {
|
if ($nt->find()) {
|
||||||
$tags = array();
|
$tags = [];
|
||||||
while ($nt->fetch()) {
|
while ($nt->fetch()) {
|
||||||
$tags[] = $nt->tag;
|
$tags[] = $nt->tag;
|
||||||
}
|
}
|
||||||
@ -367,11 +382,13 @@ class RealtimePlugin extends Plugin
|
|||||||
return $tags;
|
return $tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _getScripts()
|
public function _getScripts(): array
|
||||||
{
|
{
|
||||||
$urlpath = self::staticPath(str_replace('Plugin','',__CLASS__),
|
$urlpath = self::staticPath(
|
||||||
'js/realtimeupdate.js');
|
str_replace('Plugin', '', __CLASS__),
|
||||||
return array($urlpath);
|
'js/realtimeupdate.js'
|
||||||
|
);
|
||||||
|
return [$urlpath];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -380,9 +397,10 @@ class RealtimePlugin extends Plugin
|
|||||||
* @param Action $action
|
* @param Action $action
|
||||||
* @param array $messages
|
* @param array $messages
|
||||||
*
|
*
|
||||||
* @return boolean hook return value
|
* @return bool hook return value
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
function onEndScriptMessages($action, &$messages)
|
public function onEndScriptMessages(Action $action, array &$messages)
|
||||||
{
|
{
|
||||||
// TRANS: Text label for realtime view "play" button, usually replaced by an icon.
|
// TRANS: Text label for realtime view "play" button, usually replaced by an icon.
|
||||||
$messages['realtime_play'] = _m('BUTTON', 'Play');
|
$messages['realtime_play'] = _m('BUTTON', 'Play');
|
||||||
@ -400,40 +418,40 @@ class RealtimePlugin extends Plugin
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _updateInitialize($timeline, $user_id)
|
public function _updateInitialize($timeline, int $user_id)
|
||||||
{
|
{
|
||||||
return "RealtimeUpdate.init($user_id, \"$this->showurl\"); ";
|
return "RealtimeUpdate.init($user_id, \"$this->showurl\"); ";
|
||||||
}
|
}
|
||||||
|
|
||||||
function _connect()
|
public function _connect()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
function _publish($timeline, $json)
|
public function _publish($timeline, $json)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
function _disconnect()
|
public function _disconnect()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
function _pathToChannel($path)
|
public function _pathToChannel(array $path): string
|
||||||
{
|
{
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function _getTimeline($action)
|
public function _getTimeline(Action $action)
|
||||||
{
|
{
|
||||||
$channel = $this->_getChannel($action);
|
$channel = $this->_getChannel($action);
|
||||||
if (empty($channel)) {
|
if (empty($channel)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->_pathToChannel(array($channel->channel_key));
|
return $this->_pathToChannel([$channel->channel_key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function _getChannel($action)
|
public function _getChannel(Action $action)
|
||||||
{
|
{
|
||||||
$timeline = null;
|
$timeline = null;
|
||||||
$arg1 = null;
|
$arg1 = null;
|
||||||
@ -478,15 +496,17 @@ class RealtimePlugin extends Plugin
|
|||||||
|
|
||||||
$user_id = (!empty($user)) ? $user->id : null;
|
$user_id = (!empty($user)) ? $user->id : null;
|
||||||
|
|
||||||
$channel = Realtime_channel::getChannel($user_id,
|
$channel = Realtime_channel::getChannel(
|
||||||
|
$user_id,
|
||||||
$action_name,
|
$action_name,
|
||||||
$arg1,
|
$arg1,
|
||||||
$arg2);
|
$arg2
|
||||||
|
);
|
||||||
|
|
||||||
return $channel;
|
return $channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
function onStartReadWriteTables(&$alwaysRW, &$rwdb)
|
public function onStartReadWriteTables(&$alwaysRW, &$rwdb)
|
||||||
{
|
{
|
||||||
$alwaysRW[] = 'realtime_channel';
|
$alwaysRW[] = 'realtime_channel';
|
||||||
return true;
|
return true;
|
@ -1,48 +1,38 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||||
* StatusNet - the distributed open-source microblogging tool
|
//
|
||||||
* Copyright (C) 2011, StatusNet, Inc.
|
// GNU social is free software: you can redistribute it and/or modify
|
||||||
*
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
* action to close a channel
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
*
|
// (at your option) any later version.
|
||||||
* PHP version 5
|
//
|
||||||
*
|
// GNU social is distributed in the hope that it will be useful,
|
||||||
* This program is free software: you can redistribute it and/or modify
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
// GNU Affero General Public License for more details.
|
||||||
* (at your option) any later version.
|
//
|
||||||
*
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
* This program is distributed in the hope that it will be useful,
|
// along with GNU social. If not, see <http://www.gnu.org/licenses/>.
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* @category Realtime
|
|
||||||
* @package StatusNet
|
|
||||||
* @author Evan Prodromou <evan@status.net>
|
|
||||||
* @copyright 2011 StatusNet, Inc.
|
|
||||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
|
||||||
* @link http://status.net/
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!defined('STATUSNET')) {
|
|
||||||
// This check helps protect against security problems;
|
|
||||||
// your code file can't be executed directly from the web.
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action to close a channel
|
* Action to close a channel
|
||||||
*
|
*
|
||||||
* @category Realtime
|
* @category Realtime
|
||||||
* @package StatusNet
|
* @package GNUsocial
|
||||||
* @author Evan Prodromou <evan@status.net>
|
* @author Evan Prodromou <evan@status.net>
|
||||||
* @copyright 2011 StatusNet, Inc.
|
* @copyright 2011-2019 Free Software Foundation, Inc http://www.fsf.org
|
||||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||||
* @link http://status.net/
|
*/
|
||||||
|
|
||||||
|
defined('GNUSOCIAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action to close a channel
|
||||||
|
*
|
||||||
|
* @category Realtime
|
||||||
|
* @package GNUsocial
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||||
*/
|
*/
|
||||||
class ClosechannelAction extends Action
|
class ClosechannelAction extends Action
|
||||||
{
|
{
|
||||||
@ -57,7 +47,7 @@ class ClosechannelAction extends Action
|
|||||||
* @return boolean true
|
* @return boolean true
|
||||||
* @throws ClientException
|
* @throws ClientException
|
||||||
*/
|
*/
|
||||||
function prepare(array $args = [])
|
public function prepare(array $args = [])
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
@ -88,7 +78,7 @@ class ClosechannelAction extends Action
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function handle()
|
public function handle(): void
|
||||||
{
|
{
|
||||||
$this->channel->decrement();
|
$this->channel->decrement();
|
||||||
|
|
||||||
@ -104,9 +94,9 @@ class ClosechannelAction extends Action
|
|||||||
*
|
*
|
||||||
* @param array $args other arguments
|
* @param array $args other arguments
|
||||||
*
|
*
|
||||||
* @return boolean is read only action?
|
* @return bool is read only action?
|
||||||
*/
|
*/
|
||||||
function isReadOnly($args)
|
public function isReadOnly($args): bool
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
@ -54,10 +54,10 @@ class KeepalivechannelAction extends Action
|
|||||||
*
|
*
|
||||||
* @param array $args misc. arguments
|
* @param array $args misc. arguments
|
||||||
*
|
*
|
||||||
* @return boolean true
|
* @return bool true
|
||||||
* @throws ClientException
|
* @throws ClientException
|
||||||
*/
|
*/
|
||||||
function prepare(array $args = [])
|
public function prepare(array $args = []): bool
|
||||||
{
|
{
|
||||||
parent::prepare($args);
|
parent::prepare($args);
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ class KeepalivechannelAction extends Action
|
|||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
function handle()
|
public function handle(): void
|
||||||
{
|
{
|
||||||
$this->channel->touch();
|
$this->channel->touch();
|
||||||
|
|
||||||
@ -104,9 +104,9 @@ class KeepalivechannelAction extends Action
|
|||||||
*
|
*
|
||||||
* @param array $args other arguments
|
* @param array $args other arguments
|
||||||
*
|
*
|
||||||
* @return boolean is read only action?
|
* @return bool is read only action?
|
||||||
*/
|
*/
|
||||||
function isReadOnly($args)
|
public function isReadOnly($args): bool
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
@ -23,7 +23,7 @@
|
|||||||
* @category Realtime
|
* @category Realtime
|
||||||
* @package GNUsocial
|
* @package GNUsocial
|
||||||
* @author Evan Prodromou <evan@status.net>
|
* @author Evan Prodromou <evan@status.net>
|
||||||
* @copyright 2011 StatusNet, Inc.
|
* @copyright 2011-2019 Free Software Foundation, Inc http://www.fsf.org
|
||||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -32,7 +32,6 @@ defined('GNUSOCIAL') || die();
|
|||||||
/**
|
/**
|
||||||
* A channel for real-time browser data
|
* A channel for real-time browser data
|
||||||
*
|
*
|
||||||
* @copyright 2011 StatusNet, Inc.
|
|
||||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||||
*
|
*
|
||||||
* @see DB_DataObject
|
* @see DB_DataObject
|
||||||
@ -57,52 +56,52 @@ class Realtime_channel extends Managed_DataObject
|
|||||||
*/
|
*/
|
||||||
public static function schemaDef()
|
public static function schemaDef()
|
||||||
{
|
{
|
||||||
return array(
|
return [
|
||||||
'description' => 'A channel of realtime notice data',
|
'description' => 'A channel of realtime notice data',
|
||||||
'fields' => array(
|
'fields' => [
|
||||||
'user_id' => array('type' => 'int',
|
'user_id' => ['type' => 'int',
|
||||||
'not null' => false,
|
'not null' => false,
|
||||||
'description' => 'user viewing page; can be null'),
|
'description' => 'user viewing page; can be null'],
|
||||||
'action' => array('type' => 'varchar',
|
'action' => ['type' => 'varchar',
|
||||||
'length' => 191,
|
'length' => 191,
|
||||||
'not null' => true,
|
'not null' => true,
|
||||||
'description' => 'page being viewed'),
|
'description' => 'page being viewed'],
|
||||||
'arg1' => array('type' => 'varchar',
|
'arg1' => ['type' => 'varchar',
|
||||||
'length' => 191,
|
'length' => 191,
|
||||||
'not null' => false,
|
'not null' => false,
|
||||||
'description' => 'page argument, like username or tag'),
|
'description' => 'page argument, like username or tag'],
|
||||||
'arg2' => array('type' => 'varchar',
|
'arg2' => ['type' => 'varchar',
|
||||||
'length' => 191,
|
'length' => 191,
|
||||||
'not null' => false,
|
'not null' => false,
|
||||||
'description' => 'second page argument, like tag for showstream'),
|
'description' => 'second page argument, like tag for showstream'],
|
||||||
'channel_key' => array('type' => 'varchar',
|
'channel_key' => ['type' => 'varchar',
|
||||||
'length' => 32,
|
'length' => 32,
|
||||||
'not null' => true,
|
'not null' => true,
|
||||||
'description' => 'shared secret key for this channel'),
|
'description' => 'shared secret key for this channel'],
|
||||||
'audience' => array('type' => 'int',
|
'audience' => ['type' => 'int',
|
||||||
'not null' => true,
|
'not null' => true,
|
||||||
'default' => 0,
|
'default' => 0,
|
||||||
'description' => 'reference count'),
|
'description' => 'reference count'],
|
||||||
'created' => array('type' => 'datetime',
|
'created' => ['type' => 'datetime',
|
||||||
'not null' => true,
|
'not null' => true,
|
||||||
'description' => 'date this record was created'),
|
'description' => 'date this record was created'],
|
||||||
'modified' => array('type' => 'datetime',
|
'modified' => ['type' => 'datetime',
|
||||||
'not null' => true,
|
'not null' => true,
|
||||||
'description' => 'date this record was modified'),
|
'description' => 'date this record was modified'],
|
||||||
),
|
],
|
||||||
'primary key' => array('channel_key'),
|
'primary key' => ['channel_key'],
|
||||||
'unique keys' => array('realtime_channel_user_page_idx' => array('user_id', 'action', 'arg1', 'arg2')),
|
'unique keys' => ['realtime_channel_user_page_idx' => ['user_id', 'action', 'arg1', 'arg2']],
|
||||||
'foreign keys' => array(
|
'foreign keys' => [
|
||||||
'realtime_channel_user_id_fkey' => array('user', array('user_id' => 'id')),
|
'realtime_channel_user_id_fkey' => ['user', ['user_id' => 'id']],
|
||||||
),
|
],
|
||||||
'indexes' => array(
|
'indexes' => [
|
||||||
'realtime_channel_modified_idx' => array('modified'),
|
'realtime_channel_modified_idx' => ['modified'],
|
||||||
'realtime_channel_page_idx' => array('action', 'arg1', 'arg2')
|
'realtime_channel_page_idx' => ['action', 'arg1', 'arg2']
|
||||||
),
|
],
|
||||||
);
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function saveNew($user_id, $action, $arg1, $arg2)
|
public static function saveNew(int $user_id, Action $action, $arg1, $arg2): Realtime_channel
|
||||||
{
|
{
|
||||||
$channel = new Realtime_channel();
|
$channel = new Realtime_channel();
|
||||||
|
|
||||||
@ -122,7 +121,7 @@ class Realtime_channel extends Managed_DataObject
|
|||||||
return $channel;
|
return $channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getChannel($user_id, $action, $arg1, $arg2)
|
public static function getChannel(int $user_id, Action $action, $arg1, $arg2): Realtime_channel
|
||||||
{
|
{
|
||||||
$channel = self::fetchChannel($user_id, $action, $arg1, $arg2);
|
$channel = self::fetchChannel($user_id, $action, $arg1, $arg2);
|
||||||
|
|
||||||
@ -143,7 +142,7 @@ class Realtime_channel extends Managed_DataObject
|
|||||||
return $channel;
|
return $channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getAllChannels($action, $arg1, $arg2)
|
public static function getAllChannels(Action $action, $arg1, $arg2): array
|
||||||
{
|
{
|
||||||
$channel = new Realtime_channel();
|
$channel = new Realtime_channel();
|
||||||
|
|
||||||
@ -172,7 +171,7 @@ class Realtime_channel extends Managed_DataObject
|
|||||||
return $channels;
|
return $channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function fetchChannel($user_id, $action, $arg1, $arg2)
|
public static function fetchChannel(int $user_id, Action $action, $arg1, $arg2): ?Realtime_channel
|
||||||
{
|
{
|
||||||
$channel = new Realtime_channel();
|
$channel = new Realtime_channel();
|
||||||
|
|
||||||
@ -204,7 +203,7 @@ class Realtime_channel extends Managed_DataObject
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function increment()
|
public function increment(): void
|
||||||
{
|
{
|
||||||
// XXX: race
|
// XXX: race
|
||||||
$orig = clone($this);
|
$orig = clone($this);
|
||||||
@ -213,7 +212,7 @@ class Realtime_channel extends Managed_DataObject
|
|||||||
$this->update($orig);
|
$this->update($orig);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function touch()
|
public function touch(): void
|
||||||
{
|
{
|
||||||
// XXX: race
|
// XXX: race
|
||||||
$orig = clone($this);
|
$orig = clone($this);
|
||||||
@ -221,7 +220,7 @@ class Realtime_channel extends Managed_DataObject
|
|||||||
$this->update($orig);
|
$this->update($orig);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function decrement()
|
public function decrement(): void
|
||||||
{
|
{
|
||||||
// XXX: race
|
// XXX: race
|
||||||
if ($this->audience == 1) {
|
if ($this->audience == 1) {
|
@ -20,7 +20,7 @@
|
|||||||
*
|
*
|
||||||
* @package Realtime
|
* @package Realtime
|
||||||
* @author Mikael Nordfeldth <mmn@hethane.se>
|
* @author Mikael Nordfeldth <mmn@hethane.se>
|
||||||
* @copyright 2011 StatusNet, Inc.
|
* @copyright 2011-2019 Free Software Foundation, Inc http://www.fsf.org
|
||||||
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ define('INSTALLDIR', dirname(__DIR__, 3));
|
|||||||
define('PUBLICDIR', INSTALLDIR . DIRECTORY_SEPARATOR . 'public');
|
define('PUBLICDIR', INSTALLDIR . DIRECTORY_SEPARATOR . 'public');
|
||||||
|
|
||||||
$shortoptions = 'u';
|
$shortoptions = 'u';
|
||||||
$longoptions = array('universe');
|
$longoptions = ['universe'];
|
||||||
|
|
||||||
$helptext = <<<END_OF_CLEANUPCHANNELS_HELP
|
$helptext = <<<END_OF_CLEANUPCHANNELS_HELP
|
||||||
cleanupchannels.php [options]
|
cleanupchannels.php [options]
|
@ -26,6 +26,17 @@
|
|||||||
|
|
||||||
defined('GNUSOCIAL') || die();
|
defined('GNUSOCIAL') || die();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class TheFreeNetworkModule
|
||||||
|
* This module ensures that multiple protocols serving the same purpose won't result in duplicated data.
|
||||||
|
* This class is not to be extended but a developer implementing a new protocol should be aware of it and notify the
|
||||||
|
* StartTFNCensus event.
|
||||||
|
*
|
||||||
|
* @category Module
|
||||||
|
* @package GNUsocial
|
||||||
|
* @author Bruno Casteleiro <brunoccast@fc.up.pt>
|
||||||
|
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||||
|
*/
|
||||||
class TheFreeNetworkModule extends Module
|
class TheFreeNetworkModule extends Module
|
||||||
{
|
{
|
||||||
const MODULE_VERSION = '0.1.0alpha0';
|
const MODULE_VERSION = '0.1.0alpha0';
|
||||||
|
@ -46,6 +46,8 @@ const ACTIVITYPUB_HTTP_CLIENT_HEADERS = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Adds ActivityPub support to GNU social when enabled
|
||||||
|
*
|
||||||
* @category Plugin
|
* @category Plugin
|
||||||
* @package GNUsocial
|
* @package GNUsocial
|
||||||
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
* @author Diogo Cordeiro <diogo@fc.up.pt>
|
||||||
|
@ -31,7 +31,7 @@ if (!defined('GNUSOCIAL') && !defined('STATUSNET')) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
require_once INSTALLDIR.'/plugins/Realtime/RealtimePlugin.php';
|
require_once INSTALLDIR . DIRECTORY_SEPARATOR . 'lib/modules/Realtime/RealtimePlugin.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plugin to do realtime updates using Comet
|
* Plugin to do realtime updates using Comet
|
||||||
@ -52,8 +52,12 @@ class CometPlugin extends RealtimePlugin
|
|||||||
public $prefix = null;
|
public $prefix = null;
|
||||||
protected $bay = null;
|
protected $bay = null;
|
||||||
|
|
||||||
function __construct($server=null, $username=null, $password=null, $prefix=null)
|
public function __construct(
|
||||||
{
|
?string $server = null,
|
||||||
|
?string $username = null,
|
||||||
|
?string $password = null,
|
||||||
|
?string $prefix = null
|
||||||
|
) {
|
||||||
$this->server = $server;
|
$this->server = $server;
|
||||||
$this->username = $username;
|
$this->username = $username;
|
||||||
$this->password = $password;
|
$this->password = $password;
|
||||||
@ -62,11 +66,11 @@ class CometPlugin extends RealtimePlugin
|
|||||||
parent::__construct();
|
parent::__construct();
|
||||||
}
|
}
|
||||||
|
|
||||||
function _getScripts()
|
public function _getScripts(): array
|
||||||
{
|
{
|
||||||
$scripts = parent::_getScripts();
|
$scripts = parent::_getScripts();
|
||||||
|
|
||||||
$ours = array('js/jquery.comet.js', 'js/cometupdate.js');
|
$ours = ['js/jquery.comet.js', 'js/cometupdate.js'];
|
||||||
|
|
||||||
foreach ($ours as $script) {
|
foreach ($ours as $script) {
|
||||||
$scripts[] = $this->path($script);
|
$scripts[] = $this->path($script);
|
||||||
@ -75,30 +79,30 @@ class CometPlugin extends RealtimePlugin
|
|||||||
return $scripts;
|
return $scripts;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _updateInitialize($timeline, $user_id)
|
public function _updateInitialize($timeline, int $user_id)
|
||||||
{
|
{
|
||||||
$script = parent::_updateInitialize($timeline, $user_id);
|
$script = parent::_updateInitialize($timeline, $user_id);
|
||||||
return $script." CometUpdate.init(\"$this->server\", \"$timeline\", $user_id, \"$this->replyurl\", \"$this->favorurl\", \"$this->deleteurl\");";
|
return $script." CometUpdate.init(\"$this->server\", \"$timeline\", $user_id, \"$this->replyurl\", \"$this->favorurl\", \"$this->deleteurl\");";
|
||||||
}
|
}
|
||||||
|
|
||||||
function _connect()
|
public function _connect(): void
|
||||||
{
|
{
|
||||||
require_once INSTALLDIR.'/plugins/Comet/extlib/Bayeux/Bayeux.class.php';
|
require_once __DIR__. DIRECTORY_SEPARATOR . 'extlib/Bayeux/Bayeux.class.php';
|
||||||
// Bayeux? Comet? Huh? These terms confuse me
|
// Bayeux? Comet? Huh? These terms confuse me
|
||||||
$this->bay = new Bayeux($this->server, $this->user, $this->password);
|
$this->bay = new Bayeux($this->server, $this->user, $this->password);
|
||||||
}
|
}
|
||||||
|
|
||||||
function _publish($timeline, $json)
|
public function _publish($timeline, $json): void
|
||||||
{
|
{
|
||||||
$this->bay->publish($timeline, $json);
|
$this->bay->publish($timeline, $json);
|
||||||
}
|
}
|
||||||
|
|
||||||
function _disconnect()
|
public function _disconnect(): void
|
||||||
{
|
{
|
||||||
unset($this->bay);
|
unset($this->bay);
|
||||||
}
|
}
|
||||||
|
|
||||||
function _pathToChannel($path)
|
public function _pathToChannel(array $path): string
|
||||||
{
|
{
|
||||||
if (!empty($this->prefix)) {
|
if (!empty($this->prefix)) {
|
||||||
array_unshift($path, $this->prefix);
|
array_unshift($path, $this->prefix);
|
||||||
@ -108,14 +112,16 @@ class CometPlugin extends RealtimePlugin
|
|||||||
|
|
||||||
public function onPluginVersion(array &$versions): bool
|
public function onPluginVersion(array &$versions): bool
|
||||||
{
|
{
|
||||||
$versions[] = array('name' => 'Comet',
|
$versions[] = [
|
||||||
|
'name' => 'Comet',
|
||||||
'version' => self::PLUGIN_VERSION,
|
'version' => self::PLUGIN_VERSION,
|
||||||
'author' => 'Evan Prodromou',
|
'author' => 'Evan Prodromou',
|
||||||
'homepage' => 'https://git.gnu.io/gnu/gnu-social/tree/master/plugins/Comet',
|
'homepage' => 'https://git.gnu.io/gnu/gnu-social/tree/master/plugins/Comet',
|
||||||
'rawdescription' =>
|
'rawdescription' =>
|
||||||
// TRANS: Plugin description message. Bayeux is a protocol for transporting asynchronous messages
|
// TRANS: Plugin description message. Bayeux is a protocol for transporting asynchronous messages
|
||||||
// TRANS: and Comet is a web application model.
|
// TRANS: and Comet is a web application model.
|
||||||
_m('Plugin to make updates using Comet and Bayeux.'));
|
_m('Plugin to make updates using Comet and Bayeux.')
|
||||||
|
];
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,36 +30,36 @@ class Bayeux
|
|||||||
|
|
||||||
public $sUrl = '';
|
public $sUrl = '';
|
||||||
|
|
||||||
function __construct($sUrl, $sUser='', $sPassword='')
|
public function __construct($sUrl, $sUser='', $sPassword='')
|
||||||
{
|
{
|
||||||
$this->sUrl = $sUrl;
|
$this->sUrl = $sUrl;
|
||||||
|
|
||||||
$this->oCurl = curl_init();
|
$this->oCurl = curl_init();
|
||||||
|
|
||||||
$aHeaders = array();
|
$aHeaders = [];
|
||||||
$aHeaders[] = 'Connection: Keep-Alive';
|
$aHeaders[] = 'Connection: Keep-Alive';
|
||||||
|
|
||||||
curl_setopt($this->oCurl, CURLOPT_URL, $sUrl);
|
curl_setopt($this->oCurl, CURLOPT_URL, $sUrl);
|
||||||
curl_setopt($this->oCurl, CURLOPT_HTTPHEADER, $aHeaders);
|
curl_setopt($this->oCurl, CURLOPT_HTTPHEADER, $aHeaders);
|
||||||
curl_setopt($this->oCurl, CURLOPT_HEADER, 0);
|
curl_setopt($this->oCurl, CURLOPT_HEADER, 0);
|
||||||
curl_setopt($this->oCurl, CURLOPT_POST, 1);
|
curl_setopt($this->oCurl, CURLOPT_POST, 1);
|
||||||
curl_setopt($this->oCurl, CURLOPT_RETURNTRANSFER,1);
|
curl_setopt($this->oCurl, CURLOPT_RETURNTRANSFER, 1);
|
||||||
|
|
||||||
if (!is_null($sUser) && mb_strlen($sUser) > 0) {
|
if (!is_null($sUser) && mb_strlen($sUser) > 0) {
|
||||||
curl_setopt($this->oCurl, CURLOPT_USERPWD,"$sUser:$sPassword");
|
curl_setopt($this->oCurl, CURLOPT_USERPWD, "$sUser:$sPassword");
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->handShake();
|
$this->handShake();
|
||||||
}
|
}
|
||||||
|
|
||||||
function __destruct()
|
public function __destruct()
|
||||||
{
|
{
|
||||||
$this->disconnect();
|
$this->disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handShake()
|
public function handShake()
|
||||||
{
|
{
|
||||||
$msgHandshake = array();
|
$msgHandshake = [];
|
||||||
$msgHandshake['channel'] = '/meta/handshake';
|
$msgHandshake['channel'] = '/meta/handshake';
|
||||||
$msgHandshake['version'] = "1.0";
|
$msgHandshake['version'] = "1.0";
|
||||||
$msgHandshake['minimumVersion'] = "0.9";
|
$msgHandshake['minimumVersion'] = "0.9";
|
||||||
@ -70,8 +70,9 @@ class Bayeux
|
|||||||
|
|
||||||
$data = curl_exec($this->oCurl);
|
$data = curl_exec($this->oCurl);
|
||||||
|
|
||||||
if(curl_errno($this->oCurl))
|
if (curl_errno($this->oCurl)) {
|
||||||
die("Error: " . curl_error($this->oCurl));
|
die("Error: " . curl_error($this->oCurl));
|
||||||
|
}
|
||||||
|
|
||||||
$oReturn = json_decode($data);
|
$oReturn = json_decode($data);
|
||||||
|
|
||||||
@ -81,8 +82,7 @@ class Bayeux
|
|||||||
|
|
||||||
$bSuccessful = ($oReturn->successful) ? true : false;
|
$bSuccessful = ($oReturn->successful) ? true : false;
|
||||||
|
|
||||||
if($bSuccessful)
|
if ($bSuccessful) {
|
||||||
{
|
|
||||||
$this->clientId = $oReturn->clientId;
|
$this->clientId = $oReturn->clientId;
|
||||||
|
|
||||||
$this->connect();
|
$this->connect();
|
||||||
@ -101,9 +101,9 @@ class Bayeux
|
|||||||
$data = curl_exec($this->oCurl);
|
$data = curl_exec($this->oCurl);
|
||||||
}
|
}
|
||||||
|
|
||||||
function disconnect()
|
public function disconnect()
|
||||||
{
|
{
|
||||||
$msgHandshake = array();
|
$msgHandshake = [];
|
||||||
$msgHandshake['channel'] = '/meta/disconnect';
|
$msgHandshake['channel'] = '/meta/disconnect';
|
||||||
$msgHandshake['id'] = $this->nNextId++;
|
$msgHandshake['id'] = $this->nNextId++;
|
||||||
$msgHandshake['clientId'] = $this->clientId;
|
$msgHandshake['clientId'] = $this->clientId;
|
||||||
@ -115,10 +115,11 @@ class Bayeux
|
|||||||
|
|
||||||
public function publish($sChannel, $oData)
|
public function publish($sChannel, $oData)
|
||||||
{
|
{
|
||||||
if(!$sChannel || !$oData)
|
if (!$sChannel || !$oData) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$aMsg = array();
|
$aMsg = [];
|
||||||
|
|
||||||
$aMsg['channel'] = $sChannel;
|
$aMsg['channel'] = $sChannel;
|
||||||
$aMsg['id'] = $this->nNextId++;
|
$aMsg['id'] = $this->nNextId++;
|
||||||
|
@ -1,46 +1,40 @@
|
|||||||
<?php
|
<?php
|
||||||
|
// This file is part of GNU social - https://www.gnu.org/software/social
|
||||||
|
//
|
||||||
|
// GNU social 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.
|
||||||
|
//
|
||||||
|
// GNU social 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 GNU social. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* StatusNet, the distributed open-source microblogging tool
|
|
||||||
*
|
|
||||||
* Plugin to do "real time" updates using Meteor
|
* Plugin to do "real time" updates using Meteor
|
||||||
*
|
*
|
||||||
* PHP version 5
|
|
||||||
*
|
|
||||||
* LICENCE: 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* @category Plugin
|
* @category Plugin
|
||||||
* @package StatusNet
|
* @package GNUsocial
|
||||||
* @author Evan Prodromou <evan@status.net>
|
* @author Evan Prodromou <evan@status.net>
|
||||||
* @copyright 2009 StatusNet, Inc.
|
* @copyright 2010-2019 Free Software Foundation, Inc http://www.fsf.org
|
||||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||||
* @link http://status.net/
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!defined('GNUSOCIAL') && !defined('STATUSNET')) {
|
defined('GNUSOCIAL') || die();
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
require_once INSTALLDIR.'/plugins/Realtime/RealtimePlugin.php';
|
require_once INSTALLDIR . DIRECTORY_SEPARATOR . 'lib/modules/Realtime/RealtimePlugin.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plugin to do realtime updates using Meteor
|
* Plugin to do realtime updates using Meteor
|
||||||
*
|
*
|
||||||
* @category Plugin
|
* @category Plugin
|
||||||
* @package StatusNet
|
* @package GNUsocial
|
||||||
* @author Evan Prodromou <evan@status.net>
|
* @author Evan Prodromou <evan@status.net>
|
||||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
|
||||||
* @link http://status.net/
|
|
||||||
*/
|
*/
|
||||||
class MeteorPlugin extends RealtimePlugin
|
class MeteorPlugin extends RealtimePlugin
|
||||||
{
|
{
|
||||||
@ -55,8 +49,14 @@ class MeteorPlugin extends RealtimePlugin
|
|||||||
public $persistent = true;
|
public $persistent = true;
|
||||||
protected $_socket = null;
|
protected $_socket = null;
|
||||||
|
|
||||||
function __construct($webserver=null, $webport=4670, $controlport=4671, $controlserver=null, $channelbase='', $protocol='http')
|
public function __construct(
|
||||||
{
|
?string $webserver = null,
|
||||||
|
int $webport = 4670,
|
||||||
|
int $controlport = 4671,
|
||||||
|
?string $controlserver = null,
|
||||||
|
string $channelbase = '',
|
||||||
|
string $protocol = 'http'
|
||||||
|
) {
|
||||||
global $config;
|
global $config;
|
||||||
|
|
||||||
$this->webserver = (empty($webserver)) ? $config['site']['server'] : $webserver;
|
$this->webserver = (empty($webserver)) ? $config['site']['server'] : $webserver;
|
||||||
@ -72,14 +72,16 @@ class MeteorPlugin extends RealtimePlugin
|
|||||||
/**
|
/**
|
||||||
* Pull settings from config file/database if set.
|
* Pull settings from config file/database if set.
|
||||||
*/
|
*/
|
||||||
function initialize()
|
public function initialize()
|
||||||
{
|
{
|
||||||
$settings = array('webserver',
|
$settings = [
|
||||||
|
'webserver',
|
||||||
'webport',
|
'webport',
|
||||||
'controlport',
|
'controlport',
|
||||||
'controlserver',
|
'controlserver',
|
||||||
'channelbase',
|
'channelbase',
|
||||||
'protocol');
|
'protocol',
|
||||||
|
];
|
||||||
foreach ($settings as $name) {
|
foreach ($settings as $name) {
|
||||||
$val = common_config('meteor', $name);
|
$val = common_config('meteor', $name);
|
||||||
if ($val !== false) {
|
if ($val !== false) {
|
||||||
@ -90,47 +92,57 @@ class MeteorPlugin extends RealtimePlugin
|
|||||||
return parent::initialize();
|
return parent::initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
function _getScripts()
|
public function _getScripts()
|
||||||
{
|
{
|
||||||
$scripts = parent::_getScripts();
|
$scripts = parent::_getScripts();
|
||||||
if ($this->protocol == 'https') {
|
if ($this->protocol == 'https') {
|
||||||
$scripts[] = 'https://'.$this->webserver.(($this->webport == 443) ? '':':'.$this->webport).'/meteor.js';
|
$scripts[] = 'https://' . $this->webserver . (($this->webport == 443) ? '' : ':' . $this->webport) . '/meteor.js';
|
||||||
} else {
|
} else {
|
||||||
$scripts[] = 'http://'.$this->webserver.(($this->webport == 80) ? '':':'.$this->webport).'/meteor.js';
|
$scripts[] = 'http://' . $this->webserver . (($this->webport == 80) ? '' : ':' . $this->webport) . '/meteor.js';
|
||||||
}
|
}
|
||||||
$scripts[] = $this->path('js/meteorupdater.js');
|
$scripts[] = $this->path('js/meteorupdater.js');
|
||||||
return $scripts;
|
return $scripts;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _updateInitialize($timeline, $user_id)
|
public function _updateInitialize($timeline, int $user_id)
|
||||||
{
|
{
|
||||||
$script = parent::_updateInitialize($timeline, $user_id);
|
$script = parent::_updateInitialize($timeline, $user_id);
|
||||||
$ours = sprintf("MeteorUpdater.init(%s, %s, %s, %s);",
|
$ours = sprintf(
|
||||||
|
"MeteorUpdater.init(%s, %s, %s, %s);",
|
||||||
json_encode($this->webserver),
|
json_encode($this->webserver),
|
||||||
json_encode($this->webport),
|
json_encode($this->webport),
|
||||||
json_encode($this->protocol),
|
json_encode($this->protocol),
|
||||||
json_encode($timeline));
|
json_encode($timeline)
|
||||||
|
);
|
||||||
return $script." ".$ours;
|
return $script." ".$ours;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _connect()
|
public function _connect()
|
||||||
{
|
{
|
||||||
$controlserver = (empty($this->controlserver)) ? $this->webserver : $this->controlserver;
|
$controlserver = (empty($this->controlserver)) ? $this->webserver : $this->controlserver;
|
||||||
|
|
||||||
$errno = $errstr = null;
|
$errno = $errstr = null;
|
||||||
$timeout = 5;
|
$timeout = 5;
|
||||||
$flags = STREAM_CLIENT_CONNECT;
|
$flags = STREAM_CLIENT_CONNECT;
|
||||||
if ($this->persistent) $flags |= STREAM_CLIENT_PERSISTENT;
|
if ($this->persistent) {
|
||||||
|
$flags |= STREAM_CLIENT_PERSISTENT;
|
||||||
|
}
|
||||||
|
|
||||||
// May throw an exception.
|
// May throw an exception.
|
||||||
$this->_socket = stream_socket_client("tcp://{$controlserver}:{$this->controlport}", $errno, $errstr, $timeout, $flags);
|
$this->_socket = stream_socket_client(
|
||||||
|
"tcp://{$controlserver}:{$this->controlport}",
|
||||||
|
$errno,
|
||||||
|
$errstr,
|
||||||
|
$timeout,
|
||||||
|
$flags
|
||||||
|
);
|
||||||
if (!$this->_socket) {
|
if (!$this->_socket) {
|
||||||
// TRANS: Exception. %1$s is the control server, %2$s is the control port.
|
// TRANS: Exception. %1$s is the control server, %2$s is the control port.
|
||||||
throw new Exception(sprintf(_m('Could not connect to %1$s on %2$s.'),$controlserver,$this->controlport));
|
throw new Exception(sprintf(_m('Could not connect to %1$s on %2$s.'), $controlserver, $this->controlport));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _publish($channel, $message)
|
public function _publish($channel, $message)
|
||||||
{
|
{
|
||||||
$message = json_encode($message);
|
$message = json_encode($message);
|
||||||
$message = addslashes($message);
|
$message = addslashes($message);
|
||||||
@ -139,12 +151,12 @@ class MeteorPlugin extends RealtimePlugin
|
|||||||
$result = fgets($this->_socket);
|
$result = fgets($this->_socket);
|
||||||
if (preg_match('/^ERR (.*)$/', $result, $matches)) {
|
if (preg_match('/^ERR (.*)$/', $result, $matches)) {
|
||||||
// TRANS: Exception. %s is the Meteor message that could not be added.
|
// TRANS: Exception. %s is the Meteor message that could not be added.
|
||||||
throw new Exception(sprintf(_m('Error adding meteor message "%s".'),$matches[1]));
|
throw new Exception(sprintf(_m('Error adding meteor message "%s".'), $matches[1]));
|
||||||
}
|
}
|
||||||
// TODO: parse and deal with result
|
// TODO: parse and deal with result
|
||||||
}
|
}
|
||||||
|
|
||||||
function _disconnect()
|
public function _disconnect()
|
||||||
{
|
{
|
||||||
if (!$this->persistent) {
|
if (!$this->persistent) {
|
||||||
$cnt = fwrite($this->_socket, "QUIT\n");
|
$cnt = fwrite($this->_socket, "QUIT\n");
|
||||||
@ -154,7 +166,7 @@ class MeteorPlugin extends RealtimePlugin
|
|||||||
|
|
||||||
// Meteord flips out with default '/' separator
|
// Meteord flips out with default '/' separator
|
||||||
|
|
||||||
function _pathToChannel($path)
|
public function _pathToChannel(array $path): string
|
||||||
{
|
{
|
||||||
if (!empty($this->channelbase)) {
|
if (!empty($this->channelbase)) {
|
||||||
array_unshift($path, $this->channelbase);
|
array_unshift($path, $this->channelbase);
|
||||||
@ -164,13 +176,15 @@ class MeteorPlugin extends RealtimePlugin
|
|||||||
|
|
||||||
public function onPluginVersion(array &$versions): bool
|
public function onPluginVersion(array &$versions): bool
|
||||||
{
|
{
|
||||||
$versions[] = array('name' => 'Meteor',
|
$versions[] = [
|
||||||
|
'name' => 'Meteor',
|
||||||
'version' => self::PLUGIN_VERSION,
|
'version' => self::PLUGIN_VERSION,
|
||||||
'author' => 'Evan Prodromou',
|
'author' => 'Evan Prodromou',
|
||||||
'homepage' => 'https://git.gnu.io/gnu/gnu-social/tree/master/plugins/Meteor',
|
'homepage' => 'https://git.gnu.io/gnu/gnu-social/tree/master/plugins/Meteor',
|
||||||
'rawdescription' =>
|
'rawdescription' =>
|
||||||
// TRANS: Plugin description.
|
// TRANS: Plugin description.
|
||||||
_m('Plugin to do "real time" updates using Meteor.'));
|
_m('Plugin to do "real time" updates using Meteor.')
|
||||||
|
];
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ FriendFeed's "real time" news.
|
|||||||
|
|
||||||
It requires a meteor server.
|
It requires a meteor server.
|
||||||
|
|
||||||
http://meteorserver.org/
|
https://github.com/visitsb/meteorserver/
|
||||||
|
|
||||||
Note that the controller interface needs to be accessible by the Web server, and
|
Note that the controller interface needs to be accessible by the Web server, and
|
||||||
the subscriber interface needs to be accessible by your Web users. You MUST
|
the subscriber interface needs to be accessible by your Web users. You MUST
|
||||||
@ -13,7 +13,7 @@ push any message to your subscribers. Not good!
|
|||||||
|
|
||||||
You can enable the plugin with this line in config.php:
|
You can enable the plugin with this line in config.php:
|
||||||
|
|
||||||
addPlugin('Meteor', array('webserver' => 'meteor server address'));
|
addPlugin('Meteor', ['webserver' => 'meteor server address']);
|
||||||
|
|
||||||
Available parameters:
|
Available parameters:
|
||||||
* webserver: Web server address. Defaults to site server.
|
* webserver: Web server address. Defaults to site server.
|
@ -1,9 +0,0 @@
|
|||||||
.fake: all clean
|
|
||||||
|
|
||||||
all: realtimeupdate.min.js
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f js/realtimeupdate.min.js
|
|
||||||
|
|
||||||
realtimeupdate.min.js: js/realtimeupdate.js
|
|
||||||
yui-compressor js/realtimeupdate.js > js/realtimeupdate.min.js
|
|
Loading…
Reference in New Issue
Block a user