diff --git a/plugins/Orbited/OrbitedPlugin.php b/plugins/Orbited/OrbitedPlugin.php new file mode 100644 index 0000000000..ba87b266a0 --- /dev/null +++ b/plugins/Orbited/OrbitedPlugin.php @@ -0,0 +1,154 @@ +. + * + * @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); +} + +require_once INSTALLDIR.'/plugins/Realtime/RealtimePlugin.php'; + +/** + * 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 + * @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 OrbitedPlugin extends RealtimePlugin +{ + public $webserver = null; + 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 onStartShowHeadElements($action) + { + // See http://orbited.org/wiki/Deployment#Cross-SubdomainDeployment + $action->element('script', null, ' document.domain = document.domain; '); + } + + function _getScripts() + { + $scripts = parent::_getScripts(); + + $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[] = common_path('plugins/Orbited/orbitedextra.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); + + $server = $this->_getStompServer(); + $port = $this->_getStompPort(); + + return $script." OrbitedUpdater.init(\"$server\", $port, ". + "\"{$timeline}\", \"{$this->webuser}\", \"{$this->webpass}\");"; + } + + function _connect() + { + 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."); + } else { + $this->log(LOG_ERR, 'Failed to connect to queue server'); + throw new ServerException('Failed to connect to queue server'); + } + } + + function _publish($channel, $message) + { + $result = $this->con->send($channel, + json_encode($message)); + + return $result; + // TODO: parse and deal with result + } + + function _disconnect() + { + $this->con->disconnect(); + } + + function _pathToChannel($path) + { + if (!empty($this->channelbase)) { + array_unshift($path, $this->channelbase); + } + return '/' . implode('/', $path); + } + + function _getStompServer() + { + return (!is_null($this->stompserver)) ? $this->stompserver : + (!is_null($this->webserver)) ? $this->webserver : + common_config('site', 'server'); + } + + function _getStompPort() + { + return (!is_null($this->stompport)) ? $this->stompport : 61613; + } + + function _getStompUrl() + { + $server = $this->_getStompServer(); + $port = $this->_getStompPort(); + return "tcp://$server:$port/"; + } +} diff --git a/plugins/Orbited/orbitedextra.js b/plugins/Orbited/orbitedextra.js new file mode 100644 index 0000000000..47e5c0c80e --- /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 new file mode 100644 index 0000000000..8c5ab3b732 --- /dev/null +++ b/plugins/Orbited/orbitedupdater.js @@ -0,0 +1,24 @@ +// 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.onmessageframe = function(frame) { + RealtimeUpdate.receive(JSON.parse(frame.body)); + }; + + stomp.onconnectedframe = function() { + stomp.subscribe(timeline); + } + + stomp.connect(server, port, username, password); + } + } +}(); + diff --git a/plugins/Realtime/RealtimePlugin.php b/plugins/Realtime/RealtimePlugin.php index 0f0d0f9f42..1819279686 100644 --- a/plugins/Realtime/RealtimePlugin.php +++ b/plugins/Realtime/RealtimePlugin.php @@ -230,6 +230,7 @@ class RealtimePlugin extends Plugin } $action->showContentBlock(); + $action->showScripts(); $action->elementEnd('body'); return false; // No default processing }