From 0d6314052fed12fd626bfa5519853f1d6ecb6814 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 1 Jul 2009 00:58:44 -0400 Subject: rename plugin --- plugins/Orbited/OrbitedPlugin.php | 205 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 plugins/Orbited/OrbitedPlugin.php (limited to 'plugins/Orbited/OrbitedPlugin.php') diff --git a/plugins/Orbited/OrbitedPlugin.php b/plugins/Orbited/OrbitedPlugin.php new file mode 100644 index 000000000..45251c66f --- /dev/null +++ b/plugins/Orbited/OrbitedPlugin.php @@ -0,0 +1,205 @@ +. + * + * @category Plugin + * @package Laconica + * @author Evan Prodromou + * @copyright 2009 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +/** + * Plugin to do realtime updates using Comet + * + * @category Plugin + * @package Laconica + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +class CometPlugin extends Plugin +{ + var $server = null; + + function __construct($server=null, $username=null, $password=null) + { + $this->server = $server; + $this->username = $username; + $this->password = $password; + + parent::__construct(); + } + + function onEndShowScripts($action) + { + $timeline = null; + + $this->log(LOG_DEBUG, 'got action ' . $action->trimmed('action')); + + switch ($action->trimmed('action')) { + case 'public': + $timeline = '/timelines/public'; + break; + case 'tag': + $tag = $action->trimmed('tag'); + if (!empty($tag)) { + $timeline = '/timelines/tag/'.$tag; + } else { + return true; + } + break; + default: + return true; + } + + $scripts = array('jquery.comet.js', 'json2.js', 'updatetimeline.js'); + + foreach ($scripts as $script) { + $action->element('script', array('type' => 'text/javascript', + 'src' => common_path('plugins/Comet/'.$script)), + ' '); + } + + $user = common_current_user(); + + if (!empty($user->id)) { + $user_id = $user->id; + } else { + $user_id = 0; + } + + $replyurl = common_local_url('newnotice'); + $favorurl = common_local_url('favor'); + // FIXME: need to find a better way to pass this pattern in + $deleteurl = common_local_url('deletenotice', + array('notice' => '0000000000')); + + $action->elementStart('script', array('type' => 'text/javascript')); + $action->raw("$(document).ready(function() { updater.init(\"$this->server\", \"$timeline\", $user_id, \"$replyurl\", \"$favorurl\", \"$deleteurl\"); });"); + $action->elementEnd('script'); + + return true; + } + + function onEndNoticeSave($notice) + { + $this->log(LOG_INFO, "Called for save notice."); + + $timelines = array(); + + // XXX: Add other timelines; this is just for the public one + + if ($notice->is_local || + ($notice->is_local == 0 && !common_config('public', 'localonly'))) { + $timelines[] = '/timelines/public'; + } + + $tags = $this->getNoticeTags($notice); + + if (!empty($tags)) { + foreach ($tags as $tag) { + $timelines[] = '/timelines/tag/' . $tag; + } + } + + if (count($timelines) > 0) { + // Require this, since we need it + require_once(INSTALLDIR.'/plugins/Comet/bayeux.class.inc.php'); + + $json = $this->noticeAsJson($notice); + + // Bayeux? Comet? Huh? These terms confuse me + $bay = new Bayeux($this->server, $this->user, $this->password); + + foreach ($timelines as $timeline) { + $this->log(LOG_INFO, "Posting notice $notice->id to '$timeline'."); + $bay->publish($timeline, $json); + } + + $bay = NULL; + } + + return true; + } + + function noticeAsJson($notice) + { + // FIXME: this code should be abstracted to a neutral third + // party, like Notice::asJson(). I'm not sure of the ethics + // of refactoring from within a plugin, so I'm just abusing + // the TwitterApiAction method. Don't do this unless you're me! + + require_once(INSTALLDIR.'/lib/twitterapi.php'); + + $act = new TwitterApiAction('/dev/null'); + + $arr = $act->twitter_status_array($notice, true); + $arr['url'] = $notice->bestUrl(); + $arr['html'] = htmlspecialchars($notice->rendered); + $arr['source'] = htmlspecialchars($arr['source']); + + if (!empty($notice->reply_to)) { + $reply_to = Notice::staticGet('id', $notice->reply_to); + if (!empty($reply_to)) { + $arr['in_reply_to_status_url'] = $reply_to->bestUrl(); + } + $reply_to = null; + } + + $profile = $notice->getProfile(); + $arr['user']['profile_url'] = $profile->profileurl; + + return $arr; + } + + function getNoticeTags($notice) + { + $tags = null; + + $nt = new Notice_tag(); + $nt->notice_id = $notice->id; + + if ($nt->find()) { + $tags = array(); + while ($nt->fetch()) { + $tags[] = $nt->tag; + } + } + + $nt->free(); + $nt = null; + + return $tags; + } + + // Push this up to Plugin + + function log($level, $msg) + { + common_log($level, get_class($this) . ': '.$msg); + } +} -- cgit v1.2.3-54-g00ecf From 9c2d0879e9064fe3b9cf9af2c7eabe869966bd92 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 21 Jul 2009 11:00:03 -0700 Subject: updated OrbitedPlugin to use RealtimePlugin --- plugins/Orbited/OrbitedPlugin.php | 186 ++++++++++---------------------------- 1 file changed, 47 insertions(+), 139 deletions(-) (limited to 'plugins/Orbited/OrbitedPlugin.php') diff --git a/plugins/Orbited/OrbitedPlugin.php b/plugins/Orbited/OrbitedPlugin.php index 45251c66f..cf6e5de13 100644 --- a/plugins/Orbited/OrbitedPlugin.php +++ b/plugins/Orbited/OrbitedPlugin.php @@ -2,7 +2,7 @@ /** * Laconica, the distributed open-source microblogging tool * - * Plugin to do "real time" updates using Comet/Bayeux + * Plugin to do "real time" updates using Orbited + STOMP * * PHP version 5 * @@ -31,8 +31,13 @@ if (!defined('LACONICA')) { exit(1); } +require_once INSTALLDIR.'/plugins/Realtime/RealtimePlugin.php'; + /** - * Plugin to do realtime updates using Comet + * Plugin to do realtime updates using Orbited + STOMP + * + * This plugin pushes data to a STOMP server which is then served to the + * browser by the Orbited server. * * @category Plugin * @package Laconica @@ -41,165 +46,68 @@ if (!defined('LACONICA')) { * @link http://laconi.ca/ */ -class CometPlugin extends Plugin +class OrbitedPlugin extends RealtimePlugin { - var $server = null; + public $webserver = null; + public $webport = null; + public $channelbase = null; + public $stompserver = null; + public $username = null; + public $password = null; - function __construct($server=null, $username=null, $password=null) - { - $this->server = $server; - $this->username = $username; - $this->password = $password; + protected $con = null; - parent::__construct(); + function _getScripts() + { + $scripts = parent::_getScripts(); + $root = 'http://'.$this->webserver.(($this->webport == 80) ? '':':'.$this->webport); + $scripts[] = $root.'/static/Orbited.js'; + $scripts[] = $root.'/static/protocols/stomp/stomp.js'; + $scripts[] = common_path('plugins/Orbited/orbitedupdater.js'); + return $scripts; } - function onEndShowScripts($action) + function _updateInitialize($timeline, $user_id) { - $timeline = null; - - $this->log(LOG_DEBUG, 'got action ' . $action->trimmed('action')); - - switch ($action->trimmed('action')) { - case 'public': - $timeline = '/timelines/public'; - break; - case 'tag': - $tag = $action->trimmed('tag'); - if (!empty($tag)) { - $timeline = '/timelines/tag/'.$tag; - } else { - return true; - } - break; - default: - return true; - } - - $scripts = array('jquery.comet.js', 'json2.js', 'updatetimeline.js'); - - foreach ($scripts as $script) { - $action->element('script', array('type' => 'text/javascript', - 'src' => common_path('plugins/Comet/'.$script)), - ' '); - } - - $user = common_current_user(); - - if (!empty($user->id)) { - $user_id = $user->id; - } else { - $user_id = 0; - } - - $replyurl = common_local_url('newnotice'); - $favorurl = common_local_url('favor'); - // FIXME: need to find a better way to pass this pattern in - $deleteurl = common_local_url('deletenotice', - array('notice' => '0000000000')); - - $action->elementStart('script', array('type' => 'text/javascript')); - $action->raw("$(document).ready(function() { updater.init(\"$this->server\", \"$timeline\", $user_id, \"$replyurl\", \"$favorurl\", \"$deleteurl\"); });"); - $action->elementEnd('script'); - - return true; + $script = parent::_updateInitialize($timeline, $user_id); + return $script." OrbitedUpdater.init(\"$this->stompserver\", $this->stompport, \"{$timeline}\");"; } - function onEndNoticeSave($notice) + function _connect() { - $this->log(LOG_INFO, "Called for save notice."); - - $timelines = array(); + require_once(INSTALLDIR.'/extlibs/Stomp.php'); - // XXX: Add other timelines; this is just for the public one + $stompserver = (empty($this->stompserver)) ? "tcp://{$this->webserver}:61613/" : $this->stompserver; - if ($notice->is_local || - ($notice->is_local == 0 && !common_config('public', 'localonly'))) { - $timelines[] = '/timelines/public'; - } + $this->con = new Stomp($stompserver); - $tags = $this->getNoticeTags($notice); - - if (!empty($tags)) { - foreach ($tags as $tag) { - $timelines[] = '/timelines/tag/' . $tag; - } - } - - if (count($timelines) > 0) { - // Require this, since we need it - require_once(INSTALLDIR.'/plugins/Comet/bayeux.class.inc.php'); - - $json = $this->noticeAsJson($notice); - - // Bayeux? Comet? Huh? These terms confuse me - $bay = new Bayeux($this->server, $this->user, $this->password); - - foreach ($timelines as $timeline) { - $this->log(LOG_INFO, "Posting notice $notice->id to '$timeline'."); - $bay->publish($timeline, $json); - } - - $bay = NULL; + if ($this->con->connect($this->username, $this->password)) { + $this->_log(LOG_INFO, "Connected."); + } else { + $this->_log(LOG_ERR, 'Failed to connect to queue server'); + throw new ServerException('Failed to connect to queue server'); } - - return true; } - function noticeAsJson($notice) + function _publish($channel, $message) { - // FIXME: this code should be abstracted to a neutral third - // party, like Notice::asJson(). I'm not sure of the ethics - // of refactoring from within a plugin, so I'm just abusing - // the TwitterApiAction method. Don't do this unless you're me! - - require_once(INSTALLDIR.'/lib/twitterapi.php'); - - $act = new TwitterApiAction('/dev/null'); - - $arr = $act->twitter_status_array($notice, true); - $arr['url'] = $notice->bestUrl(); - $arr['html'] = htmlspecialchars($notice->rendered); - $arr['source'] = htmlspecialchars($arr['source']); + $result = $this->con->send($channel, + json_encode($message)); - if (!empty($notice->reply_to)) { - $reply_to = Notice::staticGet('id', $notice->reply_to); - if (!empty($reply_to)) { - $arr['in_reply_to_status_url'] = $reply_to->bestUrl(); - } - $reply_to = null; - } - - $profile = $notice->getProfile(); - $arr['user']['profile_url'] = $profile->profileurl; - - return $arr; + return $result; + // TODO: parse and deal with result } - function getNoticeTags($notice) + function _disconnect() { - $tags = null; - - $nt = new Notice_tag(); - $nt->notice_id = $notice->id; - - if ($nt->find()) { - $tags = array(); - while ($nt->fetch()) { - $tags[] = $nt->tag; - } - } - - $nt->free(); - $nt = null; - - return $tags; + $this->con->disconnect(); } - // Push this up to Plugin - - function log($level, $msg) + function _pathToChannel($path) { - common_log($level, get_class($this) . ': '.$msg); + if (!empty($this->channelbase)) { + array_unshift($path, $this->channelbase); + } + return '/' . implode('/', $path); } } -- cgit v1.2.3-54-g00ecf From 035978270d609b650b8e32f252366e0e75b12507 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 4 Oct 2009 03:02:04 -0400 Subject: Update OrbitedPlugin to work with RealtimePlugin framework --- plugins/Orbited/OrbitedPlugin.php | 43 ++++++++++- plugins/Orbited/orbitedupdater.js | 21 ++++++ plugins/Orbited/updatetimeline.js | 154 -------------------------------------- 3 files changed, 60 insertions(+), 158 deletions(-) create mode 100644 plugins/Orbited/orbitedupdater.js delete mode 100644 plugins/Orbited/updatetimeline.js (limited to 'plugins/Orbited/OrbitedPlugin.php') diff --git a/plugins/Orbited/OrbitedPlugin.php b/plugins/Orbited/OrbitedPlugin.php index cf6e5de13..ad7d1d276 100644 --- a/plugins/Orbited/OrbitedPlugin.php +++ b/plugins/Orbited/OrbitedPlugin.php @@ -52,34 +52,49 @@ class OrbitedPlugin extends RealtimePlugin public $webport = null; public $channelbase = null; public $stompserver = null; + public $stompport = null; public $username = null; public $password = null; + public $webuser = null; + public $webpass = null; protected $con = null; function _getScripts() { $scripts = parent::_getScripts(); - $root = 'http://'.$this->webserver.(($this->webport == 80) ? '':':'.$this->webport); + + $port = (is_null($this->webport)) ? 8000 : $this->webport; + + $server = (is_null($this->webserver)) ? common_config('site', 'server') : $this->webserver; + + $root = 'http://'.$server.(($port == 80) ? '':':'.$port); + $scripts[] = $root.'/static/Orbited.js'; $scripts[] = $root.'/static/protocols/stomp/stomp.js'; $scripts[] = common_path('plugins/Orbited/orbitedupdater.js'); + return $scripts; } function _updateInitialize($timeline, $user_id) { $script = parent::_updateInitialize($timeline, $user_id); - return $script." OrbitedUpdater.init(\"$this->stompserver\", $this->stompport, \"{$timeline}\");"; + + $server = $this->_getStompServer(); + $port = $this->_getStompPort(); + + return $script." OrbitedUpdater.init(\"$server\", $port, ". + "\"{$timeline}\", \"{$this->webuser}\", \"{$this->webpass}\");"; } function _connect() { require_once(INSTALLDIR.'/extlibs/Stomp.php'); - $stompserver = (empty($this->stompserver)) ? "tcp://{$this->webserver}:61613/" : $this->stompserver; + $url = $this->_getStompUrl(); - $this->con = new Stomp($stompserver); + $this->con = new Stomp($url); if ($this->con->connect($this->username, $this->password)) { $this->_log(LOG_INFO, "Connected."); @@ -110,4 +125,24 @@ class OrbitedPlugin extends RealtimePlugin } return '/' . implode('/', $path); } + + function _getStompServer() + { + $server = (!is_null($this->stompserver)) ? $this->stompserver : + (!is_null($this->webserver)) ? $this->webserver : + common_config('site', 'server'); + return $server; + } + + function _getStompPort() + { + $port = (!is_null($this->stompport)) ? $this->stompport : 61613; + } + + function _getStompUrl() + { + $server = $this->_getStompServer(); + $port = $this->_getStompPort(); + return "tcp://$server:$port/"; + } } diff --git a/plugins/Orbited/orbitedupdater.js b/plugins/Orbited/orbitedupdater.js new file mode 100644 index 000000000..d70f4a4fd --- /dev/null +++ b/plugins/Orbited/orbitedupdater.js @@ -0,0 +1,21 @@ +// Update the local timeline from a Orbited server + +var OrbitedUpdater = function() +{ + return { + + init: function(server, port, timeline, username, password) + { + // set up stomp client. + stomp = new STOMPClient(); + + stomp.connect(server, port, username, password); + stomp.subscribe(timeline); + + stomp.onmessageframe = function(frame) { + RealtimeUpdate.receive(JSON.parse(frame.body)); + }; + }; + } +}(); + diff --git a/plugins/Orbited/updatetimeline.js b/plugins/Orbited/updatetimeline.js deleted file mode 100644 index 170949e9b..000000000 --- a/plugins/Orbited/updatetimeline.js +++ /dev/null @@ -1,154 +0,0 @@ -// update the local timeline from a Comet server -// - -var updater = function() -{ - var _server; - var _timeline; - var _userid; - var _replyurl; - var _favorurl; - var _deleteurl; - var _cometd; - - return { - init: function(server, timeline, userid, replyurl, favorurl, deleteurl) - { - _cometd = $.cometd; // Uses the default Comet object - _cometd.setLogLevel('debug'); - _cometd.init(server); - _server = server; - _timeline = timeline; - _userid = userid; - _favorurl = favorurl; - _replyurl = replyurl; - _deleteurl = deleteurl; - _cometd.subscribe(timeline, receive); - $(window).unload(leave); - } - } - - function leave() - { - _cometd.disconnect(); - } - - function receive(message) - { - id = message.data.id; - - // Don't add it if it already exists - - if ($("#notice-"+id).length > 0) { - return; - } - - var noticeItem = makeNoticeItem(message.data); - $("#notices_primary .notices").prepend(noticeItem, true); - $("#notices_primary .notice:first").css({display:"none"}); - $("#notices_primary .notice:first").fadeIn(1000); - NoticeHover(); - NoticeReply(); - } - - function makeNoticeItem(data) - { - user = data['user']; - html = data['html'].replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"'); - source = data['source'].replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"'); - - ni = "
  • "+ - "
    "+ - ""+ - ""+ - "\""+user['screen_name']+"\"/"+ - ""+user['screen_name']+""+ - ""+ - ""+ - "

    "+html+"

    "+ - "
    "+ - "
    "+ - "
    "+ - "
    Published
    "+ - "
    "+ - ""+ - "a few seconds ago"+ - " "+ - "
    "+ - "
    "+ - "
    "+ - "
    From
    "+ - "
    "+source+"
    "+ // may have a link, I think - "
    "; - - if (data['in_reply_to_status_id']) { - ni = ni+"
    "+ - "
    To
    "+ - "
    "+ - "in reply to"+ - "
    "+ - "
    "; - } - - ni = ni+"
    "+ - "
    "; - - if (_userid != 0) { - var input = $("form#form_notice fieldset input#token"); - var session_key = input.val(); - ni = ni+makeFavoriteForm(data['id'], session_key); - ni = ni+makeReplyLink(data['id'], data['user']['screen_name']); - if (_userid == data['user']['id']) { - ni = ni+makeDeleteLink(data['id']); - } - } - - ni = ni+"
    "+ - "
  • "; - return ni; - } - - function makeFavoriteForm(id, session_key) - { - var ff; - - ff = "
    "+ - "
    "+ - "Favor this notice"+ // XXX: i18n - ""+ - ""+ - ""+ - "
    "+ - "
    "; - return ff; - } - - function makeReplyLink(id, nickname) - { - var rl; - rl = "
    "+ - "
    Reply to this notice
    "+ - "
    "+ - "Reply "+id+""+ - ""+ - "
    "+ - "
    "; - return rl; - } - - function makeDeleteLink(id) - { - var dl, delurl; - delurl = _deleteurl.replace("0000000000", id); - - dl = "
    "+ - "
    Delete this notice
    "+ - "
    "+ - "Delete"+ - "
    "+ - "
    "; - - return dl; - } -}(); - -- cgit v1.2.3-54-g00ecf From 27ff66c9de64a60cb3219f6d823cb290d4f18c01 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sun, 4 Oct 2009 04:05:40 -0400 Subject: Some changes required from Orbited debugging --- plugins/Orbited/OrbitedPlugin.php | 18 ++++++++++++------ plugins/Orbited/orbitedextra.js | 2 ++ plugins/Orbited/orbitedupdater.js | 11 +++++++---- 3 files changed, 21 insertions(+), 10 deletions(-) create mode 100644 plugins/Orbited/orbitedextra.js (limited to 'plugins/Orbited/OrbitedPlugin.php') diff --git a/plugins/Orbited/OrbitedPlugin.php b/plugins/Orbited/OrbitedPlugin.php index ad7d1d276..ba87b266a 100644 --- a/plugins/Orbited/OrbitedPlugin.php +++ b/plugins/Orbited/OrbitedPlugin.php @@ -60,6 +60,12 @@ class OrbitedPlugin extends RealtimePlugin protected $con = null; + function onStartShowHeadElements($action) + { + // See http://orbited.org/wiki/Deployment#Cross-SubdomainDeployment + $action->element('script', null, ' document.domain = document.domain; '); + } + function _getScripts() { $scripts = parent::_getScripts(); @@ -71,6 +77,7 @@ class OrbitedPlugin extends RealtimePlugin $root = 'http://'.$server.(($port == 80) ? '':':'.$port); $scripts[] = $root.'/static/Orbited.js'; + $scripts[] = common_path('plugins/Orbited/orbitedextra.js'); $scripts[] = $root.'/static/protocols/stomp/stomp.js'; $scripts[] = common_path('plugins/Orbited/orbitedupdater.js'); @@ -90,16 +97,16 @@ class OrbitedPlugin extends RealtimePlugin function _connect() { - require_once(INSTALLDIR.'/extlibs/Stomp.php'); + require_once(INSTALLDIR.'/extlib/Stomp.php'); $url = $this->_getStompUrl(); $this->con = new Stomp($url); if ($this->con->connect($this->username, $this->password)) { - $this->_log(LOG_INFO, "Connected."); + $this->log(LOG_INFO, "Connected."); } else { - $this->_log(LOG_ERR, 'Failed to connect to queue server'); + $this->log(LOG_ERR, 'Failed to connect to queue server'); throw new ServerException('Failed to connect to queue server'); } } @@ -128,15 +135,14 @@ class OrbitedPlugin extends RealtimePlugin function _getStompServer() { - $server = (!is_null($this->stompserver)) ? $this->stompserver : + return (!is_null($this->stompserver)) ? $this->stompserver : (!is_null($this->webserver)) ? $this->webserver : common_config('site', 'server'); - return $server; } function _getStompPort() { - $port = (!is_null($this->stompport)) ? $this->stompport : 61613; + return (!is_null($this->stompport)) ? $this->stompport : 61613; } function _getStompUrl() diff --git a/plugins/Orbited/orbitedextra.js b/plugins/Orbited/orbitedextra.js new file mode 100644 index 000000000..47e5c0c80 --- /dev/null +++ b/plugins/Orbited/orbitedextra.js @@ -0,0 +1,2 @@ +TCPSocket = Orbited.TCPSocket; + diff --git a/plugins/Orbited/orbitedupdater.js b/plugins/Orbited/orbitedupdater.js index d70f4a4fd..8c5ab3b73 100644 --- a/plugins/Orbited/orbitedupdater.js +++ b/plugins/Orbited/orbitedupdater.js @@ -9,13 +9,16 @@ var OrbitedUpdater = function() // set up stomp client. stomp = new STOMPClient(); - stomp.connect(server, port, username, password); - stomp.subscribe(timeline); - stomp.onmessageframe = function(frame) { RealtimeUpdate.receive(JSON.parse(frame.body)); }; - }; + + stomp.onconnectedframe = function() { + stomp.subscribe(timeline); + } + + stomp.connect(server, port, username, password); + } } }(); -- cgit v1.2.3-54-g00ecf