Commit ec145b73fc91dd54695dd374c8a71a11e233b8c0
- Diff rendering mode:
- inline
- side by side
classes/Memcached_DataObject.php
(23 / 0)
|   | |||
| 331 | 331 | $exists = false; | |
| 332 | 332 | } | |
| 333 | 333 | ||
| 334 | // @fixme horrible evil hack! | ||
| 335 | // | ||
| 336 | // In multisite configuration we don't want to keep around a separate | ||
| 337 | // connection for every database; we could end up with thousands of | ||
| 338 | // connections open per thread. In an ideal world we might keep | ||
| 339 | // a connection per server and select different databases, but that'd | ||
| 340 | // be reliant on having the same db username/pass as well. | ||
| 341 | // | ||
| 342 | // MySQL connections are cheap enough we're going to try just | ||
| 343 | // closing out the old connection and reopening when we encounter | ||
| 344 | // a new DSN. | ||
| 345 | // | ||
| 346 | // WARNING WARNING if we end up actually using multiple DBs at a time | ||
| 347 | // we'll need some fancier logic here. | ||
| 348 | if (!$exists && !empty($_DB_DATAOBJECT['CONNECTIONS'])) { | ||
| 349 | foreach ($_DB_DATAOBJECT['CONNECTIONS'] as $index => $conn) { | ||
| 350 | if (!empty($conn)) { | ||
| 351 | $conn->disconnect(); | ||
| 352 | } | ||
| 353 | unset($_DB_DATAOBJECT['CONNECTIONS'][$index]); | ||
| 354 | } | ||
| 355 | } | ||
| 356 | |||
| 334 | 357 | $result = parent::_connect(); | |
| 335 | 358 | ||
| 336 | 359 | if ($result && !$exists) { |
classes/Queue_item.php
(6 / 3)
|   | |||
| 25 | 25 | function sequenceKey() | |
| 26 | 26 | { return array(false, false); } | |
| 27 | 27 | ||
| 28 | static function top($transport) { | ||
| 28 | static function top($transport=null) { | ||
| 29 | 29 | ||
| 30 | 30 | $qi = new Queue_item(); | |
| 31 | $qi->transport = $transport; | ||
| 31 | if ($transport) { | ||
| 32 | $qi->transport = $transport; | ||
| 33 | } | ||
| 32 | 34 | $qi->orderBy('created'); | |
| 33 | 35 | $qi->whereAdd('claimed is null'); | |
| 34 | 36 | ||
| … | … | ||
| 42 | 42 | # XXX: potential race condition | |
| 43 | 43 | # can we force it to only update if claimed is still null | |
| 44 | 44 | # (or old)? | |
| 45 | common_log(LOG_INFO, 'claiming queue item = ' . $qi->notice_id . ' for transport ' . $transport); | ||
| 45 | common_log(LOG_INFO, 'claiming queue item = ' . $qi->notice_id . | ||
| 46 | ' for transport ' . $qi->transport); | ||
| 46 | 47 | $orig = clone($qi); | |
| 47 | 48 | $qi->claimed = common_sql_now(); | |
| 48 | 49 | $result = $qi->update($orig); |
classes/Status_network.php
(20 / 3)
|   | |||
| 49 | 49 | static $cache = null; | |
| 50 | 50 | static $base = null; | |
| 51 | 51 | ||
| 52 | /** | ||
| 53 | * @param string $dbhost | ||
| 54 | * @param string $dbuser | ||
| 55 | * @param string $dbpass | ||
| 56 | * @param string $dbname | ||
| 57 | * @param array $servers memcached servers to use for caching config info | ||
| 58 | */ | ||
| 52 | 59 | static function setupDB($dbhost, $dbuser, $dbpass, $dbname, $servers) | |
| 53 | 60 | { | |
| 54 | 61 | global $config; | |
| … | … | ||
| 67 | 67 | if (class_exists('Memcache')) { | |
| 68 | 68 | self::$cache = new Memcache(); | |
| 69 | 69 | ||
| 70 | // Can't close persistent connections, making forking painful. | ||
| 71 | // | ||
| 72 | // @fixme only do this in *parent* CLI processes. | ||
| 73 | // single-process and child-processes *should* use persistent. | ||
| 74 | $persist = php_sapi_name() != 'cli'; | ||
| 70 | 75 | if (is_array($servers)) { | |
| 71 | 76 | foreach($servers as $server) { | |
| 72 | self::$cache->addServer($server); | ||
| 77 | self::$cache->addServer($server, 11211, $persist); | ||
| 73 | 78 | } | |
| 74 | 79 | } else { | |
| 75 | self::$cache->addServer($servers); | ||
| 80 | self::$cache->addServer($servers, 11211, $persist); | ||
| 76 | 81 | } | |
| 77 | 82 | } | |
| 78 | 83 | ||
| … | … | ||
| 101 | 101 | if (empty($sn)) { | |
| 102 | 102 | $sn = self::staticGet($k, $v); | |
| 103 | 103 | if (!empty($sn)) { | |
| 104 | self::$cache->set($ck, $sn); | ||
| 104 | self::$cache->set($ck, clone($sn)); | ||
| 105 | 105 | } | |
| 106 | 106 | } | |
| 107 | 107 | ||
| … | … | ||
| 133 | 133 | return parent::delete(); | |
| 134 | 134 | } | |
| 135 | 135 | ||
| 136 | /** | ||
| 137 | * @param string $servername hostname | ||
| 138 | * @param string $pathname URL base path | ||
| 139 | * @param string $wildcard hostname suffix to match wildcard config | ||
| 140 | */ | ||
| 136 | 141 | static function setupSite($servername, $pathname, $wildcard) | |
| 137 | 142 | { | |
| 138 | 143 | global $config; |
lib/cache.php
(19 / 0)
|   | |||
| 179 | 179 | ||
| 180 | 180 | return $success; | |
| 181 | 181 | } | |
| 182 | |||
| 183 | /** | ||
| 184 | * Close or reconnect any remote connections, such as to give | ||
| 185 | * daemon processes a chance to reconnect on a fresh socket. | ||
| 186 | * | ||
| 187 | * @return boolean success flag | ||
| 188 | */ | ||
| 189 | |||
| 190 | function reconnect() | ||
| 191 | { | ||
| 192 | $success = false; | ||
| 193 | |||
| 194 | if (Event::handle('StartCacheReconnect', array(&$success))) { | ||
| 195 | $success = true; | ||
| 196 | Event::handle('EndCacheReconnect', array()); | ||
| 197 | } | ||
| 198 | |||
| 199 | return $success; | ||
| 200 | } | ||
| 182 | 201 | } |
lib/common.php
(14 / 180)
|   | |||
| 76 | 76 | require_once(INSTALLDIR.'/lib/event.php'); | |
| 77 | 77 | require_once(INSTALLDIR.'/lib/plugin.php'); | |
| 78 | 78 | ||
| 79 | function _sn_to_path($sn) | ||
| 80 | { | ||
| 81 | $past_root = substr($sn, 1); | ||
| 82 | $last_slash = strrpos($past_root, '/'); | ||
| 83 | if ($last_slash > 0) { | ||
| 84 | $p = substr($past_root, 0, $last_slash); | ||
| 85 | } else { | ||
| 86 | $p = ''; | ||
| 87 | } | ||
| 88 | return $p; | ||
| 89 | } | ||
| 90 | |||
| 91 | // Save our sanity when code gets loaded through subroutines such as PHPUnit tests | ||
| 92 | global $default, $config, $_server, $_path; | ||
| 93 | |||
| 94 | // try to figure out where we are. $server and $path | ||
| 95 | // can be set by including module, else we guess based | ||
| 96 | // on HTTP info. | ||
| 97 | |||
| 98 | if (isset($server)) { | ||
| 99 | $_server = $server; | ||
| 100 | } else { | ||
| 101 | $_server = array_key_exists('SERVER_NAME', $_SERVER) ? | ||
| 102 | strtolower($_SERVER['SERVER_NAME']) : | ||
| 103 | null; | ||
| 104 | } | ||
| 105 | |||
| 106 | if (isset($path)) { | ||
| 107 | $_path = $path; | ||
| 108 | } else { | ||
| 109 | $_path = (array_key_exists('SERVER_NAME', $_SERVER) && array_key_exists('SCRIPT_NAME', $_SERVER)) ? | ||
| 110 | _sn_to_path($_SERVER['SCRIPT_NAME']) : | ||
| 111 | null; | ||
| 112 | } | ||
| 113 | |||
| 114 | require_once(INSTALLDIR.'/lib/default.php'); | ||
| 115 | |||
| 116 | // Set config values initially to default values | ||
| 117 | |||
| 118 | $config = $default; | ||
| 119 | |||
| 120 | // default configuration, overwritten in config.php | ||
| 121 | |||
| 122 | $config['db'] = &PEAR::getStaticProperty('DB_DataObject','options'); | ||
| 123 | |||
| 124 | $config['db'] = $default['db']; | ||
| 125 | |||
| 126 | // Backward compatibility | ||
| 127 | |||
| 128 | $config['site']['design'] =& $config['design']; | ||
| 129 | |||
| 130 | if (function_exists('date_default_timezone_set')) { | ||
| 131 | /* Work internally in UTC */ | ||
| 132 | date_default_timezone_set('UTC'); | ||
| 133 | } | ||
| 134 | |||
| 135 | 79 | function addPlugin($name, $attrs = null) | |
| 136 | 80 | { | |
| 137 | $name = ucfirst($name); | ||
| 138 | $pluginclass = "{$name}Plugin"; | ||
| 139 | |||
| 140 | if (!class_exists($pluginclass)) { | ||
| 141 | |||
| 142 | $files = array("local/plugins/{$pluginclass}.php", | ||
| 143 | "local/plugins/{$name}/{$pluginclass}.php", | ||
| 144 | "local/{$pluginclass}.php", | ||
| 145 | "local/{$name}/{$pluginclass}.php", | ||
| 146 | "plugins/{$pluginclass}.php", | ||
| 147 | "plugins/{$name}/{$pluginclass}.php"); | ||
| 148 | |||
| 149 | foreach ($files as $file) { | ||
| 150 | $fullpath = INSTALLDIR.'/'.$file; | ||
| 151 | if (@file_exists($fullpath)) { | ||
| 152 | include_once($fullpath); | ||
| 153 | break; | ||
| 154 | } | ||
| 155 | } | ||
| 156 | } | ||
| 157 | |||
| 158 | $inst = new $pluginclass(); | ||
| 159 | |||
| 160 | if (!empty($attrs)) { | ||
| 161 | foreach ($attrs as $aname => $avalue) { | ||
| 162 | $inst->$aname = $avalue; | ||
| 163 | } | ||
| 164 | } | ||
| 165 | return $inst; | ||
| 81 | return StatusNet::addPlugin($name, $attrs); | ||
| 166 | 82 | } | |
| 167 | 83 | ||
| 168 | // From most general to most specific: | ||
| 169 | // server-wide, then vhost-wide, then for a path, | ||
| 170 | // finally for a dir (usually only need one of the last two). | ||
| 171 | |||
| 172 | if (isset($conffile)) { | ||
| 173 | $_config_files = array($conffile); | ||
| 174 | } else { | ||
| 175 | $_config_files = array('/etc/statusnet/statusnet.php', | ||
| 176 | '/etc/statusnet/laconica.php', | ||
| 177 | '/etc/laconica/laconica.php', | ||
| 178 | '/etc/statusnet/'.$_server.'.php', | ||
| 179 | '/etc/laconica/'.$_server.'.php'); | ||
| 180 | |||
| 181 | if (strlen($_path) > 0) { | ||
| 182 | $_config_files[] = '/etc/statusnet/'.$_server.'_'.$_path.'.php'; | ||
| 183 | $_config_files[] = '/etc/laconica/'.$_server.'_'.$_path.'.php'; | ||
| 184 | } | ||
| 185 | |||
| 186 | $_config_files[] = INSTALLDIR.'/config.php'; | ||
| 187 | } | ||
| 188 | |||
| 189 | global $_have_a_config; | ||
| 190 | $_have_a_config = false; | ||
| 191 | |||
| 192 | foreach ($_config_files as $_config_file) { | ||
| 193 | if (@file_exists($_config_file)) { | ||
| 194 | include_once($_config_file); | ||
| 195 | $_have_a_config = true; | ||
| 196 | } | ||
| 197 | } | ||
| 198 | |||
| 199 | 84 | function _have_config() | |
| 200 | 85 | { | |
| 201 | global $_have_a_config; | ||
| 202 | return $_have_a_config; | ||
| 86 | return StatusNet::haveConfig(); | ||
| 203 | 87 | } | |
| 204 | 88 | ||
| 205 | // XXX: Throw a conniption if database not installed | ||
| 206 | // XXX: Find a way to use htmlwriter for this instead of handcoded markup | ||
| 207 | if (!_have_config()) { | ||
| 208 | echo '<p>'. _('No configuration file found. ') .'</p>'; | ||
| 209 | echo '<p>'. _('I looked for configuration files in the following places: ') .'<br /> '. implode($_config_files, '<br />'); | ||
| 210 | echo '<p>'. _('You may wish to run the installer to fix this.') .'</p>'; | ||
| 211 | echo '<a href="install.php">'. _('Go to the installer.') .'</a>'; | ||
| 212 | exit; | ||
| 213 | } | ||
| 214 | // Fixup for statusnet.ini | ||
| 215 | |||
| 216 | $_db_name = substr($config['db']['database'], strrpos($config['db']['database'], '/') + 1); | ||
| 217 | |||
| 218 | if ($_db_name != 'statusnet' && !array_key_exists('ini_'.$_db_name, $config['db'])) { | ||
| 219 | $config['db']['ini_'.$_db_name] = INSTALLDIR.'/classes/statusnet.ini'; | ||
| 220 | } | ||
| 221 | |||
| 222 | // Backwards compatibility | ||
| 223 | |||
| 224 | if (array_key_exists('memcached', $config)) { | ||
| 225 | if ($config['memcached']['enabled']) { | ||
| 226 | addPlugin('Memcache', array('servers' => $config['memcached']['server'])); | ||
| 227 | } | ||
| 228 | |||
| 229 | if (!empty($config['memcached']['base'])) { | ||
| 230 | $config['cache']['base'] = $config['memcached']['base']; | ||
| 231 | } | ||
| 232 | } | ||
| 233 | |||
| 234 | 89 | function __autoload($cls) | |
| 235 | 90 | { | |
| 236 | 91 | if (file_exists(INSTALLDIR.'/classes/' . $cls . '.php')) { | |
| … | … | ||
| 102 | 102 | } | |
| 103 | 103 | } | |
| 104 | 104 | ||
| 105 | // Load default plugins | ||
| 106 | |||
| 107 | foreach ($config['plugins']['default'] as $name => $params) { | ||
| 108 | if (is_null($params)) { | ||
| 109 | addPlugin($name); | ||
| 110 | } else if (is_array($params)) { | ||
| 111 | if (count($params) == 0) { | ||
| 112 | addPlugin($name); | ||
| 113 | } else { | ||
| 114 | $keys = array_keys($params); | ||
| 115 | if (is_string($keys[0])) { | ||
| 116 | addPlugin($name, $params); | ||
| 117 | } else { | ||
| 118 | foreach ($params as $paramset) { | ||
| 119 | addPlugin($name, $paramset); | ||
| 120 | } | ||
| 121 | } | ||
| 122 | } | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | 105 | // XXX: how many of these could be auto-loaded on use? | |
| 127 | 106 | // XXX: note that these files should not use config options | |
| 128 | 107 | // at compile time since DB config options are not yet loaded. | |
| … | … | ||
| 117 | 117 | require_once INSTALLDIR.'/lib/clientexception.php'; | |
| 118 | 118 | require_once INSTALLDIR.'/lib/serverexception.php'; | |
| 119 | 119 | ||
| 120 | // Load settings from database; note we need autoload for this | ||
| 121 | |||
| 122 | Config::loadSettings(); | ||
| 123 | |||
| 124 | // XXX: if plugins should check the schema at runtime, do that here. | ||
| 125 | |||
| 126 | if ($config['db']['schemacheck'] == 'runtime') { | ||
| 127 | Event::handle('CheckSchema'); | ||
| 120 | try { | ||
| 121 | StatusNet::init(@$server, @$path, @$conffile); | ||
| 122 | } catch (NoConfigException $e) { | ||
| 123 | // XXX: Throw a conniption if database not installed | ||
| 124 | // XXX: Find a way to use htmlwriter for this instead of handcoded markup | ||
| 125 | echo '<p>'. _('No configuration file found. ') .'</p>'; | ||
| 126 | echo '<p>'. _('I looked for configuration files in the following places: ') .'<br/> '; | ||
| 127 | echo implode($e->configFiles, '<br/>'); | ||
| 128 | echo '<p>'. _('You may wish to run the installer to fix this.') .'</p>'; | ||
| 129 | echo '<a href="install.php">'. _('Go to the installer.') .'</a>'; | ||
| 130 | exit; | ||
| 128 | 131 | } | |
| 129 | 132 | ||
| 133 | |||
| 130 | 134 | // XXX: other formats here | |
| 131 | 135 | ||
| 132 | 136 | define('NICKNAME_FMT', VALIDATE_NUM.VALIDATE_ALPHA_LOWER); | |
| 133 | |||
| 134 | // Give plugins a chance to initialize in a fully-prepared environment | ||
| 135 | |||
| 136 | Event::handle('InitializePlugin'); |
lib/dbqueuemanager.php
(97 / 64)
|   | |||
| 22 | 22 | * @category QueueManager | |
| 23 | 23 | * @package StatusNet | |
| 24 | 24 | * @author Evan Prodromou <evan@status.net> | |
| 25 | * @copyright 2009 StatusNet, Inc. | ||
| 25 | * @author Brion Vibber <brion@status.net> | ||
| 26 | * @copyright 2009-2010 StatusNet, Inc. | ||
| 26 | 27 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 | |
| 27 | 28 | * @link http://status.net/ | |
| 28 | 29 | */ | |
| 29 | 30 | ||
| 30 | 31 | class DBQueueManager extends QueueManager | |
| 31 | 32 | { | |
| 32 | var $qis = array(); | ||
| 33 | |||
| 34 | function enqueue($object, $queue) | ||
| 33 | /** | ||
| 34 | * Saves a notice object reference into the queue item table. | ||
| 35 | * @return boolean true on success | ||
| 36 | * @throws ServerException on failure | ||
| 37 | */ | ||
| 38 | public function enqueue($object, $queue) | ||
| 35 | 39 | { | |
| 36 | 40 | $notice = $object; | |
| 37 | 41 | ||
| … | … | ||
| 51 | 51 | throw new ServerException('DB error inserting queue item'); | |
| 52 | 52 | } | |
| 53 | 53 | ||
| 54 | $this->stats('enqueued', $queue); | ||
| 55 | |||
| 54 | 56 | return true; | |
| 55 | 57 | } | |
| 56 | 58 | ||
| 57 | function service($queue, $handler) | ||
| 59 | /** | ||
| 60 | * Poll every minute for new events during idle periods. | ||
| 61 | * We'll look in more often when there's data available. | ||
| 62 | * | ||
| 63 | * @return int seconds | ||
| 64 | */ | ||
| 65 | public function pollInterval() | ||
| 58 | 66 | { | |
| 59 | while (true) { | ||
| 60 | $this->_log(LOG_DEBUG, 'Checking for notices...'); | ||
| 61 | $timeout = $handler->timeout(); | ||
| 62 | $notice = $this->_nextItem($queue, $timeout); | ||
| 63 | if (empty($notice)) { | ||
| 64 | $this->_log(LOG_DEBUG, 'No notices waiting; idling.'); | ||
| 65 | // Nothing in the queue. Do you | ||
| 66 | // have other tasks, like servicing your | ||
| 67 | // XMPP connection, to do? | ||
| 68 | $handler->idle(QUEUE_HANDLER_MISS_IDLE); | ||
| 67 | return 60; | ||
| 68 | } | ||
| 69 | |||
| 70 | /** | ||
| 71 | * Run a polling cycle during idle processing in the input loop. | ||
| 72 | * @return boolean true if we had a hit | ||
| 73 | */ | ||
| 74 | public function poll() | ||
| 75 | { | ||
| 76 | $this->_log(LOG_DEBUG, 'Checking for notices...'); | ||
| 77 | $item = $this->_nextItem(); | ||
| 78 | if ($item === false) { | ||
| 79 | $this->_log(LOG_DEBUG, 'No notices waiting; idling.'); | ||
| 80 | return false; | ||
| 81 | } | ||
| 82 | if ($item === true) { | ||
| 83 | // We dequeued an entry for a deleted or invalid notice. | ||
| 84 | // Consider it a hit for poll rate purposes. | ||
| 85 | return true; | ||
| 86 | } | ||
| 87 | |||
| 88 | list($queue, $notice) = $item; | ||
| 89 | $this->_log(LOG_INFO, 'Got notice '. $notice->id . ' for transport ' . $queue); | ||
| 90 | |||
| 91 | // Yay! Got one! | ||
| 92 | $handler = $this->getHandler($queue); | ||
| 93 | if ($handler) { | ||
| 94 | if ($handler->handle_notice($notice)) { | ||
| 95 | $this->_log(LOG_INFO, "[$queue:notice $notice->id] Successfully handled notice"); | ||
| 96 | $this->_done($notice, $queue); | ||
| 69 | 97 | } else { | |
| 70 | $this->_log(LOG_INFO, 'Got notice '. $notice->id); | ||
| 71 | // Yay! Got one! | ||
| 72 | if ($handler->handle_notice($notice)) { | ||
| 73 | $this->_log(LOG_INFO, 'Successfully handled notice '. $notice->id); | ||
| 74 | $this->_done($notice, $queue); | ||
| 75 | } else { | ||
| 76 | $this->_log(LOG_INFO, 'Failed to handle notice '. $notice->id); | ||
| 77 | $this->_fail($notice, $queue); | ||
| 78 | } | ||
| 79 | // Chance to e.g. service your XMPP connection | ||
| 80 | $this->_log(LOG_DEBUG, 'Idling after success.'); | ||
| 81 | $handler->idle(QUEUE_HANDLER_HIT_IDLE); | ||
| 98 | $this->_log(LOG_INFO, "[$queue:notice $notice->id] Failed to handle notice"); | ||
| 99 | $this->_fail($notice, $queue); | ||
| 82 | 100 | } | |
| 83 | // XXX: when do we give up? | ||
| 101 | } else { | ||
| 102 | $this->_log(LOG_INFO, "[$queue:notice $notice->id] No handler for queue $queue"); | ||
| 103 | $this->_fail($notice, $queue); | ||
| 84 | 104 | } | |
| 105 | return true; | ||
| 85 | 106 | } | |
| 86 | 107 | ||
| 87 | function _nextItem($queue, $timeout=null) | ||
| 108 | /** | ||
| 109 | * Pop the oldest unclaimed item off the queue set and claim it. | ||
| 110 | * | ||
| 111 | * @return mixed false if no items; true if bogus hit; otherwise array(string, Notice) | ||
| 112 | * giving the queue transport name. | ||
| 113 | */ | ||
| 114 | protected function _nextItem() | ||
| 88 | 115 | { | |
| 89 | 116 | $start = time(); | |
| 90 | 117 | $result = null; | |
| 91 | 118 | ||
| 92 | $sleeptime = 1; | ||
| 119 | $qi = Queue_item::top(); | ||
| 120 | if (empty($qi)) { | ||
| 121 | return false; | ||
| 122 | } | ||
| 93 | 123 | ||
| 94 | do { | ||
| 95 | $qi = Queue_item::top($queue); | ||
| 96 | if (empty($qi)) { | ||
| 97 | $this->_log(LOG_DEBUG, "No new queue items, sleeping $sleeptime seconds."); | ||
| 98 | sleep($sleeptime); | ||
| 99 | $sleeptime *= 2; | ||
| 100 | } else { | ||
| 101 | $notice = Notice::staticGet('id', $qi->notice_id); | ||
| 102 | if (!empty($notice)) { | ||
| 103 | $result = $notice; | ||
| 104 | } else { | ||
| 105 | $this->_log(LOG_INFO, 'dequeued non-existent notice ' . $notice->id); | ||
| 106 | $qi->delete(); | ||
| 107 | $qi->free(); | ||
| 108 | $qi = null; | ||
| 109 | } | ||
| 110 | $sleeptime = 1; | ||
| 111 | } | ||
| 112 | } while (empty($result) && (is_null($timeout) || (time() - $start) < $timeout)); | ||
| 124 | $queue = $qi->transport; | ||
| 125 | $notice = Notice::staticGet('id', $qi->notice_id); | ||
| 126 | if (empty($notice)) { | ||
| 127 | $this->_log(LOG_INFO, "[$queue:notice $notice->id] dequeued non-existent notice"); | ||
| 128 | $qi->delete(); | ||
| 129 | return true; | ||
| 130 | } | ||
| 113 | 131 | ||
| 114 | return $result; | ||
| 132 | $result = $notice; | ||
| 133 | return array($queue, $notice); | ||
| 115 | 134 | } | |
| 116 | 135 | ||
| 117 | function _done($object, $queue) | ||
| 136 | /** | ||
| 137 | * Delete our claimed item from the queue after successful processing. | ||
| 138 | * | ||
| 139 | * @param Notice $object | ||
| 140 | * @param string $queue | ||
| 141 | */ | ||
| 142 | protected function _done($object, $queue) | ||
| 118 | 143 | { | |
| 119 | 144 | // XXX: right now, we only handle notices | |
| 120 | 145 | ||
| … | … | ||
| 149 | 149 | 'transport' => $queue)); | |
| 150 | 150 | ||
| 151 | 151 | if (empty($qi)) { | |
| 152 | $this->_log(LOG_INFO, 'Cannot find queue item for notice '.$notice->id.', queue '.$queue); | ||
| 152 | $this->_log(LOG_INFO, "[$queue:notice $notice->id] Cannot find queue item"); | ||
| 153 | 153 | } else { | |
| 154 | 154 | if (empty($qi->claimed)) { | |
| 155 | $this->_log(LOG_WARNING, 'Reluctantly releasing unclaimed queue item '. | ||
| 156 | 'for '.$notice->id.', queue '.$queue); | ||
| 155 | $this->_log(LOG_WARNING, "[$queue:notice $notice->id] Reluctantly releasing unclaimed queue item"); | ||
| 157 | 156 | } | |
| 158 | 157 | $qi->delete(); | |
| 159 | 158 | $qi->free(); | |
| 160 | $qi = null; | ||
| 161 | 159 | } | |
| 162 | 160 | ||
| 163 | $this->_log(LOG_INFO, 'done with notice ID = ' . $notice->id); | ||
| 161 | $this->_log(LOG_INFO, "[$queue:notice $notice->id] done with item"); | ||
| 162 | $this->stats('handled', $queue); | ||
| 164 | 163 | ||
| 165 | 164 | $notice->free(); | |
| 166 | $notice = null; | ||
| 167 | 165 | } | |
| 168 | 166 | ||
| 169 | function _fail($object, $queue) | ||
| 167 | /** | ||
| 168 | * Free our claimed queue item for later reprocessing in case of | ||
| 169 | * temporary failure. | ||
| 170 | * | ||
| 171 | * @param Notice $object | ||
| 172 | * @param string $queue | ||
| 173 | */ | ||
| 174 | protected function _fail($object, $queue) | ||
| 170 | 175 | { | |
| 171 | 176 | // XXX: right now, we only handle notices | |
| 172 | 177 | ||
| … | … | ||
| 181 | 181 | 'transport' => $queue)); | |
| 182 | 182 | ||
| 183 | 183 | if (empty($qi)) { | |
| 184 | $this->_log(LOG_INFO, 'Cannot find queue item for notice '.$notice->id.', queue '.$queue); | ||
| 184 | $this->_log(LOG_INFO, "[$queue:notice $notice->id] Cannot find queue item"); | ||
| 185 | 185 | } else { | |
| 186 | 186 | if (empty($qi->claimed)) { | |
| 187 | $this->_log(LOG_WARNING, 'Ignoring failure for unclaimed queue item '. | ||
| 188 | 'for '.$notice->id.', queue '.$queue); | ||
| 187 | $this->_log(LOG_WARNING, "[$queue:notice $notice->id] Ignoring failure for unclaimed queue item"); | ||
| 189 | 188 | } else { | |
| 190 | 189 | $orig = clone($qi); | |
| 191 | 190 | $qi->claimed = null; | |
| … | … | ||
| 193 | 193 | } | |
| 194 | 194 | } | |
| 195 | 195 | ||
| 196 | $this->_log(LOG_INFO, 'done with notice ID = ' . $notice->id); | ||
| 196 | $this->_log(LOG_INFO, "[$queue:notice $notice->id] done with queue item"); | ||
| 197 | $this->stats('error', $queue); | ||
| 197 | 198 | ||
| 198 | 199 | $notice->free(); | |
| 199 | $notice = null; | ||
| 200 | 200 | } | |
| 201 | 201 | ||
| 202 | function _log($level, $msg) | ||
| 202 | protected function _log($level, $msg) | ||
| 203 | 203 | { | |
| 204 | 204 | common_log($level, 'DBQueueManager: '.$msg); | |
| 205 | 205 | } |
lib/default.php
(2 / 0)
|   | |||
| 79 | 79 | 'queue_basename' => '/queue/statusnet/', | |
| 80 | 80 | 'stomp_username' => null, | |
| 81 | 81 | 'stomp_password' => null, | |
| 82 | 'monitor' => null, // URL to monitor ping endpoint (work in progress) | ||
| 83 | 'softlimit' => '90%', // total size or % of memory_limit at which to restart queue threads gracefully | ||
| 82 | 84 | ), | |
| 83 | 85 | 'license' => | |
| 84 | 86 | array('url' => 'http://creativecommons.org/licenses/by/3.0/', |
lib/event.php
(8 / 0)
|   | |||
| 138 | 138 | } | |
| 139 | 139 | return false; | |
| 140 | 140 | } | |
| 141 | |||
| 142 | /** | ||
| 143 | * Disables any and all handlers that have been set up so far; | ||
| 144 | * use only if you know it's safe to reinitialize all plugins. | ||
| 145 | */ | ||
| 146 | public static function clearHandlers() { | ||
| 147 | Event::$_handlers = array(); | ||
| 148 | } | ||
| 141 | 149 | } |
lib/iomanager.php
(192 / 0)
|   | |||
| 1 | <?php | ||
| 2 | /** | ||
| 3 | * StatusNet, the distributed open-source microblogging tool | ||
| 4 | * | ||
| 5 | * Abstract class for i/o managers | ||
| 6 | * | ||
| 7 | * PHP version 5 | ||
| 8 | * | ||
| 9 | * LICENCE: This program is free software: you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU Affero General Public License as published by | ||
| 11 | * the Free Software Foundation, either version 3 of the License, or | ||
| 12 | * (at your option) any later version. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, | ||
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | * GNU Affero General Public License for more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU Affero General Public License | ||
| 20 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 21 | * | ||
| 22 | * @category QueueManager | ||
| 23 | * @package StatusNet | ||
| 24 | * @author Evan Prodromou <evan@status.net> | ||
| 25 | * @author Sarven Capadisli <csarven@status.net> | ||
| 26 | * @author Brion Vibber <brion@status.net> | ||
| 27 | * @copyright 2009-2010 StatusNet, Inc. | ||
| 28 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 | ||
| 29 | * @link http://status.net/ | ||
| 30 | */ | ||
| 31 | |||
| 32 | abstract class IoManager | ||
| 33 | { | ||
| 34 | const SINGLE_ONLY = 0; | ||
| 35 | const INSTANCE_PER_SITE = 1; | ||
| 36 | const INSTANCE_PER_PROCESS = 2; | ||
| 37 | |||
| 38 | /** | ||
| 39 | * Factory function to get an appropriate subclass. | ||
| 40 | */ | ||
| 41 | public abstract static function get(); | ||
| 42 | |||
| 43 | /** | ||
| 44 | * Tell the i/o queue master if and how we can handle multi-site | ||
| 45 | * processes. | ||
| 46 | * | ||
| 47 | * Return one of: | ||
| 48 | * IoManager::SINGLE_ONLY | ||
| 49 | * IoManager::INSTANCE_PER_SITE | ||
| 50 | * IoManager::INSTANCE_PER_PROCESS | ||
| 51 | */ | ||
| 52 | public static function multiSite() | ||
| 53 | { | ||
| 54 | return IoManager::SINGLE_ONLY; | ||
| 55 | } | ||
| 56 | |||
| 57 | /** | ||
| 58 | * If in a multisite configuration, the i/o master will tell | ||
| 59 | * your manager about each site you'll have to handle so you | ||
| 60 | * can do any necessary per-site setup. | ||
| 61 | * | ||
| 62 | * @param string $site target site server name | ||
| 63 | */ | ||
| 64 | public function addSite($site) | ||
| 65 | { | ||
| 66 | /* no-op */ | ||
| 67 | } | ||
| 68 | |||
| 69 | /** | ||
| 70 | * This method is called when data is available on one of your | ||
| 71 | * i/o manager's sockets. The socket with data is passed in, | ||
| 72 | * in case you have multiple sockets. | ||
| 73 | * | ||
| 74 | * If your i/o manager is based on polling during idle processing, | ||
| 75 | * you don't need to implement this. | ||
| 76 | * | ||
| 77 | * @param resource $socket | ||
| 78 | * @return boolean true on success, false on failure | ||
| 79 | */ | ||
| 80 | public function handleInput($socket) | ||
| 81 | { | ||
| 82 | return true; | ||
| 83 | } | ||
| 84 | |||
| 85 | /** | ||
| 86 | * Return any open sockets that the run loop should listen | ||
| 87 | * for input on. If input comes in on a listed socket, | ||
| 88 | * the matching manager's handleInput method will be called. | ||
| 89 | * | ||
| 90 | * @return array of resources | ||
| 91 | */ | ||
| 92 | function getSockets() | ||
| 93 | { | ||
| 94 | return array(); | ||
| 95 | } | ||
| 96 | |||
| 97 | /** | ||
| 98 | * Maximum planned time between poll() calls when input isn't waiting. | ||
| 99 | * Actual time may vary! | ||
| 100 | * | ||
| 101 | * When we get a polling hit, the timeout will be cut down to 0 while | ||
| 102 | * input is coming in, then will back off to this amount if no further | ||
| 103 | * input shows up. | ||
| 104 | * | ||
| 105 | * By default polling is disabled; you must override this to enable | ||
| 106 | * polling for this manager. | ||
| 107 | * | ||
| 108 | * @return int max poll interval in seconds, or 0 to disable polling | ||
| 109 | */ | ||
| 110 | function pollInterval() | ||
| 111 | { | ||
| 112 | return 0; | ||
| 113 | } | ||
| 114 | |||
| 115 | /** | ||
| 116 | * Request a maximum timeout for listeners before the next idle period. | ||
| 117 | * Actual wait may be shorter, so don't go crazy in your idle()! | ||
| 118 | * Wait could be longer if other handlers performed some slow activity. | ||
| 119 | * | ||
| 120 | * Return 0 to request that listeners return immediately if there's no | ||
| 121 | * i/o and speed up the idle as much as possible; but don't do that all | ||
| 122 | * the time as this will burn CPU. | ||
| 123 | * | ||
| 124 | * @return int seconds | ||
| 125 | */ | ||
| 126 | function timeout() | ||
| 127 | { | ||
| 128 | return 60; | ||
| 129 | } | ||
| 130 | |||
| 131 | /** | ||
| 132 | * Called by IoManager after each handled item or empty polling cycle. | ||
| 133 | * This is a good time to e.g. service your XMPP connection. | ||
| 134 | * | ||
| 135 | * Doesn't need to be overridden if there's no maintenance to do. | ||
| 136 | */ | ||
| 137 | function idle() | ||
| 138 | { | ||
| 139 | return true; | ||
| 140 | } | ||
| 141 | |||
| 142 | /** | ||
| 143 | * The meat of a polling manager... check for something to do | ||
| 144 | * and do it! Note that you should not take too long, as other | ||
| 145 | * i/o managers may need to do some work too! | ||
| 146 | * | ||
| 147 | * On a successful hit, the next poll() call will come as soon | ||
| 148 | * as possible followed by exponential backoff up to pollInterval() | ||
| 149 | * if no more data is available. | ||
| 150 | * | ||
| 151 | * @return boolean true if events were hit | ||
| 152 | */ | ||
| 153 | public function poll() | ||
| 154 | { | ||
| 155 | return false; | ||
| 156 | } | ||
| 157 | |||
| 158 | /** | ||
| 159 | * Initialization, run when the queue manager starts. | ||
| 160 | * If this function indicates failure, the handler run will be aborted. | ||
| 161 | * | ||
| 162 | * @param IoMaster $master process/event controller | ||
| 163 | * @return boolean true on success, false on failure | ||
| 164 | */ | ||
| 165 | public function start($master) | ||
| 166 | { | ||
| 167 | $this->master = $master; | ||
| 168 | return true; | ||
| 169 | } | ||
| 170 | |||
| 171 | /** | ||
| 172 | * Cleanup, run when the queue manager ends. | ||
| 173 | * If this function indicates failure, a warning will be logged. | ||
| 174 | * | ||
| 175 | * @return boolean true on success, false on failure | ||
| 176 | */ | ||
| 177 | public function finish() | ||
| 178 | { | ||
| 179 | return true; | ||
| 180 | } | ||
| 181 | |||
| 182 | /** | ||
| 183 | * Ping iomaster's queue status monitor with a stats update. | ||
| 184 | * Only valid during input loop! | ||
| 185 | * | ||
| 186 | * @param string $counter keyword for counter to increment | ||
| 187 | */ | ||
| 188 | public function stats($counter, $owners=array()) | ||
| 189 | { | ||
| 190 | $this->master->stats($counter, $owners); | ||
| 191 | } | ||
| 192 | } |
lib/iomaster.php
(360 / 0)
|   | |||
| 1 | <?php | ||
| 2 | /** | ||
| 3 | * StatusNet, the distributed open-source microblogging tool | ||
| 4 | * | ||
| 5 | * I/O manager to wrap around socket-reading and polling queue & connection managers. | ||
| 6 | * | ||
| 7 | * PHP version 5 | ||
| 8 | * | ||
| 9 | * LICENCE: This program is free software: you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU Affero General Public License as published by | ||
| 11 | * the Free Software Foundation, either version 3 of the License, or | ||
| 12 | * (at your option) any later version. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, | ||
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | * GNU Affero General Public License for more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU Affero General Public License | ||
| 20 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 21 | * | ||
| 22 | * @category QueueManager | ||
| 23 | * @package StatusNet | ||
| 24 | * @author Brion Vibber <brion@status.net> | ||
| 25 | * @copyright 2009 StatusNet, Inc. | ||
| 26 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 | ||
| 27 | * @link http://status.net/ | ||
| 28 | */ | ||
| 29 | |||
| 30 | class IoMaster | ||
| 31 | { | ||
| 32 | public $id; | ||
| 33 | |||
| 34 | protected $multiSite = false; | ||
| 35 | protected $managers = array(); | ||
| 36 | protected $singletons = array(); | ||
| 37 | |||
| 38 | protected $pollTimeouts = array(); | ||
| 39 | protected $lastPoll = array(); | ||
| 40 | |||
| 41 | /** | ||
| 42 | * @param string $id process ID to use in logging/monitoring | ||
| 43 | */ | ||
| 44 | public function __construct($id) | ||
| 45 | { | ||
| 46 | $this->id = $id; | ||
| 47 | $this->monitor = new QueueMonitor(); | ||
| 48 | } | ||
| 49 | |||
| 50 | public function init($multiSite=null) | ||
| 51 | { | ||
| 52 | if ($multiSite !== null) { | ||
| 53 | $this->multiSite = $multiSite; | ||
| 54 | } | ||
| 55 | if ($this->multiSite) { | ||
| 56 | $this->sites = $this->findAllSites(); | ||
| 57 | } else { | ||
| 58 | $this->sites = array(common_config('site', 'server')); | ||
| 59 | } | ||
| 60 | |||
| 61 | if (empty($this->sites)) { | ||
| 62 | throw new Exception("Empty status_network table, cannot init"); | ||
| 63 | } | ||
| 64 | |||
| 65 | foreach ($this->sites as $site) { | ||
| 66 | if ($site != common_config('site', 'server')) { | ||
| 67 | StatusNet::init($site); | ||
| 68 | } | ||
| 69 | |||
| 70 | $classes = array(); | ||
| 71 | if (Event::handle('StartIoManagerClasses', array(&$classes))) { | ||
| 72 | $classes[] = 'QueueManager'; | ||
| 73 | if (common_config('xmpp', 'enabled')) { | ||
| 74 | $classes[] = 'XmppManager'; // handles pings/reconnects | ||
| 75 | $classes[] = 'XmppConfirmManager'; // polls for outgoing confirmations | ||
| 76 | } | ||
| 77 | } | ||
| 78 | Event::handle('EndIoManagerClasses', array(&$classes)); | ||
| 79 | |||
| 80 | foreach ($classes as $class) { | ||
| 81 | $this->instantiate($class); | ||
| 82 | } | ||
| 83 | } | ||
| 84 | } | ||
| 85 | |||
| 86 | /** | ||
| 87 | * Pull all local sites from status_network table. | ||
| 88 | * @return array of hostnames | ||
| 89 | */ | ||
| 90 | protected function findAllSites() | ||
| 91 | { | ||
| 92 | $hosts = array(); | ||
| 93 | $sn = new Status_network(); | ||
| 94 | $sn->find(); | ||
| 95 | while ($sn->fetch()) { | ||
| 96 | $hosts[] = $sn->hostname; | ||
| 97 | } | ||
| 98 | return $hosts; | ||
| 99 | } | ||
| 100 | |||
| 101 | /** | ||
| 102 | * Instantiate an i/o manager class for the current site. | ||
| 103 | * If a multi-site capable handler is already present, | ||
| 104 | * we don't need to build a new one. | ||
| 105 | * | ||
| 106 | * @param string $class | ||
| 107 | */ | ||
| 108 | protected function instantiate($class) | ||
| 109 | { | ||
| 110 | if (isset($this->singletons[$class])) { | ||
| 111 | // Already instantiated a multi-site-capable handler. | ||
| 112 | // Just let it know it should listen to this site too! | ||
| 113 | $this->singletons[$class]->addSite(common_config('site', 'server')); | ||
| 114 | return; | ||
| 115 | } | ||
| 116 | |||
| 117 | $manager = $this->getManager($class); | ||
| 118 | |||
| 119 | if ($this->multiSite) { | ||
| 120 | $caps = $manager->multiSite(); | ||
| 121 | if ($caps == IoManager::SINGLE_ONLY) { | ||
| 122 | throw new Exception("$class can't run with --all; aborting."); | ||
| 123 | } | ||
| 124 | if ($caps == IoManager::INSTANCE_PER_PROCESS) { | ||
| 125 | // Save this guy for later! | ||
| 126 | // We'll only need the one to cover multiple sites. | ||
| 127 | $this->singletons[$class] = $manager; | ||
| 128 | $manager->addSite(common_config('site', 'server')); | ||
| 129 | } | ||
| 130 | } | ||
| 131 | |||
| 132 | $this->managers[] = $manager; | ||
| 133 | } | ||
| 134 | |||
| 135 | protected function getManager($class) | ||
| 136 | { | ||
| 137 | return call_user_func(array($class, 'get')); | ||
| 138 | } | ||
| 139 | |||
| 140 | /** | ||
| 141 | * Basic run loop... | ||
| 142 | * | ||
| 143 | * Initialize all io managers, then sit around waiting for input. | ||
| 144 | * Between events or timeouts, pass control back to idle() method | ||
| 145 | * to allow for any additional background processing. | ||
| 146 | */ | ||
| 147 | function service() | ||
| 148 | { | ||
| 149 | $this->logState('init'); | ||
| 150 | $this->start(); | ||
| 151 | |||
| 152 | while (true) { | ||
| 153 | $timeouts = array_values($this->pollTimeouts); | ||
| 154 | $timeouts[] = 60; // default max timeout | ||
| 155 | |||
| 156 | // Wait for something on one of our sockets | ||
| 157 | $sockets = array(); | ||
| 158 | $managers = array(); | ||
| 159 | foreach ($this->managers as $manager) { | ||
| 160 | foreach ($manager->getSockets() as $socket) { | ||
| 161 | $sockets[] = $socket; | ||
| 162 | $managers[] = $manager; | ||
| 163 | } | ||
| 164 | $timeouts[] = intval($manager->timeout()); | ||
| 165 | } | ||
| 166 | |||
| 167 | $timeout = min($timeouts); | ||
| 168 | if ($sockets) { | ||
| 169 | $read = $sockets; | ||
| 170 | $write = array(); | ||
| 171 | $except = array(); | ||
| 172 | $this->logState('listening'); | ||
| 173 | common_log(LOG_INFO, "Waiting up to $timeout seconds for socket data..."); | ||
| 174 | $ready = stream_select($read, $write, $except, $timeout, 0); | ||
| 175 | |||
| 176 | if ($ready === false) { | ||
| 177 | common_log(LOG_ERR, "Error selecting on sockets"); | ||
| 178 | } else if ($ready > 0) { | ||
| 179 | foreach ($read as $socket) { | ||
| 180 | $index = array_search($socket, $sockets, true); | ||
| 181 | if ($index !== false) { | ||
| 182 | $this->logState('queue'); | ||
| 183 | $managers[$index]->handleInput($socket); | ||
| 184 | } else { | ||
| 185 | common_log(LOG_ERR, "Saw input on a socket we didn't listen to"); | ||
| 186 | } | ||
| 187 | } | ||
| 188 | } | ||
| 189 | } | ||
| 190 | |||
| 191 | if ($timeout > 0 && empty($sockets)) { | ||
| 192 | // If we had no listeners, sleep until the pollers' next requested wakeup. | ||
| 193 | common_log(LOG_INFO, "Sleeping $timeout seconds until next poll cycle..."); | ||
| 194 | $this->logState('sleep'); | ||
| 195 | sleep($timeout); | ||
| 196 | } | ||
| 197 | |||
| 198 | $this->logState('poll'); | ||
| 199 | $this->poll(); | ||
| 200 | |||
| 201 | $this->logState('idle'); | ||
| 202 | $this->idle(); | ||
| 203 | |||
| 204 | $memoryLimit = $this->softMemoryLimit(); | ||
| 205 | if ($memoryLimit > 0) { | ||
| 206 | $usage = memory_get_usage(); | ||
| 207 | if ($usage > $memoryLimit) { | ||
| 208 | common_log(LOG_INFO, "Queue thread hit soft memory limit ($usage > $memoryLimit); gracefully restarting."); | ||
| 209 | break; | ||
| 210 | } | ||
| 211 | } | ||
| 212 | } | ||
| 213 | |||
| 214 | $this->logState('shutdown'); | ||
| 215 | $this->finish(); | ||
| 216 | } | ||
| 217 | |||
| 218 | /** | ||
| 219 | * Return fully-parsed soft memory limit in bytes. | ||
| 220 | * @return intval 0 or -1 if not set | ||
| 221 | */ | ||
| 222 | function softMemoryLimit() | ||
| 223 | { | ||
| 224 | $softLimit = trim(common_config('queue', 'softlimit')); | ||
| 225 | if (substr($softLimit, -1) == '%') { | ||
| 226 | $limit = trim(ini_get('memory_limit')); | ||
| 227 | $limit = $this->parseMemoryLimit($limit); | ||
| 228 | if ($limit > 0) { | ||
| 229 | return intval(substr($softLimit, 0, -1) * $limit / 100); | ||
| 230 | } else { | ||
| 231 | return -1; | ||
| 232 | } | ||
| 233 | } else { | ||
| 234 | return $this->parseMemoryLimit($limit); | ||
| 235 | } | ||
| 236 | return $softLimit; | ||
| 237 | } | ||
| 238 | |||
| 239 | /** | ||
| 240 | * Interpret PHP shorthand for memory_limit and friends. | ||
| 241 | * Why don't they just expose the actual numeric value? :P | ||
| 242 | * @param string $mem | ||
| 243 | * @return int | ||
| 244 | */ | ||
| 245 | protected function parseMemoryLimit($mem) | ||
| 246 | { | ||
| 247 | // http://www.php.net/manual/en/faq.using.php#faq.using.shorthandbytes | ||
| 248 | $size = array('k' => 1024, | ||
| 249 | 'm' => 1024*1024, | ||
| 250 | 'g' => 1024*1024*1024); | ||
| 251 | if (empty($mem)) { | ||
| 252 | return 0; | ||
| 253 | } else if (is_numeric($mem)) { | ||
| 254 | return intval($mem); | ||
| 255 | } else { | ||
| 256 | $mult = strtolower(substr($mem, -1)); | ||
| 257 | if (isset($size[$mult])) { | ||
| 258 | return substr($mem, 0, -1) * $size[$mult]; | ||
| 259 | } else { | ||
| 260 | return intval($mem); | ||
| 261 | } | ||
| 262 | } | ||
| 263 | } | ||
| 264 | |||
| 265 | function start() | ||
| 266 | { | ||
| 267 | foreach ($this->managers as $index => $manager) { | ||
| 268 | $manager->start($this); | ||
| 269 | // @fixme error check | ||
| 270 | if ($manager->pollInterval()) { | ||
| 271 | // We'll want to check for input on the first pass | ||
| 272 | $this->pollTimeouts[$index] = 0; | ||
| 273 | $this->lastPoll[$index] = 0; | ||
| 274 | } | ||
| 275 | } | ||
| 276 | } | ||
| 277 | |||
| 278 | function finish() | ||
| 279 | { | ||
| 280 | foreach ($this->managers as $manager) { | ||
| 281 | $manager->finish(); | ||
| 282 | // @fixme error check | ||
| 283 | } | ||
| 284 | } | ||
| 285 | |||
| 286 | /** | ||
| 287 | * Called during the idle portion of the runloop to see which handlers | ||
| 288 | */ | ||
| 289 | function poll() | ||
| 290 | { | ||
| 291 | foreach ($this->managers as $index => $manager) { | ||
| 292 | $interval = $manager->pollInterval(); | ||
| 293 | if ($interval <= 0) { | ||
| 294 | // Not a polling manager. | ||
| 295 | continue; | ||
| 296 | } | ||
| 297 | |||
| 298 | if (isset($this->pollTimeouts[$index])) { | ||
| 299 | $timeout = $this->pollTimeouts[$index]; | ||
| 300 | if (time() - $this->lastPoll[$index] < $timeout) { | ||
| 301 | // Not time to poll yet. | ||
| 302 | continue; | ||
| 303 | } | ||
| 304 | } else { | ||
| 305 | $timeout = 0; | ||
| 306 | } | ||
| 307 | $hit = $manager->poll(); | ||
| 308 | |||
| 309 | $this->lastPoll[$index] = time(); | ||
| 310 | if ($hit) { | ||
| 311 | // Do the next poll quickly, there may be more input! | ||
| 312 | $this->pollTimeouts[$index] = 0; | ||
| 313 | } else { | ||
| 314 | // Empty queue. Exponential backoff up to the maximum poll interval. | ||
| 315 | if ($timeout > 0) { | ||
| 316 | $timeout = min($timeout * 2, $interval); | ||
| 317 | } else { | ||
| 318 | $timeout = 1; | ||
| 319 | } | ||
| 320 | $this->pollTimeouts[$index] = $timeout; | ||
| 321 | } | ||
| 322 | } | ||
| 323 | } | ||
| 324 | |||
| 325 | /** | ||
| 326 | * Called after each handled item or empty polling cycle. | ||
| 327 | * This is a good time to e.g. service your XMPP connection. | ||
| 328 | */ | ||
| 329 | function idle() | ||
| 330 | { | ||
| 331 | foreach ($this->managers as $manager) { | ||
| 332 | $manager->idle(); | ||
| 333 | } | ||
| 334 | } | ||
| 335 | |||
| 336 | /** | ||
| 337 | * Send thread state update to the monitoring server, if configured. | ||
| 338 | * | ||
| 339 | * @param string $state ('init', 'queue', 'shutdown' etc) | ||
| 340 | * @param string $substate (optional, eg queue name 'omb' 'sms' etc) | ||
| 341 | */ | ||
| 342 | protected function logState($state, $substate='') | ||
| 343 | { | ||
| 344 | $this->monitor->logState($this->id, $state, $substate); | ||
| 345 | } | ||
| 346 | |||
| 347 | /** | ||
| 348 | * Send thread stats. | ||
| 349 | * Thread ID will be implicit; other owners can be listed as well | ||
| 350 | * for per-queue and per-site records. | ||
| 351 | * | ||
| 352 | * @param string $key counter name | ||
| 353 | * @param array $owners list of owner keys like 'queue:jabber' or 'site:stat01' | ||
| 354 | */ | ||
| 355 | public function stats($key, $owners=array()) | ||
| 356 | { | ||
| 357 | $owners[] = "thread:" . $this->id; | ||
| 358 | $this->monitor->stats($key, $owners); | ||
| 359 | } | ||
| 360 | } |
lib/jabber.php
(18 / 7)
|   | |||
| 86 | 86 | } | |
| 87 | 87 | ||
| 88 | 88 | /** | |
| 89 | * connect the configured Jabber account to the configured server | ||
| 89 | * Lazy-connect the configured Jabber account to the configured server; | ||
| 90 | * if already opened, the same connection will be returned. | ||
| 90 | 91 | * | |
| 92 | * In a multi-site background process, each site configuration | ||
| 93 | * will get its own connection. | ||
| 94 | * | ||
| 91 | 95 | * @param string $resource Resource to connect (defaults to configured resource) | |
| 92 | 96 | * | |
| 93 | 97 | * @return XMPPHP connection to the configured server | |
| … | … | ||
| 99 | 99 | ||
| 100 | 100 | function jabber_connect($resource=null) | |
| 101 | 101 | { | |
| 102 | static $conn = null; | ||
| 103 | if (!$conn) { | ||
| 102 | static $connections = array(); | ||
| 103 | $site = common_config('site', 'server'); | ||
| 104 | if (empty($connections[$site])) { | ||
| 105 | if (empty($resource)) { | ||
| 106 | $resource = common_config('xmpp', 'resource'); | ||
| 107 | } | ||
| 104 | 108 | $conn = new Sharing_XMPP(common_config('xmpp', 'host') ? | |
| 105 | 109 | common_config('xmpp', 'host') : | |
| 106 | 110 | common_config('xmpp', 'server'), | |
| 107 | 111 | common_config('xmpp', 'port'), | |
| 108 | 112 | common_config('xmpp', 'user'), | |
| 109 | 113 | common_config('xmpp', 'password'), | |
| 110 | ($resource) ? $resource : | ||
| 111 | common_config('xmpp', 'resource'), | ||
| 114 | $resource, | ||
| 112 | 115 | common_config('xmpp', 'server'), | |
| 113 | 116 | common_config('xmpp', 'debug') ? | |
| 114 | 117 | true : false, | |
| … | … | ||
| 122 | 122 | if (!$conn) { | |
| 123 | 123 | return false; | |
| 124 | 124 | } | |
| 125 | $connections[$site] = $conn; | ||
| 125 | 126 | ||
| 126 | 127 | $conn->autoSubscribe(); | |
| 127 | 128 | $conn->useEncryption(common_config('xmpp', 'encryption')); | |
| 128 | 129 | ||
| 129 | 130 | try { | |
| 130 | $conn->connect(true); // true = persistent connection | ||
| 131 | common_log(LOG_INFO, __METHOD__ . ": connecting " . | ||
| 132 | common_config('xmpp', 'user') . '/' . $resource); | ||
| 133 | //$conn->connect(true); // true = persistent connection | ||
| 134 | $conn->connect(); // persistent connections break multisite | ||
| 131 | 135 | } catch (XMPPHP_Exception $e) { | |
| 132 | 136 | common_log(LOG_ERR, $e->getMessage()); | |
| 133 | 137 | return false; | |
| … | … | ||
| 139 | 139 | ||
| 140 | 140 | $conn->processUntil('session_start'); | |
| 141 | 141 | } | |
| 142 | return $conn; | ||
| 142 | return $connections[$site]; | ||
| 143 | 143 | } | |
| 144 | 144 | ||
| 145 | 145 | /** |
lib/jabberqueuehandler.php
(47 / 0)
|   | |||
| 1 | <?php | ||
| 2 | /* | ||
| 3 | * StatusNet - the distributed open-source microblogging tool | ||
| 4 | * Copyright (C) 2008, 2009, StatusNet, Inc. | ||
| 5 | * | ||
| 6 | * This program is free software: you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU Affero General Public License as published by | ||
| 8 | * the Free Software Foundation, either version 3 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU Affero General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Affero General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | if (!defined('STATUSNET') && !defined('LACONICA')) { | ||
| 21 | exit(1); | ||
| 22 | } | ||
| 23 | |||
| 24 | /** | ||
| 25 | * Queue handler for pushing new notices to Jabber users. | ||
| 26 | * @fixme this exception handling doesn't look very good. | ||
| 27 | */ | ||
| 28 | class JabberQueueHandler extends QueueHandler | ||
| 29 | { | ||
| 30 | var $conn = null; | ||
| 31 | |||
| 32 | function transport() | ||
| 33 | { | ||
| 34 | return 'jabber'; | ||
| 35 | } | ||
| 36 | |||
| 37 | function handle_notice($notice) | ||
| 38 | { | ||
| 39 | require_once(INSTALLDIR.'/lib/jabber.php'); | ||
| 40 | try { | ||
| 41 | return jabber_broadcast_notice($notice); | ||
| 42 | } catch (XMPPHP_Exception $e) { | ||
| 43 | $this->log(LOG_ERR, "Got an XMPPHP_Exception: " . $e->getMessage()); | ||
| 44 | exit(1); | ||
| 45 | } | ||
| 46 | } | ||
| 47 | } |
lib/liberalstomp.php
(132 / 0)
|   | |||
| 1 | <?php | ||
| 2 | |||
| 3 | /** | ||
| 4 | * Based on code from Stomp PHP library, working around bugs in the base class. | ||
| 5 | * | ||
| 6 | * Original code is copyright 2005-2006 The Apache Software Foundation | ||
| 7 | * Modifications copyright 2009 StatusNet Inc by Brion Vibber <brion@status.net> | ||
| 8 | * | ||
| 9 | * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 10 | * you may not use this file except in compliance with the License. | ||
| 11 | * You may obtain a copy of the License at | ||
| 12 | * | ||
| 13 | * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 14 | * | ||
| 15 | * Unless required by applicable law or agreed to in writing, software | ||
| 16 | * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 17 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 18 | * See the License for the specific language governing permissions and | ||
| 19 | * limitations under the License. | ||
| 20 | */ | ||
| 21 | |||
| 22 | class LiberalStomp extends Stomp | ||
| 23 | { | ||
| 24 | /** | ||
| 25 | * We need to be able to get the socket so advanced daemons can | ||
| 26 | * do a select() waiting for input both from the queue and from | ||
| 27 | * other sources such as an XMPP connection. | ||
| 28 | * | ||
| 29 | * @return resource | ||
| 30 | */ | ||
| 31 | function getSocket() | ||
| 32 | { | ||
| 33 | return $this->_socket; | ||
| 34 | } | ||
| 35 | |||
| 36 | /** | ||
| 37 | * Make socket connection to the server | ||
| 38 | * We also set the stream to non-blocking mode, since we'll be | ||
| 39 | * select'ing to wait for updates. In blocking mode it seems | ||
| 40 | * to get confused sometimes. | ||
| 41 | * | ||
| 42 | * @throws StompException | ||
| 43 | */ | ||
| 44 | protected function _makeConnection () | ||
| 45 | { | ||
| 46 | parent::_makeConnection(); | ||
| 47 | stream_set_blocking($this->_socket, 0); | ||
| 48 | } | ||
| 49 | |||
| 50 | /** | ||
| 51 | * Version 1.0.0 of the Stomp library gets confused if messages | ||
| 52 | * come in too fast over the connection. This version will read | ||
| 53 | * out as many frames as are ready to be read from the socket. | ||
| 54 | * | ||
| 55 | * Modified from Stomp::readFrame() | ||
| 56 | * | ||
| 57 | * @return StompFrame False when no frame to read | ||
| 58 | */ | ||
| 59 | public function readFrames () | ||
| 60 | { | ||
| 61 | if (!$this->hasFrameToRead()) { | ||
| 62 | return false; | ||
| 63 | } | ||
| 64 | |||
| 65 | $rb = 1024; | ||
| 66 | $data = ''; | ||
| 67 | $end = false; | ||
| 68 | $frames = array(); | ||
| 69 | |||
| 70 | do { | ||
| 71 | // @fixme this sometimes hangs in blocking mode... | ||
| 72 | // shouldn't we have been idle until we found there's more data? | ||
| 73 | $read = fread($this->_socket, $rb); | ||
| 74 | if ($read === false) { | ||
| 75 | $this->_reconnect(); | ||
| 76 | // @fixme this will lose prior items | ||
| 77 | return $this->readFrames(); | ||
| 78 | } | ||
| 79 | $data .= $read; | ||
| 80 | if (strpos($data, "\x00") !== false) { | ||
| 81 | // Frames are null-delimited, but some servers | ||
| 82 | // may append an extra \n according to old bug reports. | ||
| 83 | $data = str_replace("\x00\n", "\x00", $data); | ||
| 84 | $chunks = explode("\x00", $data); | ||
| 85 | |||
| 86 | $data = array_pop($chunks); | ||
| 87 | $frames = array_merge($frames, $chunks); | ||
| 88 | if ($data == '') { | ||
| 89 | // We're at the end of a frame; stop reading. | ||
| 90 | break; | ||
| 91 | } else { | ||
| 92 | // In the middle of a frame; keep going. | ||
| 93 | } | ||
| 94 | } | ||
| 95 | // @fixme find out why this len < 2 check was there | ||
| 96 | //$len = strlen($data); | ||
| 97 | } while (true);//$len < 2 || $end == false); | ||
| 98 | |||
| 99 | return array_map(array($this, 'parseFrame'), $frames); | ||
| 100 | } | ||
| 101 | |||
| 102 | /** | ||
| 103 | * Parse a raw Stomp frame into an object. | ||
| 104 | * Extracted from Stomp::readFrame() | ||
| 105 | * | ||
| 106 | * @param string $data | ||
| 107 | * @return StompFrame | ||
| 108 | */ | ||
| 109 | function parseFrame($data) | ||
| 110 | { | ||
| 111 | list ($header, $body) = explode("\n\n", $data, 2); | ||
| 112 | $header = explode("\n", $header); | ||
| 113 | $headers = array(); | ||
| 114 | $command = null; | ||
| 115 | foreach ($header as $v) { | ||
| 116 | if (isset($command)) { | ||
| 117 | list ($name, $value) = explode(':', $v, 2); | ||
| 118 | $headers[$name] = $value; | ||
| 119 | } else { | ||
| 120 | $command = $v; | ||
| 121 | } | ||
| 122 | } | ||
| 123 | $frame = new StompFrame($command, $headers, trim($body)); | ||
| 124 | if (isset($frame->headers['transformation']) && $frame->headers['transformation'] == 'jms-map-json') { | ||
| 125 | require_once 'Stomp/Message/Map.php'; | ||
| 126 | return new StompMessageMap($frame); | ||
| 127 | } else { | ||
| 128 | return $frame; | ||
| 129 | } | ||
| 130 | return $frame; | ||
| 131 | } | ||
| 132 | } |
lib/ombqueuehandler.php
(56 / 0)
|   | |||
| 1 | <?php | ||
| 2 | /* | ||
| 3 | * StatusNet - the distributed open-source microblogging tool | ||
| 4 | * Copyright (C) 2008, 2009, StatusNet, Inc. | ||
| 5 | * | ||
| 6 | * This program is free software: you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU Affero General Public License as published by | ||
| 8 | * the Free Software Foundation, either version 3 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU Affero General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Affero General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | if (!defined('STATUSNET') && !defined('LACONICA')) { | ||
| 21 | exit(1); | ||
| 22 | } | ||
| 23 | |||
| 24 | /** | ||
| 25 | * Queue handler for pushing new notices to OpenMicroBlogging subscribers. | ||
| 26 | */ | ||
| 27 | class OmbQueueHandler extends QueueHandler | ||
| 28 | { | ||
| 29 | |||
| 30 | function transport() | ||
| 31 | { | ||
| 32 | return 'omb'; | ||
| 33 | } | ||
| 34 | |||
| 35 | /** | ||
| 36 | * @fixme doesn't currently report failure back to the queue manager | ||
| 37 | * because omb_broadcast_notice() doesn't report it to us | ||
| 38 | */ | ||
| 39 | function handle_notice($notice) | ||
| 40 | { | ||
| 41 | if ($this->is_remote($notice)) { | ||
| 42 | $this->log(LOG_DEBUG, 'Ignoring remote notice ' . $notice->id); | ||
| 43 | return true; | ||
| 44 | } else { | ||
| 45 | require_once(INSTALLDIR.'/lib/omb.php'); | ||
| 46 | omb_broadcast_notice($notice); | ||
| 47 | return true; | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | function is_remote($notice) | ||
| 52 | { | ||
| 53 | $user = User::staticGet($notice->profile_id); | ||
| 54 | return is_null($user); | ||
| 55 | } | ||
| 56 | } |
lib/pingqueuehandler.php
(37 / 0)
|   | |||
| 1 | <?php | ||
| 2 | /* | ||
| 3 | * StatusNet - the distributed open-source microblogging tool | ||
| 4 | * Copyright (C) 2008, 2009, StatusNet, Inc. | ||
| 5 | * | ||
| 6 | * This program is free software: you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU Affero General Public License as published by | ||
| 8 | * the Free Software Foundation, either version 3 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU Affero General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Affero General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | if (!defined('STATUSNET') && !defined('LACONICA')) { | ||
| 21 | exit(1); | ||
| 22 | } | ||
| 23 | |||
| 24 | /** | ||
| 25 | * Queue handler for pushing new notices to ping servers. | ||
| 26 | */ | ||
| 27 | class PingQueueHandler extends QueueHandler { | ||
| 28 | |||
| 29 | function transport() { | ||
| 30 | return 'ping'; | ||
| 31 | } | ||
| 32 | |||
| 33 | function handle_notice($notice) { | ||
| 34 | require_once INSTALLDIR . '/lib/ping.php'; | ||
| 35 | return ping_broadcast_notice($notice); | ||
| 36 | } | ||
| 37 | } |
lib/pluginqueuehandler.php
(50 / 0)
|   | |||
| 1 | <?php | ||
| 2 | /* | ||
| 3 | * StatusNet - the distributed open-source microblogging tool | ||
| 4 | * Copyright (C) 2008, 2009, StatusNet, Inc. | ||
| 5 | * | ||
| 6 | * This program is free software: you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU Affero General Public License as published by | ||
| 8 | * the Free Software Foundation, either version 3 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU Affero General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Affero General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | if (!defined('STATUSNET') && !defined('LACONICA')) { | ||
| 21 | exit(1); | ||
| 22 | } | ||
| 23 | |||
| 24 | /** | ||
| 25 | * Queue handler for letting plugins handle stuff. | ||
| 26 | * | ||
| 27 | * The plugin queue handler accepts notices over the "plugin" queue | ||
| 28 | * and simply passes them through the "HandleQueuedNotice" event. | ||
| 29 | * | ||
| 30 | * This gives plugins a chance to do background processing without | ||
| 31 | * actually registering their own queue and ensuring that things | ||
| 32 | * are queued into it. | ||
| 33 | * | ||
| 34 | * Fancier plugins may wish to instead hook the 'GetQueueHandlerClass' | ||
| 35 | * event with their own class, in which case they must ensure that | ||
| 36 | * their notices get enqueued when they need them. | ||
| 37 | */ | ||
| 38 | class PluginQueueHandler extends QueueHandler | ||
| 39 | { | ||
| 40 | function transport() | ||
| 41 | { | ||
| 42 | return 'plugin'; | ||
| 43 | } | ||
| 44 | |||
| 45 | function handle_notice($notice) | ||
| 46 | { | ||
| 47 | Event::handle('HandleQueuedNotice', array(&$notice)); | ||
| 48 | return true; | ||
| 49 | } | ||
| 50 | } |
lib/publicqueuehandler.php
(47 / 0)
|   | |||
| 1 | <?php | ||
| 2 | /* | ||
| 3 | * StatusNet - the distributed open-source microblogging tool | ||
| 4 | * Copyright (C) 2008, 2009, StatusNet, Inc. | ||
| 5 | * | ||
| 6 | * This program is free software: you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU Affero General Public License as published by | ||
| 8 | * the Free Software Foundation, either version 3 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU Affero General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Affero General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | if (!defined('STATUSNET') && !defined('LACONICA')) { | ||
| 21 | exit(1); | ||
| 22 | } | ||
| 23 | |||
| 24 | /** | ||
| 25 | * Queue handler for pushing new notices to public XMPP subscribers. | ||
| 26 | * @fixme correct this exception handling | ||
| 27 | */ | ||
| 28 | class PublicQueueHandler extends QueueHandler | ||
| 29 | { | ||
| 30 | |||
| 31 | function transport() | ||
| 32 | { | ||
| 33 | return 'public'; | ||
| 34 | } | ||
| 35 | |||
| 36 | function handle_notice($notice) | ||
| 37 | { | ||
| 38 | require_once(INSTALLDIR.'/lib/jabber.php'); | ||
| 39 | try { | ||
| 40 | return jabber_public_notice($notice); | ||
| 41 | } catch (XMPPHP_Exception $e) { | ||
| 42 | $this->log(LOG_ERR, "Got an XMPPHP_Exception: " . $e->getMessage()); | ||
| 43 | die($e->getMessage()); | ||
| 44 | } | ||
| 45 | return true; | ||
| 46 | } | ||
| 47 | } |
lib/queuehandler.php
(23 / 77)
|   | |||
| 19 | 19 | ||
| 20 | 20 | if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } | |
| 21 | 21 | ||
| 22 | require_once(INSTALLDIR.'/lib/daemon.php'); | ||
| 23 | require_once(INSTALLDIR.'/classes/Queue_item.php'); | ||
| 24 | require_once(INSTALLDIR.'/classes/Notice.php'); | ||
| 25 | |||
| 26 | define('CLAIM_TIMEOUT', 1200); | ||
| 27 | define('QUEUE_HANDLER_MISS_IDLE', 10); | ||
| 28 | define('QUEUE_HANDLER_HIT_IDLE', 0); | ||
| 29 | |||
| 30 | 22 | /** | |
| 31 | 23 | * Base class for queue handlers. | |
| 32 | 24 | * | |
| … | … | ||
| 28 | 28 | * | |
| 29 | 29 | * Subclasses must override at least the following methods: | |
| 30 | 30 | * - transport | |
| 31 | * - start | ||
| 32 | * - finish | ||
| 33 | 31 | * - handle_notice | |
| 34 | * | ||
| 35 | * Some subclasses will also want to override the idle handler: | ||
| 36 | * - idle | ||
| 37 | 32 | */ | |
| 38 | class QueueHandler extends Daemon | ||
| 33 | #class QueueHandler extends Daemon | ||
| 34 | class QueueHandler | ||
| 39 | 35 | { | |
| 40 | 36 | ||
| 41 | function __construct($id=null, $daemonize=true) | ||
| 42 | { | ||
| 43 | parent::__construct($daemonize); | ||
| 37 | # function __construct($id=null, $daemonize=true) | ||
| 38 | # { | ||
| 39 | # parent::__construct($daemonize); | ||
| 40 | # | ||
| 41 | # if ($id) { | ||
| 42 | # $this->set_id($id); | ||
| 43 | # } | ||
| 44 | # } | ||
| 44 | 45 | ||
| 45 | if ($id) { | ||
| 46 | $this->set_id($id); | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | 46 | /** | |
| 51 | 47 | * How many seconds a polling-based queue manager should wait between | |
| 52 | 48 | * checks for new items to handle. | |
| 53 | 49 | * | |
| 54 | 50 | * Defaults to 60 seconds; override to speed up or slow down. | |
| 55 | 51 | * | |
| 52 | * @fixme not really compatible with global queue manager | ||
| 56 | 53 | * @return int timeout in seconds | |
| 57 | 54 | */ | |
| 58 | function timeout() | ||
| 59 | { | ||
| 60 | return 60; | ||
| 61 | } | ||
| 55 | # function timeout() | ||
| 56 | # { | ||
| 57 | # return 60; | ||
| 58 | # } | ||
| 62 | 59 | ||
| 63 | function class_name() | ||
| 64 | { | ||
| 65 | return ucfirst($this->transport()) . 'Handler'; | ||
| 66 | } | ||
| 60 | # function class_name() | ||
| 61 | # { | ||
| 62 | # return ucfirst($this->transport()) . 'Handler'; | ||
| 63 | # } | ||
| 67 | 64 | ||
| 68 | function name() | ||
| 69 | { | ||
| 70 | return strtolower($this->class_name().'.'.$this->get_id()); | ||
| 71 | } | ||
| 65 | # function name() | ||
| 66 | # { | ||
| 67 | # return strtolower($this->class_name().'.'.$this->get_id()); | ||
| 68 | # } | ||
| 72 | 69 | ||
| 73 | 70 | /** | |
| 74 | 71 | * Return transport keyword which identifies items this queue handler | |
| … | … | ||
| 82 | 82 | } | |
| 83 | 83 | ||
| 84 | 84 | /** | |
| 85 | * Initialization, run when the queue handler starts. | ||
| 86 | * If this function indicates failure, the handler run will be aborted. | ||
| 87 | * | ||
| 88 | * @fixme run() will abort if this doesn't return true, | ||
| 89 | * but some subclasses don't bother. | ||
| 90 | * @return boolean true on success, false on failure | ||
| 91 | */ | ||
| 92 | function start() | ||
| 93 | { | ||
| 94 | } | ||
| 95 | |||
| 96 | /** | ||
| 97 | * Cleanup, run when the queue handler ends. | ||
| 98 | * If this function indicates failure, a warning will be logged. | ||
| 99 | * | ||
| 100 | * @fixme run() will throw warnings if this doesn't return true, | ||
| 101 | * but many subclasses don't bother. | ||
| 102 | * @return boolean true on success, false on failure | ||
| 103 | */ | ||
| 104 | function finish() | ||
| 105 | { | ||
| 106 | } | ||
| 107 | |||
| 108 | /** | ||
| 109 | 85 | * Here's the meat of your queue handler -- you're handed a Notice | |
| 110 | 86 | * object, which you may do as you will with. | |
| 111 | 87 | * | |
| … | … | ||
| 134 | 134 | return true; | |
| 135 | 135 | } | |
| 136 | 136 | ||
| 137 | /** | ||
| 138 | * Called by QueueHandler after each handled item or empty polling cycle. | ||
| 139 | * This is a good time to e.g. service your XMPP connection. | ||
| 140 | * | ||
| 141 | * Doesn't need to be overridden if there's no maintenance to do. | ||
| 142 | * | ||
| 143 | * @param int $timeout seconds to sleep if there's nothing to do | ||
| 144 | */ | ||
| 145 | function idle($timeout=0) | ||
| 146 | { | ||
| 147 | if ($timeout > 0) { | ||
| 148 | sleep($timeout); | ||
| 149 | } | ||
| 150 | } | ||
| 151 | 137 | ||
| 152 | 138 | function log($level, $msg) | |
| 153 | 139 | { | |
| 154 | 140 | common_log($level, $this->class_name() . ' ('. $this->get_id() .'): '.$msg); | |
| 155 | } | ||
| 156 | |||
| 157 | function getSockets() | ||
| 158 | { | ||
| 159 | return array(); | ||
| 160 | 141 | } | |
| 161 | 142 | } |
lib/queuemanager.php
(141 / 8)
|   | |||
| 2 | 2 | /** | |
| 3 | 3 | * StatusNet, the distributed open-source microblogging tool | |
| 4 | 4 | * | |
| 5 | * Abstract class for queue managers | ||
| 5 | * Abstract class for i/o managers | ||
| 6 | 6 | * | |
| 7 | 7 | * PHP version 5 | |
| 8 | 8 | * | |
| … | … | ||
| 23 | 23 | * @package StatusNet | |
| 24 | 24 | * @author Evan Prodromou <evan@status.net> | |
| 25 | 25 | * @author Sarven Capadisli <csarven@status.net> | |
| 26 | * @copyright 2009 StatusNet, Inc. | ||
| 26 | * @author Brion Vibber <brion@status.net> | ||
| 27 | * @copyright 2009-2010 StatusNet, Inc. | ||
| 27 | 28 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 | |
| 28 | 29 | * @link http://status.net/ | |
| 29 | 30 | */ | |
| 30 | 31 | ||
| 31 | class QueueManager | ||
| 32 | /** | ||
| 33 | * Completed child classes must implement the enqueue() method. | ||
| 34 | * | ||
| 35 | * For background processing, classes should implement either socket-based | ||
| 36 | * input (handleInput(), getSockets()) or idle-loop polling (idle()). | ||
| 37 | */ | ||
| 38 | abstract class QueueManager extends IoManager | ||
| 32 | 39 | { | |
| 33 | 40 | static $qm = null; | |
| 34 | 41 | ||
| 35 | static function get() | ||
| 42 | /** | ||
| 43 | * Factory function to pull the appropriate QueueManager object | ||
| 44 | * for this site's configuration. It can then be used to queue | ||
| 45 | * events for later processing or to spawn a processing loop. | ||
| 46 | * | ||
| 47 | * Plugins can add to the built-in types by hooking StartNewQueueManager. | ||
| 48 | * | ||
| 49 | * @return QueueManager | ||
| 50 | */ | ||
| 51 | public static function get() | ||
| 36 | 52 | { | |
| 37 | 53 | if (empty(self::$qm)) { | |
| 38 | 54 | ||
| … | … | ||
| 78 | 78 | return self::$qm; | |
| 79 | 79 | } | |
| 80 | 80 | ||
| 81 | function enqueue($object, $queue) | ||
| 81 | /** | ||
| 82 | * @fixme wouldn't necessarily work with other class types. | ||
| 83 | * Better to change the interface...? | ||
| 84 | */ | ||
| 85 | public static function multiSite() | ||
| 82 | 86 | { | |
| 83 | throw ServerException("Unimplemented function 'enqueue' called"); | ||
| 87 | if (common_config('queue', 'subsystem') == 'stomp') { | ||
| 88 | return IoManager::INSTANCE_PER_PROCESS; | ||
| 89 | } else { | ||
| 90 | return IoManager::SINGLE_ONLY; | ||
| 91 | } | ||
| 84 | 92 | } | |
| 85 | 93 | ||
| 86 | function service($queue, $handler) | ||
| 94 | function __construct() | ||
| 87 | 95 | { | |
| 88 | throw ServerException("Unimplemented function 'service' called"); | ||
| 96 | $this->initialize(); | ||
| 97 | } | ||
| 98 | |||
| 99 | /** | ||
| 100 | * Store an object (usually/always a Notice) into the given queue | ||
| 101 | * for later processing. No guarantee is made on when it will be | ||
| 102 | * processed; it could be immediately or at some unspecified point | ||
| 103 | * in the future. | ||
| 104 | * | ||
| 105 | * Must be implemented by any queue manager. | ||
| 106 | * | ||
| 107 | * @param Notice $object | ||
| 108 | * @param string $queue | ||
| 109 | */ | ||
| 110 | abstract function enqueue($object, $queue); | ||
| 111 | |||
| 112 | /** | ||
| 113 | * Instantiate the appropriate QueueHandler class for the given queue. | ||
| 114 | * | ||
| 115 | * @param string $queue | ||
| 116 | * @return mixed QueueHandler or null | ||
| 117 | */ | ||
| 118 | function getHandler($queue) | ||
| 119 | { | ||
| 120 | if (isset($this->handlers[$queue])) { | ||
| 121 | $class = $this->handlers[$queue]; | ||
| 122 | if (class_exists($class)) { | ||
| 123 | return new $class(); | ||
| 124 | } else { | ||
| 125 | common_log(LOG_ERR, "Nonexistent handler class '$class' for queue '$queue'"); | ||
| 126 | } | ||
| 127 | } else { | ||
| 128 | common_log(LOG_ERR, "Requested handler for unkown queue '$queue'"); | ||
| 129 | } | ||
| 130 | return null; | ||
| 131 | } | ||
| 132 | |||
| 133 | /** | ||
| 134 | * Get a list of all registered queue transport names. | ||
| 135 | * | ||
| 136 | * @return array of strings | ||
| 137 | */ | ||
| 138 | function getQueues() | ||
| 139 | { | ||
| 140 | return array_keys($this->handlers); | ||
| 141 | } | ||
| 142 | |||
| 143 | /** | ||
| 144 | * Initialize the list of queue handlers | ||
| 145 | * | ||
| 146 | * @event StartInitializeQueueManager | ||
| 147 | * @event EndInitializeQueueManager | ||
| 148 | */ | ||
| 149 | function initialize() | ||
| 150 | { | ||
| 151 | if (Event::handle('StartInitializeQueueManager', array($this))) { | ||
| 152 | $this->connect('plugin', 'PluginQueueHandler'); | ||
| 153 | $this->connect('omb', 'OmbQueueHandler'); | ||
| 154 | $this->connect('ping', 'PingQueueHandler'); | ||
| 155 | if (common_config('sms', 'enabled')) { | ||
| 156 | $this->connect('sms', 'SmsQueueHandler'); | ||
| 157 | } | ||
| 158 | |||
| 159 | // XMPP output handlers... | ||
| 160 | if (common_config('xmpp', 'enabled')) { | ||
| 161 | $this->connect('jabber', 'JabberQueueHandler'); | ||
| 162 | $this->connect('public', 'PublicQueueHandler'); | ||
| 163 | |||
| 164 | // @fixme this should move up a level or should get an actual queue | ||
| 165 | $this->connect('confirm', 'XmppConfirmHandler'); | ||
| 166 | } | ||
| 167 | |||
| 168 | // For compat with old plugins not registering their own handlers. | ||
| 169 | $this->connect('plugin', 'PluginQueueHandler'); | ||
| 170 | } | ||
| 171 | Event::handle('EndInitializeQueueManager', array($this)); | ||
| 172 | } | ||
| 173 | |||
| 174 | /** | ||
| 175 | * Register a queue transport name and handler class for your plugin. | ||
| 176 | * Only registered transports will be reliably picked up! | ||
| 177 | * | ||
| 178 | * @param string $transport | ||
| 179 | * @param string $class | ||
| 180 | */ | ||
| 181 | public function connect($transport, $class) | ||
| 182 | { | ||
| 183 | $this->handlers[$transport] = $class; | ||
| 184 | } | ||
| 185 | |||
| 186 | /** | ||
| 187 | * Send a statistic ping to the queue monitoring system, | ||
| 188 | * optionally with a per-queue id. | ||
| 189 | * | ||
| 190 | * @param string $key | ||
| 191 | * @param string $queue | ||
| 192 | */ | ||
| 193 | function stats($key, $queue=false) | ||
| 194 | { | ||
| 195 | $owners = array(); | ||
| 196 | if ($queue) { | ||
| 197 | $owners[] = "queue:$queue"; | ||
| 198 | $owners[] = "site:" . common_config('site', 'server'); | ||
| 199 | } | ||
| 200 | if (isset($this->master)) { | ||
| 201 | $this->master->stats($key, $owners); | ||
| 202 | } else { | ||
| 203 | $monitor = new QueueMonitor(); | ||
| 204 | $monitor->stats($key, $owners); | ||
| 205 | } | ||
| 89 | 206 | } | |
| 90 | 207 | } |
lib/queuemonitor.php
(116 / 0)
|   | |||
| 1 | <?php | ||
| 2 | /** | ||
| 3 | * StatusNet, the distributed open-source microblogging tool | ||
| 4 | * | ||
| 5 | * Monitoring output helper for IoMaster and IoManager/QueueManager | ||
| 6 | * | ||
| 7 | * PHP version 5 | ||
| 8 | * | ||
| 9 | * LICENCE: This program is free software: you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU Affero General Public License as published by | ||
| 11 | * the Free Software Foundation, either version 3 of the License, or | ||
| 12 | * (at your option) any later version. | ||
| 13 | * | ||
| 14 | * This program is distributed in the hope that it will be useful, | ||
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | * GNU Affero General Public License for more details. | ||
| 18 | * | ||
| 19 | * You should have received a copy of the GNU Affero General Public License | ||
| 20 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 21 | * | ||
| 22 | * @category QueueManager | ||
| 23 | * @package StatusNet | ||
| 24 | * @author Brion Vibber <brion@status.net> | ||
| 25 | * @copyright 2010 StatusNet, Inc. | ||
| 26 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 | ||
| 27 | * @link http://status.net/ | ||
| 28 | */ | ||
| 29 | |||
| 30 | class QueueMonitor | ||
| 31 | { | ||
| 32 | protected $monSocket = null; | ||
| 33 | |||
| 34 | /** | ||
| 35 | * Increment monitoring statistics for a given counter, if configured. | ||
| 36 | * Only explicitly listed thread/site/queue owners will be incremented. | ||
| 37 | * | ||
| 38 | * @param string $key counter name | ||
| 39 | * @param array $owners list of owner keys like 'queue:jabber' or 'site:stat01' | ||
| 40 | */ | ||
| 41 | public function stats($key, $owners=array()) | ||
| 42 | { | ||
| 43 | $this->ping(array('counter' => $key, | ||
| 44 | 'owners' => $owners)); | ||
| 45 | } | ||
| 46 | |||
| 47 | /** | ||
| 48 | * Send thread state update to the monitoring server, if configured. | ||
| 49 | * | ||
| 50 | * @param string $thread ID (eg 'generic.1') | ||
| 51 | * @param string $state ('init', 'queue', 'shutdown' etc) | ||
| 52 | * @param string $substate (optional, eg queue name 'omb' 'sms' etc) | ||
| 53 | */ | ||
| 54 | public function logState($threadId, $state, $substate='') | ||
| 55 | { | ||
| 56 | $this->ping(array('thread_id' => $threadId, | ||
| 57 | 'state' => $state, | ||
| 58 | 'substate' => $substate, | ||
| 59 | 'ts' => microtime(true))); | ||
| 60 | } | ||
| 61 | |||
| 62 | /** | ||
| 63 | * General call to the monitoring server | ||
| 64 | */ | ||
| 65 | protected function ping($data) | ||
| 66 | { | ||
| 67 | $target = common_config('queue', 'monitor'); | ||
| 68 | if (empty($target)) { | ||
| 69 | return; | ||
| 70 | } | ||
| 71 | |||
| 72 | $data = $this->prepMonitorData($data); | ||
| 73 | |||
| 74 | if (substr($target, 0, 4) == 'udp:') { | ||
| 75 | $this->pingUdp($target, $data); | ||
| 76 | } else if (substr($target, 0, 5) == 'http:') { | ||
| 77 | $this->pingHttp($target, $data); | ||
| 78 | } else { | ||
| 79 | common_log(LOG_ERR, __METHOD__ . ' unknown monitor target type ' . $target); | ||
| 80 | } | ||
| 81 | } | ||
| 82 | |||
| 83 | protected function pingUdp($target, $data) | ||
| 84 | { | ||
| 85 | if (!$this->monSocket) { | ||
| 86 | $this->monSocket = stream_socket_client($target, $errno, $errstr); | ||
| 87 | } | ||
| 88 | if ($this->monSocket) { | ||
| 89 | $post = http_build_query($data, '', '&'); | ||
| 90 | stream_socket_sendto($this->monSocket, $post); | ||
| 91 | } else { | ||
| 92 | common_log(LOG_ERR, __METHOD__ . " UDP logging fail: $errstr"); | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | protected function pingHttp($target, $data) | ||
| 97 | { | ||
| 98 | $client = new HTTPClient(); | ||
| 99 | $result = $client->post($target, array(), $data); | ||
| 100 | |||
| 101 | if (!$result->isOk()) { | ||
| 102 | common_log(LOG_ERR, __METHOD__ . ' HTTP ' . $result->getStatus() . | ||
| 103 | ': ' . $result->getBody()); | ||
| 104 | } | ||
| 105 | } | ||
| 106 | |||
| 107 | protected function prepMonitorData($data) | ||
| 108 | { | ||
| 109 | #asort($data); | ||
| 110 | #$macdata = http_build_query($data, '', '&'); | ||
| 111 | #$key = 'This is a nice old key'; | ||
| 112 | #$data['hmac'] = hash_hmac('sha256', $macdata, $key); | ||
| 113 | return $data; | ||
| 114 | } | ||
| 115 | |||
| 116 | } |
lib/smsqueuehandler.php
(39 / 0)
|   | |||
| 1 | <?php | ||
| 2 | /* | ||
| 3 | * StatusNet - the distributed open-source microblogging tool | ||
| 4 | * Copyright (C) 2008, 2009, StatusNet, Inc. | ||
| 5 | * | ||
| 6 | * This program is free software: you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU Affero General Public License as published by | ||
| 8 | * the Free Software Foundation, either version 3 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU Affero General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Affero General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | if (!defined('STATUSNET') && !defined('LACONICA')) { | ||
| 21 | exit(1); | ||
| 22 | } | ||
| 23 | |||
| 24 | /** | ||
| 25 | * Queue handler for pushing new notices to local subscribers using SMS. | ||
| 26 | */ | ||
| 27 | class SmsQueueHandler extends QueueHandler | ||
| 28 | { | ||
| 29 | function transport() | ||
| 30 | { | ||
| 31 | return 'sms'; | ||
| 32 | } | ||
| 33 | |||
| 34 | function handle_notice($notice) | ||
| 35 | { | ||
| 36 | require_once(INSTALLDIR.'/lib/mail.php'); | ||
| 37 | return mail_broadcast_notice_sms($notice); | ||
| 38 | } | ||
| 39 | } |
lib/statusnet.php
(295 / 0)
|   | |||
| 1 | <?php | ||
| 2 | /* | ||
| 3 | * StatusNet - the distributed open-source microblogging tool | ||
| 4 | * Copyright (C) 2009, StatusNet, Inc. | ||
| 5 | * | ||
| 6 | * This program is free software: you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU Affero General Public License as published by | ||
| 8 | * the Free Software Foundation, either version 3 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU Affero General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Affero General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } | ||
| 21 | |||
| 22 | global $config, $_server, $_path; | ||
| 23 | |||
| 24 | /** | ||
| 25 | * Global configuration setup and management. | ||
| 26 | */ | ||
| 27 | class StatusNet | ||
| 28 | { | ||
| 29 | protected static $have_config; | ||
| 30 | |||
| 31 | /** | ||
| 32 | * Configure and instantiate a plugin into the current configuration. | ||
| 33 | * Class definitions will be loaded from standard paths if necessary. | ||
| 34 | * Note that initialization events won't be fired until later. | ||
| 35 | * | ||
| 36 | * @param string $name class name & plugin file/subdir name | ||
| 37 | * @param array $attrs key/value pairs of public attributes to set on plugin instance | ||
| 38 | * | ||
| 39 | * @throws ServerException if plugin can't be found | ||
| 40 | */ | ||
| 41 | public static function addPlugin($name, $attrs = null) | ||
| 42 | { | ||
| 43 | $name = ucfirst($name); | ||
| 44 | $pluginclass = "{$name}Plugin"; | ||
| 45 | |||
| 46 | if (!class_exists($pluginclass)) { | ||
| 47 | |||
| 48 | $files = array("local/plugins/{$pluginclass}.php", | ||
| 49 | "local/plugins/{$name}/{$pluginclass}.php", | ||
| 50 | "local/{$pluginclass}.php", | ||
| 51 | "local/{$name}/{$pluginclass}.php", | ||
| 52 | "plugins/{$pluginclass}.php", | ||
| 53 | "plugins/{$name}/{$pluginclass}.php"); | ||
| 54 | |||
| 55 | foreach ($files as $file) { | ||
| 56 | $fullpath = INSTALLDIR.'/'.$file; | ||
| 57 | if (@file_exists($fullpath)) { | ||
| 58 | include_once($fullpath); | ||
| 59 | break; | ||
| 60 | } | ||
| 61 | } | ||
| 62 | if (!class_exists($pluginclass)) { | ||
| 63 | throw new ServerException(500, "Plugin $name not found."); | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | $inst = new $pluginclass(); | ||
| 68 | if (!empty($attrs)) { | ||
| 69 | foreach ($attrs as $aname => $avalue) { | ||
| 70 | $inst->$aname = $avalue; | ||
| 71 | } | ||
| 72 | } | ||
| 73 | return true; | ||
| 74 | } | ||
| 75 | |||
| 76 | /** | ||
| 77 | * Initialize, or re-initialize, StatusNet global configuration | ||
| 78 | * and plugins. | ||
| 79 | * | ||
| 80 | * If switching site configurations during script execution, be | ||
| 81 | * careful when working with leftover objects -- global settings | ||
| 82 | * affect many things and they may not behave as you expected. | ||
| 83 | * | ||
| 84 | * @param $server optional web server hostname for picking config | ||
| 85 | * @param $path optional URL path for picking config | ||
| 86 | * @param $conffile optional configuration file path | ||
| 87 | * | ||
| 88 | * @throws NoConfigException if config file can't be found | ||
| 89 | */ | ||
| 90 | public static function init($server=null, $path=null, $conffile=null) | ||
| 91 | { | ||
| 92 | StatusNet::initDefaults($server, $path); | ||
| 93 | StatusNet::loadConfigFile($conffile); | ||
| 94 | |||
| 95 | // Load settings from database; note we need autoload for this | ||
| 96 | Config::loadSettings(); | ||
| 97 | |||
| 98 | self::initPlugins(); | ||
| 99 | } | ||
| 100 | |||
| 101 | /** | ||
| 102 | * Fire initialization events for all instantiated plugins. | ||
| 103 | */ | ||
| 104 | protected static function initPlugins() | ||
| 105 | { | ||
| 106 | // Load default plugins | ||
| 107 | foreach (common_config('plugins', 'default') as $name => $params) { | ||
| 108 | if (is_null($params)) { | ||
| 109 | addPlugin($name); | ||
| 110 | } else if (is_array($params)) { | ||
| 111 | if (count($params) == 0) { | ||
| 112 | addPlugin($name); | ||
| 113 | } else { | ||
| 114 | $keys = array_keys($params); | ||
| 115 | if (is_string($keys[0])) { | ||
| 116 | addPlugin($name, $params); | ||
| 117 | } else { | ||
| 118 | foreach ($params as $paramset) { | ||
| 119 | addPlugin($name, $paramset); | ||
| 120 | } | ||
| 121 | } | ||
| 122 | } | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | // XXX: if plugins should check the schema at runtime, do that here. | ||
| 127 | if (common_config('db', 'schemacheck') == 'runtime') { | ||
| 128 | Event::handle('CheckSchema'); | ||
| 129 | } | ||
| 130 | |||
| 131 | // Give plugins a chance to initialize in a fully-prepared environment | ||
| 132 | Event::handle('InitializePlugin'); | ||
| 133 | } | ||
| 134 | |||
| 135 | /** | ||
| 136 | * Quick-check if configuration has been established. | ||
| 137 | * Useful for functions which may get used partway through | ||
| 138 | * initialization to back off from fancier things. | ||
| 139 | * | ||
| 140 | * @return bool | ||
| 141 | */ | ||
| 142 | public function haveConfig() | ||
| 143 | { | ||
| 144 | return self::$have_config; | ||
| 145 | } | ||
| 146 | |||
| 147 | /** | ||
| 148 | * Build default configuration array | ||
| 149 | * @return array | ||
| 150 | */ | ||
| 151 | protected static function defaultConfig() | ||
| 152 | { | ||
| 153 | global $_server, $_path; | ||
| 154 | require(INSTALLDIR.'/lib/default.php'); | ||
| 155 | return $default; | ||
| 156 | } | ||
| 157 | |||
| 158 | /** | ||
| 159 | * Establish default configuration based on given or default server and path | ||
| 160 | * Sets global $_server, $_path, and $config | ||
| 161 | */ | ||
| 162 | protected static function initDefaults($server, $path) | ||
| 163 | { | ||
| 164 | global $_server, $_path, $config; | ||
| 165 | |||
| 166 | Event::clearHandlers(); | ||
| 167 | |||
| 168 | // try to figure out where we are. $server and $path | ||
| 169 | // can be set by including module, else we guess based | ||
| 170 | // on HTTP info. | ||
| 171 | |||
| 172 | if (isset($server)) { | ||
| 173 | $_server = $server; | ||
| 174 | } else { | ||
| 175 | $_server = array_key_exists('SERVER_NAME', $_SERVER) ? | ||
| 176 | strtolower($_SERVER['SERVER_NAME']) : | ||
| 177 | null; | ||
| 178 | } | ||
| 179 | |||
| 180 | if (isset($path)) { | ||
| 181 | $_path = $path; | ||
| 182 | } else { | ||
| 183 | $_path = (array_key_exists('SERVER_NAME', $_SERVER) && array_key_exists('SCRIPT_NAME', $_SERVER)) ? | ||
| 184 | self::_sn_to_path($_SERVER['SCRIPT_NAME']) : | ||
| 185 | null; | ||
| 186 | } | ||
| 187 | |||
| 188 | // Set config values initially to default values | ||
| 189 | $default = self::defaultConfig(); | ||
| 190 | $config = $default; | ||
| 191 | |||
| 192 | // default configuration, overwritten in config.php | ||
| 193 | // Keep DB_DataObject's db config synced to ours... | ||
| 194 | |||
| 195 | $config['db'] = &PEAR::getStaticProperty('DB_DataObject','options'); | ||
| 196 | |||
| 197 | $config['db'] = $default['db']; | ||
| 198 | |||
| 199 | // Backward compatibility | ||
| 200 | |||
| 201 | $config['site']['design'] =& $config['design']; | ||
| 202 | |||
| 203 | if (function_exists('date_default_timezone_set')) { | ||
| 204 | /* Work internally in UTC */ | ||
| 205 | date_default_timezone_set('UTC'); | ||
| 206 | } | ||
| 207 | } | ||
| 208 | |||
| 209 | protected function _sn_to_path($sn) | ||
| 210 | { | ||
| 211 | $past_root = substr($sn, 1); | ||
| 212 | $last_slash = strrpos($past_root, '/'); | ||
| 213 | if ($last_slash > 0) { | ||
| 214 | $p = substr($past_root, 0, $last_slash); | ||
| 215 | } else { | ||
| 216 | $p = ''; | ||
| 217 | } | ||
| 218 | return $p; | ||
| 219 | } | ||
| 220 | |||
| 221 | /** | ||
| 222 | * Load the default or specified configuration file. | ||
| 223 | * Modifies global $config and may establish plugins. | ||
| 224 | * | ||
| 225 | * @throws NoConfigException | ||
| 226 | */ | ||
| 227 | protected function loadConfigFile($conffile=null) | ||
| 228 | { | ||
| 229 | global $_server, $_path, $config; | ||
| 230 | |||
| 231 | // From most general to most specific: | ||
| 232 | // server-wide, then vhost-wide, then for a path, | ||
| 233 | // finally for a dir (usually only need one of the last two). | ||
| 234 | |||
| 235 | if (isset($conffile)) { | ||
| 236 | $config_files = array($conffile); | ||
| 237 | } else { | ||
| 238 | $config_files = array('/etc/statusnet/statusnet.php', | ||
| 239 | '/etc/statusnet/laconica.php', | ||
| 240 | '/etc/laconica/laconica.php', | ||
| 241 | '/etc/statusnet/'.$_server.'.php', | ||
| 242 | '/etc/laconica/'.$_server.'.php'); | ||
| 243 | |||
| 244 | if (strlen($_path) > 0) { | ||
| 245 | $config_files[] = '/etc/statusnet/'.$_server.'_'.$_path.'.php'; | ||
| 246 | $config_files[] = '/etc/laconica/'.$_server.'_'.$_path.'.php'; | ||
| 247 | } | ||
| 248 | |||
| 249 | $config_files[] = INSTALLDIR.'/config.php'; | ||
| 250 | } | ||
| 251 | |||
| 252 | self::$have_config = false; | ||
| 253 | |||
| 254 | foreach ($config_files as $_config_file) { | ||
| 255 | if (@file_exists($_config_file)) { | ||
| 256 | include($_config_file); | ||
| 257 | self::$have_config = true; | ||
| 258 | } | ||
| 259 | } | ||
| 260 | |||
| 261 | if (!self::$have_config) { | ||
| 262 | throw new NoConfigException("No configuration file found.", | ||
| 263 | $config_files); | ||
| 264 | } | ||
| 265 | |||
| 266 | // Fixup for statusnet.ini | ||
| 267 | $_db_name = substr($config['db']['database'], strrpos($config['db']['database'], '/') + 1); | ||
| 268 | |||
| 269 | if ($_db_name != 'statusnet' && !array_key_exists('ini_'.$_db_name, $config['db'])) { | ||
| 270 | $config['db']['ini_'.$_db_name] = INSTALLDIR.'/classes/statusnet.ini'; | ||
| 271 | } | ||
| 272 | |||
| 273 | // Backwards compatibility | ||
| 274 | |||
| 275 | if (array_key_exists('memcached', $config)) { | ||
| 276 | if ($config['memcached']['enabled']) { | ||
| 277 | addPlugin('Memcache', array('servers' => $config['memcached']['server'])); | ||
| 278 | } | ||
| 279 | |||
| 280 | if (!empty($config['memcached']['base'])) { | ||
| 281 | $config['cache']['base'] = $config['memcached']['base']; | ||
| 282 | } | ||
| 283 | } | ||
| 284 | } | ||
| 285 | } | ||
| 286 | |||
| 287 | class NoConfigException extends Exception | ||
| 288 | { | ||
| 289 | public $config_files; | ||
| 290 | |||
| 291 | function __construct($msg, $config_files) { | ||
| 292 | parent::__construct($msg); | ||
| 293 | $this->config_files = $config_files; | ||
| 294 | } | ||
| 295 | } |
lib/stompqueuemanager.php
(213 / 72)
|   | |||
| 30 | 30 | ||
| 31 | 31 | require_once 'Stomp.php'; | |
| 32 | 32 | ||
| 33 | class LiberalStomp extends Stomp | ||
| 34 | { | ||
| 35 | function getSocket() | ||
| 36 | { | ||
| 37 | return $this->_socket; | ||
| 38 | } | ||
| 39 | } | ||
| 40 | 33 | ||
| 41 | class StompQueueManager | ||
| 34 | class StompQueueManager extends QueueManager | ||
| 42 | 35 | { | |
| 43 | 36 | var $server = null; | |
| 44 | 37 | var $username = null; | |
| 45 | 38 | var $password = null; | |
| 46 | 39 | var $base = null; | |
| 47 | 40 | var $con = null; | |
| 41 | |||
| 42 | protected $master = null; | ||
| 43 | protected $sites = array(); | ||
| 48 | 44 | ||
| 49 | 45 | function __construct() | |
| 50 | 46 | { | |
| 47 | parent::__construct(); | ||
| 51 | 48 | $this->server = common_config('queue', 'stomp_server'); | |
| 52 | 49 | $this->username = common_config('queue', 'stomp_username'); | |
| 53 | 50 | $this->password = common_config('queue', 'stomp_password'); | |
| 54 | 51 | $this->base = common_config('queue', 'queue_basename'); | |
| 55 | 52 | } | |
| 56 | 53 | ||
| 57 | function _connect() | ||
| 54 | /** | ||
| 55 | * Tell the i/o master we only need a single instance to cover | ||
| 56 | * all sites running in this process. | ||
| 57 | */ | ||
| 58 | public static function multiSite() | ||
| 58 | 59 | { | |
| 59 | if (empty($this->con)) { | ||
| 60 | $this->_log(LOG_INFO, "Connecting to '$this->server' as '$this->username'..."); | ||
| 61 | $this->con = new LiberalStomp($this->server); | ||
| 60 | return IoManager::INSTANCE_PER_PROCESS; | ||
| 61 | } | ||
| 62 | 62 | ||
| 63 | if ($this->con->connect($this->username, $this->password)) { | ||
| 64 | $this->_log(LOG_INFO, "Connected."); | ||
| 65 | } else { | ||
| 66 | $this->_log(LOG_ERR, 'Failed to connect to queue server'); | ||
| 67 | throw new ServerException('Failed to connect to queue server'); | ||
| 68 | } | ||
| 69 | } | ||
| 63 | /** | ||
| 64 | * Record each site we'll be handling input for in this process, | ||
| 65 | * so we can listen to the necessary queues for it. | ||
| 66 | * | ||
| 67 | * @fixme possibly actually do subscription here to save another | ||
| 68 | * loop over all sites later? | ||
| 69 | */ | ||
| 70 | public function addSite($server) | ||
| 71 | { | ||
| 72 | $this->sites[] = $server; | ||
| 70 | 73 | } | |
| 71 | 74 | ||
| 72 | function enqueue($object, $queue) | ||
| 75 | /** | ||
| 76 | * Saves a notice object reference into the queue item table. | ||
| 77 | * @return boolean true on success | ||
| 78 | */ | ||
| 79 | public function enqueue($object, $queue) | ||
| 73 | 80 | { | |
| 74 | 81 | $notice = $object; | |
| 75 | 82 | ||
| … | … | ||
| 84 | 84 | ||
| 85 | 85 | // XXX: serialize and send entire notice | |
| 86 | 86 | ||
| 87 | $result = $this->con->send($this->_queueName($queue), | ||
| 87 | $result = $this->con->send($this->queueName($queue), | ||
| 88 | 88 | $notice->id, // BODY of the message | |
| 89 | 89 | array ('created' => $notice->created)); | |
| 90 | 90 | ||
| … | … | ||
| 95 | 95 | ||
| 96 | 96 | common_log(LOG_DEBUG, 'complete remote queueing notice ID = ' | |
| 97 | 97 | . $notice->id . ' for ' . $queue); | |
| 98 | $this->stats('enqueued', $queue); | ||
| 98 | 99 | } | |
| 99 | 100 | ||
| 100 | function service($queue, $handler) | ||
| 101 | /** | ||
| 102 | * Send any sockets we're listening on to the IO manager | ||
| 103 | * to wait for input. | ||
| 104 | * | ||
| 105 | * @return array of resources | ||
| 106 | */ | ||
| 107 | public function getSockets() | ||
| 101 | 108 | { | |
| 102 | $result = null; | ||
| 109 | return array($this->con->getSocket()); | ||
| 110 | } | ||
| 103 | 111 | ||
| 104 | $this->_connect(); | ||
| 112 | /** | ||
| 113 | * We've got input to handle on our socket! | ||
| 114 | * Read any waiting Stomp frame(s) and process them. | ||
| 115 | * | ||
| 116 | * @param resource $socket | ||
| 117 | * @return boolean ok on success | ||
| 118 | */ | ||
| 119 | public function handleInput($socket) | ||
| 120 | { | ||
| 121 | assert($socket === $this->con->getSocket()); | ||
| 122 | $ok = true; | ||
| 123 | $frames = $this->con->readFrames(); | ||
| 124 | foreach ($frames as $frame) { | ||
| 125 | $ok = $ok && $this->_handleNotice($frame); | ||
| 126 | } | ||
| 127 | return $ok; | ||
| 128 | } | ||
| 105 | 129 | ||
| 106 | $this->con->setReadTimeout($handler->timeout()); | ||
| 130 | /** | ||
| 131 | * Initialize our connection and subscribe to all the queues | ||
| 132 | * we're going to need to handle... | ||
| 133 | * | ||
| 134 | * Side effects: in multi-site mode, may reset site configuration. | ||
| 135 | * | ||
| 136 | * @param IoMaster $master process/event controller | ||
| 137 | * @return bool return false on failure | ||
| 138 | */ | ||
| 139 | public function start($master) | ||
| 140 | { | ||
| 141 | parent::start($master); | ||
| 142 | if ($this->sites) { | ||
| 143 | foreach ($this->sites as $server) { | ||
| 144 | StatusNet::init($server); | ||
| 145 | $this->doSubscribe(); | ||
| 146 | } | ||
| 147 | } else { | ||
| 148 | $this->doSubscribe(); | ||
| 149 | } | ||
| 150 | return true; | ||
| 151 | } | ||
| 152 | |||
| 153 | /** | ||
| 154 | * Subscribe to all the queues we're going to need to handle... | ||
| 155 | * | ||
| 156 | * Side effects: in multi-site mode, may reset site configuration. | ||
| 157 | * | ||
| 158 | * @return bool return false on failure | ||
| 159 | */ | ||
| 160 | public function finish() | ||
| 161 | { | ||
| 162 | if ($this->sites) { | ||
| 163 | foreach ($this->sites as $server) { | ||
| 164 | StatusNet::init($server); | ||
| 165 | $this->doUnsubscribe(); | ||
| 166 | } | ||
| 167 | } else { | ||
| 168 | $this->doUnsubscribe(); | ||
| 169 | } | ||
| 170 | return true; | ||
| 171 | } | ||
| 172 | |||
| 173 | /** | ||
| 174 | * Lazy open connection to Stomp queue server. | ||
| 175 | */ | ||
| 176 | protected function _connect() | ||
| 177 | { | ||
| 178 | if (empty($this->con)) { | ||
| 179 | $this->_log(LOG_INFO, "Connecting to '$this->server' as '$this->username'..."); | ||
| 180 | $this->con = new LiberalStomp($this->server); | ||
| 107 | 181 | ||
| 108 | $this->con->subscribe($this->_queueName($queue)); | ||
| 182 | if ($this->con->connect($this->username, $this->password)) { | ||
| 183 | $this->_log(LOG_INFO, "Connected."); | ||
| 184 | } else { | ||
| 185 | $this->_log(LOG_ERR, 'Failed to connect to queue server'); | ||
| 186 | throw new ServerException('Failed to connect to queue server'); | ||
| 187 | } | ||
| 188 | } | ||
| 189 | } | ||
| 109 | 190 | ||
| 110 | while (true) { | ||
| 191 | /** | ||
| 192 | * Subscribe to all enabled notice queues for the current site. | ||
| 193 | */ | ||
| 194 | protected function doSubscribe() | ||
| 195 | { | ||
| 196 | $this->_connect(); | ||
| 197 | foreach ($this->getQueues() as $queue) { | ||
| 198 | $rawqueue = $this->queueName($queue); | ||
| 199 | $this->_log(LOG_INFO, "Subscribing to $rawqueue"); | ||
| 200 | $this->con->subscribe($rawqueue); | ||
| 201 | } | ||
| 202 | } | ||
| 203 | |||
| 204 | /** | ||
| 205 | * Subscribe from all enabled notice queues for the current site. | ||
| 206 | */ | ||
| 207 | protected function doUnsubscribe() | ||
| 208 | { | ||
| 209 | $this->_connect(); | ||
| 210 | foreach ($this->getQueues() as $queue) { | ||
| 211 | $this->con->unsubscribe($this->queueName($queue)); | ||
| 212 | } | ||
| 213 | } | ||
| 111 | 214 | ||
| 112 | // Wait for something on one of our sockets | ||
| 215 | /** | ||
| 216 | * Handle and acknowledge a notice event that's come in through a queue. | ||
| 217 | * | ||
| 218 | * If the queue handler reports failure, the message is requeued for later. | ||
| 219 | * Missing notices or handler classes will drop the message. | ||
| 220 | * | ||
| 221 | * Side effects: in multi-site mode, may reset site configuration to | ||
| 222 | * match the site that queued the event. | ||
| 223 | * | ||
| 224 | * @param StompFrame $frame | ||
| 225 | * @return bool | ||
| 226 | */ | ||
| 227 | protected function _handleNotice($frame) | ||
| 228 | { | ||
| 229 | list($site, $queue) = $this->parseDestination($frame->headers['destination']); | ||
| 230 | if ($site != common_config('site', 'server')) { | ||
| 231 | $this->stats('switch'); | ||
| 232 | StatusNet::init($site); | ||
| 233 | } | ||
| 113 | 234 | ||
| 114 | $stompsock = $this->con->getSocket(); | ||
| 235 | $id = intval($frame->body); | ||
| 236 | $info = "notice $id posted at {$frame->headers['created']} in queue $queue"; | ||
| 115 | 237 | ||
| 116 | $handsocks = $handler->getSockets(); | ||
| 238 | $notice = Notice::staticGet('id', $id); | ||
| 239 | if (empty($notice)) { | ||
| 240 | $this->_log(LOG_WARNING, "Skipping missing $info"); | ||
| 241 | $this->con->ack($frame); | ||
| 242 | $this->stats('badnotice', $queue); | ||
| 243 | return false; | ||
| 244 | } | ||
| 117 | 245 | ||
| 118 | $socks = array_merge(array($stompsock), $handsocks); | ||
| 246 | $handler = $this->getHandler($queue); | ||
| 247 | if (!$handler) { | ||
| 248 | $this->_log(LOG_ERROR, "Missing handler class; skipping $info"); | ||
| 249 | $this->con->ack($frame); | ||
| 250 | $this->stats('badhandler', $queue); | ||
| 251 | return false; | ||
| 252 | } | ||
| 119 | 253 | ||
| 120 | $read = $socks; | ||
| 121 | $write = array(); | ||
| 122 | $except = array(); | ||
| 254 | $ok = $handler->handle_notice($notice); | ||
| 123 | 255 | ||
| 124 | $ready = stream_select($read, $write, $except, $handler->timeout(), 0); | ||
| 125 | |||
| 126 | if ($ready === false) { | ||
| 127 | $this->_log(LOG_ERR, "Error selecting on sockets"); | ||
| 128 | } else if ($ready > 0) { | ||
| 129 | if (in_array($stompsock, $read)) { | ||
| 130 | $this->_handleNotice($queue, $handler); | ||
| 131 | } | ||
| 132 | $handler->idle(QUEUE_HANDLER_HIT_IDLE); | ||
| 133 | } | ||
| 256 | if (!$ok) { | ||
| 257 | $this->_log(LOG_WARNING, "Failed handling $info"); | ||
| 258 | // FIXME we probably shouldn't have to do | ||
| 259 | // this kind of queue management ourselves; | ||
| 260 | // if we don't ack, it should resend... | ||
| 261 | $this->con->ack($frame); | ||
| 262 | $this->enqueue($notice, $queue); | ||
| 263 | $this->stats('requeued', $queue); | ||
| 264 | return false; | ||
| 134 | 265 | } | |
| 135 | 266 | ||
| 136 | $this->con->unsubscribe($this->_queueName($queue)); | ||
| 267 | $this->_log(LOG_INFO, "Successfully handled $info"); | ||
| 268 | $this->con->ack($frame); | ||
| 269 | $this->stats('handled', $queue); | ||
| 270 | return true; | ||
| 137 | 271 | } | |
| 138 | 272 | ||
| 139 | function _handleNotice($queue, $handler) | ||
| 273 | /** | ||
| 274 | * Combines the queue_basename from configuration with the | ||
| 275 | * site server name and queue name to give eg: | ||
| 276 | * | ||
| 277 | * /queue/statusnet/identi.ca/sms | ||
| 278 | * | ||
| 279 | * @param string $queue | ||
| 280 | * @return string | ||
| 281 | */ | ||
| 282 | protected function queueName($queue) | ||
| 140 | 283 | { | |
| 141 | $frame = $this->con->readFrame(); | ||
| 142 | |||
| 143 | if (!empty($frame)) { | ||
| 144 | $notice = Notice::staticGet('id', $frame->body); | ||
| 145 | |||
| 146 | if (empty($notice)) { | ||
| 147 | $this->_log(LOG_WARNING, 'Got ID '. $frame->body .' for non-existent notice in queue '. $queue); | ||
| 148 | $this->con->ack($frame); | ||
| 149 | } else { | ||
| 150 | if ($handler->handle_notice($notice)) { | ||
| 151 | $this->_log(LOG_INFO, 'Successfully handled notice '. $notice->id .' posted at ' . $frame->headers['created'] . ' in queue '. $queue); | ||
| 152 | $this->con->ack($frame); | ||
| 153 | } else { | ||
| 154 | $this->_log(LOG_WARNING, 'Failed handling notice '. $notice->id .' posted at ' . $frame->headers['created'] . ' in queue '. $queue); | ||
| 155 | // FIXME we probably shouldn't have to do | ||
| 156 | // this kind of queue management ourselves | ||
| 157 | $this->con->ack($frame); | ||
| 158 | $this->enqueue($notice, $queue); | ||
| 159 | } | ||
| 160 | unset($notice); | ||
| 161 | } | ||
| 162 | |||
| 163 | unset($frame); | ||
| 164 | } | ||
| 284 | return common_config('queue', 'queue_basename') . | ||
| 285 | common_config('site', 'server') . '/' . $queue; | ||
| 165 | 286 | } | |
| 166 | 287 | ||
| 167 | function _queueName($queue) | ||
| 288 | /** | ||
| 289 | * Returns the site and queue name from the server-side queue. | ||
| 290 | * | ||
| 291 | * @param string queue destination (eg '/queue/statusnet/identi.ca/sms') | ||
| 292 | * @return array of site and queue: ('identi.ca','sms') or false if unrecognized | ||
| 293 | */ | ||
| 294 | protected function parseDestination($dest) | ||
| 168 | 295 | { | |
| 169 | return common_config('queue', 'queue_basename') . $queue; | ||
| 296 | $prefix = common_config('queue', 'queue_basename'); | ||
| 297 | if (substr($dest, 0, strlen($prefix)) == $prefix) { | ||
| 298 | $rest = substr($dest, strlen($prefix)); | ||
| 299 | return explode("/", $rest, 2); | ||
| 300 | } else { | ||
| 301 | common_log(LOG_ERR, "Got a message from unrecognized stomp queue: $dest"); | ||
| 302 | return array(false, false); | ||
| 303 | } | ||
| 170 | 304 | } | |
| 171 | 305 | ||
| 172 | 306 | function _log($level, $msg) |
lib/unqueuemanager.php
(17 / 39)
|   | |||
| 23 | 23 | * @package StatusNet | |
| 24 | 24 | * @author Evan Prodromou <evan@status.net> | |
| 25 | 25 | * @author Sarven Capadisli <csarven@status.net> | |
| 26 | * @author Brion Vibber <brion@status.net> | ||
| 26 | 27 | * @copyright 2009 StatusNet, Inc. | |
| 27 | 28 | * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 | |
| 28 | 29 | * @link http://status.net/ | |
| 29 | 30 | */ | |
| 30 | 31 | ||
| 31 | class UnQueueManager | ||
| 32 | class UnQueueManager extends QueueManager | ||
| 32 | 33 | { | |
| 34 | |||
| 35 | /** | ||
| 36 | * Dummy queue storage manager: instead of saving events for later, | ||
| 37 | * we just process them immediately. This is only suitable for events | ||
| 38 | * that can be processed quickly and don't need polling or long-running | ||
| 39 | * connections to another server such as XMPP. | ||
| 40 | * | ||
| 41 | * @param Notice $object | ||
| 42 | * @param string $queue | ||
| 43 | */ | ||
| 33 | 44 | function enqueue($object, $queue) | |
| 34 | 45 | { | |
| 35 | 46 | $notice = $object; | |
| 36 | |||
| 37 | switch ($queue) | ||
| 38 | { | ||
| 39 | case 'omb': | ||
| 40 | if ($this->_isLocal($notice)) { | ||
| 41 | require_once(INSTALLDIR.'/lib/omb.php'); | ||
| 42 | omb_broadcast_notice($notice); | ||
| 43 | } | ||
| 44 | break; | ||
| 45 | case 'public': | ||
| 46 | if ($this->_isLocal($notice)) { | ||
| 47 | require_once(INSTALLDIR.'/lib/jabber.php'); | ||
| 48 | jabber_public_notice($notice); | ||
| 49 | } | ||
| 50 | break; | ||
| 51 | case 'ping': | ||
| 52 | if ($this->_isLocal($notice)) { | ||
| 53 | require_once INSTALLDIR . '/lib/ping.php'; | ||
| 54 | return ping_broadcast_notice($notice); | ||
| 55 | } | ||
| 56 | case 'sms': | ||
| 57 | require_once(INSTALLDIR.'/lib/mail.php'); | ||
| 58 | mail_broadcast_notice_sms($notice); | ||
| 59 | break; | ||
| 60 | case 'jabber': | ||
| 61 | require_once(INSTALLDIR.'/lib/jabber.php'); | ||
| 62 | jabber_broadcast_notice($notice); | ||
| 63 | break; | ||
| 64 | case 'plugin': | ||
| 65 | Event::handle('HandleQueuedNotice', array(&$notice)); | ||
| 66 | break; | ||
| 67 | default: | ||
| 47 | |||
| 48 | $handler = $this->getHandler($queue); | ||
| 49 | if ($handler) { | ||
| 50 | $handler->handle_notice($notice); | ||
| 51 | } else { | ||
| 68 | 52 | if (Event::handle('UnqueueHandleNotice', array(&$notice, $queue))) { | |
| 69 | 53 | throw new ServerException("UnQueueManager: Unknown queue: $queue"); | |
| 70 | 54 | } | |
| 71 | 55 | } | |
| 72 | } | ||
| 73 | |||
| 74 | function _isLocal($notice) | ||
| 75 | { | ||
| 76 | return ($notice->is_local == Notice::LOCAL_PUBLIC || | ||
| 77 | $notice->is_local == Notice::LOCAL_NONPUBLIC); | ||
| 78 | 56 | } | |
| 79 | 57 | } |
lib/util.php
(3 / 2)
|   | |||
| 1132 | 1132 | function common_request_id() | |
| 1133 | 1133 | { | |
| 1134 | 1134 | $pid = getmypid(); | |
| 1135 | $server = common_config('site', 'server'); | ||
| 1135 | 1136 | if (php_sapi_name() == 'cli') { | |
| 1136 | return $pid; | ||
| 1137 | return "$server:$pid"; | ||
| 1137 | 1138 | } else { | |
| 1138 | 1139 | static $req_id = null; | |
| 1139 | 1140 | if (!isset($req_id)) { | |
| … | … | ||
| 1144 | 1144 | $url = $_SERVER['REQUEST_URI']; | |
| 1145 | 1145 | } | |
| 1146 | 1146 | $method = $_SERVER['REQUEST_METHOD']; | |
| 1147 | return "$pid.$req_id $method $url"; | ||
| 1147 | return "$server:$pid.$req_id $method $url"; | ||
| 1148 | 1148 | } | |
| 1149 | 1149 | } | |
| 1150 | 1150 |
lib/xmppconfirmmanager.php
(168 / 0)
|   | |||
| 1 | <?php | ||
| 2 | /* | ||
| 3 | * StatusNet - the distributed open-source microblogging tool | ||
| 4 | * Copyright (C) 2008-2010 StatusNet, Inc. | ||
| 5 | * | ||
| 6 | * This program is free software: you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU Affero General Public License as published by | ||
| 8 | * the Free Software Foundation, either version 3 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU Affero General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Affero General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | if (!defined('STATUSNET') && !defined('LACONICA')) { | ||
| 21 | exit(1); | ||
| 22 | } | ||
| 23 | |||
| 24 | /** | ||
| 25 | * Event handler for pushing new confirmations to Jabber users. | ||
| 26 | * @fixme recommend redoing this on a queue-trigger model | ||
| 27 | * @fixme expiration of old items got dropped in the past, put it back? | ||
| 28 | */ | ||
| 29 | class XmppConfirmManager extends IoManager | ||
| 30 | { | ||
| 31 | |||
| 32 | /** | ||
| 33 | * @return mixed XmppConfirmManager, or false if unneeded | ||
| 34 | */ | ||
| 35 | public static function get() | ||
| 36 | { | ||
| 37 | if (common_config('xmpp', 'enabled')) { | ||
| 38 | $site = common_config('site', 'server'); | ||
| 39 | return new XmppConfirmManager(); | ||
| 40 | } else { | ||
| 41 | return false; | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | /** | ||
| 46 | * Tell the i/o master we need one instance for each supporting site | ||
| 47 | * being handled in this process. | ||
| 48 | */ | ||
| 49 | public static function multiSite() | ||
| 50 | { | ||
| 51 | return IoManager::INSTANCE_PER_SITE; | ||
| 52 | } | ||
| 53 | |||
| 54 | function __construct() | ||
| 55 | { | ||
| 56 | $this->site = common_config('site', 'server'); | ||
| 57 | } | ||
| 58 | |||
| 59 | /** | ||
| 60 | * 10 seconds? Really? That seems a bit frequent. | ||
| 61 | */ | ||
| 62 | function pollInterval() | ||
| 63 | { | ||
| 64 | return 10; | ||
| 65 | } | ||
| 66 | |||
| 67 | /** | ||
| 68 | * Ping! | ||
| 69 | * @return boolean true if we found something | ||
| 70 | */ | ||
| 71 | function poll() | ||
| 72 | { | ||
| 73 | $this->switchSite(); | ||
| 74 | $confirm = $this->next_confirm(); | ||
| 75 | if ($confirm) { | ||
| 76 | $this->handle_confirm($confirm); | ||
| 77 | return true; | ||
| 78 | } else { | ||
| 79 | return false; | ||
| 80 | } | ||
| 81 | } | ||
| 82 | |||
| 83 | protected function handle_confirm($confirm) | ||
| 84 | { | ||
| 85 | require_once INSTALLDIR . '/lib/jabber.php'; | ||
| 86 | |||
| 87 | common_log(LOG_INFO, 'Sending confirmation for ' . $confirm->address); | ||
| 88 | $user = User::staticGet($confirm->user_id); | ||
| 89 | if (!$user) { | ||
| 90 | common_log(LOG_WARNING, 'Confirmation for unknown user ' . $confirm->user_id); | ||
| 91 | return; | ||
| 92 | } | ||
| 93 | $success = jabber_confirm_address($confirm->code, | ||
| 94 | $user->nickname, | ||
| 95 | $confirm->address); | ||
| 96 | if (!$success) { | ||
| 97 | common_log(LOG_ERR, 'Confirmation failed for ' . $confirm->address); | ||
| 98 | # Just let the claim age out; hopefully things work then | ||
| 99 | return; | ||
| 100 | } else { | ||
| 101 | common_log(LOG_INFO, 'Confirmation sent for ' . $confirm->address); | ||
| 102 | # Mark confirmation sent; need a dupe so we don't have the WHERE clause | ||
| 103 | $dupe = Confirm_address::staticGet('code', $confirm->code); | ||
| 104 | if (!$dupe) { | ||
| 105 | common_log(LOG_WARNING, 'Could not refetch confirm', __FILE__); | ||
| 106 | return; | ||
| 107 | } | ||
| 108 | $orig = clone($dupe); | ||
| 109 | $dupe->sent = $dupe->claimed; | ||
| 110 | $result = $dupe->update($orig); | ||
| 111 | if (!$result) { | ||
| 112 | common_log_db_error($dupe, 'UPDATE', __FILE__); | ||
| 113 | # Just let the claim age out; hopefully things work then | ||
| 114 | return; | ||
| 115 | } | ||
| 116 | } | ||
| 117 | return true; | ||
| 118 | } | ||
| 119 | |||
| 120 | protected function next_confirm() | ||
| 121 | { | ||
| 122 | $confirm = new Confirm_address(); | ||
| 123 | $confirm->whereAdd('claimed IS null'); | ||
| 124 | $confirm->whereAdd('sent IS null'); | ||
| 125 | # XXX: eventually we could do other confirmations in the queue, too | ||
| 126 | $confirm->address_type = 'jabber'; | ||
| 127 | $confirm->orderBy('modified DESC'); | ||
| 128 | $confirm->limit(1); | ||
| 129 | if ($confirm->find(true)) { | ||
| 130 | common_log(LOG_INFO, 'Claiming confirmation for ' . $confirm->address); | ||
| 131 | # working around some weird DB_DataObject behaviour | ||
| 132 | $confirm->whereAdd(''); # clears where stuff | ||
| 133 | $original = clone($confirm); | ||
| 134 | $confirm->claimed = common_sql_now(); | ||
| 135 | $result = $confirm->update($original); | ||
| 136 | if ($result) { | ||
| 137 | common_log(LOG_INFO, 'Succeeded in claim! '. $result); | ||
| 138 | return $confirm; | ||
| 139 | } else { | ||
| 140 | common_log(LOG_INFO, 'Failed in claim!'); | ||
| 141 | return false; | ||
| 142 | } | ||
| 143 | } | ||
| 144 | return null; | ||
| 145 | } | ||
| 146 | |||
| 147 | protected function clear_old_confirm_claims() | ||
| 148 | { | ||
| 149 | $confirm = new Confirm(); | ||
| 150 | $confirm->claimed = null; | ||
| 151 | $confirm->whereAdd('now() - claimed > '.CLAIM_TIMEOUT); | ||
| 152 | $confirm->update(DB_DATAOBJECT_WHEREADD_ONLY); | ||
| 153 | $confirm->free(); | ||
| 154 | unset($confirm); | ||
| 155 | } | ||
| 156 | |||
| 157 | /** | ||
| 158 | * Make sure we're on the right site configuration | ||
| 159 | */ | ||
| 160 | protected function switchSite() | ||
| 161 | { | ||
| 162 | if ($this->site != common_config('site', 'server')) { | ||
| 163 | common_log(LOG_DEBUG, __METHOD__ . ": switching to site $this->site"); | ||
| 164 | $this->stats('switch'); | ||
| 165 | StatusNet::init($this->site); | ||
| 166 | } | ||
| 167 | } | ||
| 168 | } |
lib/xmppmanager.php
(273 / 0)
|   | |||
| 1 | <?php | ||
| 2 | /* | ||
| 3 | * StatusNet - the distributed open-source microblogging tool | ||
| 4 | * Copyright (C) 2008, 2009, StatusNet, Inc. | ||
| 5 | * | ||
| 6 | * This program is free software: you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU Affero General Public License as published by | ||
| 8 | * the Free Software Foundation, either version 3 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU Affero General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Affero General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } | ||
| 21 | |||
| 22 | /** | ||
| 23 | * XMPP background connection manager for XMPP-using queue handlers, | ||
| 24 | * allowing them to send outgoing messages on the right connection. | ||
| 25 | * | ||
| 26 | * Input is handled during socket select loop, keepalive pings during idle. | ||
| 27 | * Any incoming messages will be forwarded to the main XmppDaemon process, | ||
| 28 | * which handles direct user interaction. | ||
| 29 | * | ||
| 30 | * In a multi-site queuedaemon.php run, one connection will be instantiated | ||
| 31 | * for each site being handled by the current process that has XMPP enabled. | ||
| 32 | */ | ||
| 33 | |||
| 34 | class XmppManager extends IoManager | ||
| 35 | { | ||
| 36 | protected $site = null; | ||
| 37 | protected $pingid = 0; | ||
| 38 | protected $lastping = null; | ||
| 39 | |||
| 40 | static protected $singletons = array(); | ||
| 41 | |||
| 42 | const PING_INTERVAL = 120; | ||
| 43 | |||
| 44 | /** | ||
| 45 | * Fetch the singleton XmppManager for the current site. | ||
| 46 | * @return mixed XmppManager, or false if unneeded | ||
| 47 | */ | ||
| 48 | public static function get() | ||
| 49 | { | ||
| 50 | if (common_config('xmpp', 'enabled')) { | ||
| 51 | $site = common_config('site', 'server'); | ||
| 52 | if (empty(self::$singletons[$site])) { | ||
| 53 | self::$singletons[$site] = new XmppManager(); | ||
| 54 | } | ||
| 55 | return self::$singletons[$site]; | ||
| 56 | } else { | ||
| 57 | return false; | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | /** | ||
| 62 | * Tell the i/o master we need one instance for each supporting site | ||
| 63 | * being handled in this process. | ||
| 64 | */ | ||
| 65 | public static function multiSite() | ||
| 66 | { | ||
| 67 | return IoManager::INSTANCE_PER_SITE; | ||
| 68 | } | ||
| 69 | |||
| 70 | function __construct() | ||
| 71 | { | ||
| 72 | $this->site = common_config('site', 'server'); | ||
| 73 | } | ||
| 74 | |||
| 75 | /** | ||
| 76 | * Initialize connection to server. | ||
| 77 | * @return boolean true on success | ||
| 78 | */ | ||
| 79 | public function start($master) | ||
| 80 | { | ||
| 81 | parent::start($master); | ||
| 82 | $this->switchSite(); | ||
| 83 | |||
| 84 | require_once "lib/jabber.php"; | ||
| 85 | |||
| 86 | # Low priority; we don't want to receive messages | ||
| 87 | |||
| 88 | common_log(LOG_INFO, "INITIALIZE"); | ||
| 89 | $this->conn = jabber_connect($this->resource()); | ||
| 90 | |||
| 91 | if (empty($this->conn)) { | ||
| 92 | common_log(LOG_ERR, "Couldn't connect to server."); | ||
| 93 | return false; | ||
| 94 | } | ||
| 95 | |||
| 96 | $this->conn->addEventHandler('message', 'forward_message', $this); | ||
| 97 | $this->conn->addEventHandler('reconnect', 'handle_reconnect', $this); | ||
| 98 | $this->conn->setReconnectTimeout(600); | ||
| 99 | jabber_send_presence("Send me a message to post a notice", 'available', null, 'available', -1); | ||
| 100 | |||
| 101 | return !is_null($this->conn); | ||
| 102 | } | ||
| 103 | |||
| 104 | /** | ||
| 105 | * Message pump is triggered on socket input, so we only need an idle() | ||
| 106 | * call often enough to trigger our outgoing pings. | ||
| 107 | */ | ||
| 108 | function timeout() | ||
| 109 | { | ||
| 110 | return self::PING_INTERVAL; | ||
| 111 | } | ||
| 112 | |||
| 113 | /** | ||
| 114 | * Lists the XMPP connection socket to allow i/o master to wake | ||
| 115 | * when input comes in here as well as from the queue source. | ||
| 116 | * | ||
| 117 | * @return array of resources | ||
| 118 | */ | ||
| 119 | public function getSockets() | ||
| 120 | { | ||
| 121 | return array($this->conn->getSocket()); | ||
| 122 | } | ||
| 123 | |||
| 124 | /** | ||
| 125 | * Process XMPP events that have come in over the wire. | ||
| 126 | * Side effects: may switch site configuration | ||
| 127 | * @fixme may kill process on XMPP error | ||
| 128 | * @param resource $socket | ||
| 129 | */ | ||
| 130 | public function handleInput($socket) | ||
| 131 | { | ||
| 132 | $this->switchSite(); | ||
| 133 | |||
| 134 | # Process the queue for as long as needed | ||
| 135 | try { | ||
| 136 | if ($this->conn) { | ||
| 137 | assert($socket === $this->conn->getSocket()); | ||
| 138 | |||
| 139 | common_log(LOG_DEBUG, "Servicing the XMPP queue."); | ||
| 140 | $this->stats('xmpp_process'); | ||
| 141 | $this->conn->processTime(0); | ||
| 142 | } | ||
| 143 | } catch (XMPPHP_Exception $e) { | ||
| 144 | common_log(LOG_ERR, "Got an XMPPHP_Exception: " . $e->getMessage()); | ||
| 145 | die($e->getMessage()); | ||
| 146 | } | ||
| 147 | } | ||
| 148 | |||
| 149 | /** | ||
| 150 | * Idle processing for io manager's execution loop. | ||
| 151 | * Send keepalive pings to server. | ||
| 152 | * | ||
| 153 | * Side effect: kills process on exception from XMPP library. | ||
| 154 | * | ||
| 155 | * @fixme non-dying error handling | ||
| 156 | */ | ||
| 157 | public function idle($timeout=0) | ||
| 158 | { | ||
| 159 | if ($this->conn) { | ||
| 160 | $now = time(); | ||
| 161 | if (empty($this->lastping) || $now - $this->lastping > self::PING_INTERVAL) { | ||
| 162 | $this->switchSite(); | ||
| 163 | try { | ||
| 164 | $this->sendPing(); | ||
| 165 | $this->lastping = $now; | ||
| 166 | } catch (XMPPHP_Exception $e) { | ||
| 167 | common_log(LOG_ERR, "Got an XMPPHP_Exception: " . $e->getMessage()); | ||
| 168 | die($e->getMessage()); | ||
| 169 | } | ||
| 170 | } | ||
| 171 | } | ||
| 172 | } | ||
| 173 | |||
| 174 | /** | ||
| 175 | * Send a keepalive ping to the XMPP server. | ||
| 176 | */ | ||
| 177 | protected function sendPing() | ||
| 178 | { | ||
| 179 | $jid = jabber_daemon_address().'/'.$this->resource(); | ||
| 180 | $server = common_config('xmpp', 'server'); | ||
| 181 | |||
| 182 | if (!isset($this->pingid)) { | ||
| 183 | $this->pingid = 0; | ||
| 184 | } else { | ||
| 185 | $this->pingid++; | ||
| 186 | } | ||
| 187 | |||
| 188 | common_log(LOG_DEBUG, "Sending ping #{$this->pingid}"); | ||
| 189 | |||
| 190 | $this->conn->send("<iq from='{$jid}' to='{$server}' id='ping_{$this->pingid}' type='get'><ping xmlns='urn:xmpp:ping'/></iq>"); | ||
| 191 | } | ||
| 192 | |||
| 193 | /** | ||
| 194 | * Callback for Jabber reconnect event | ||
| 195 | * @param $pl | ||
| 196 | */ | ||
| 197 | function handle_reconnect(&$pl) | ||
| 198 | { | ||
| 199 | common_log(LOG_NOTICE, 'XMPP reconnected'); | ||
| 200 | |||
| 201 | $this->conn->processUntil('session_start'); | ||
| 202 | $this->conn->presence(null, 'available', null, 'available', -1); | ||
| 203 | } | ||
| 204 | |||
| 205 | /** | ||
| 206 | * Callback for Jabber message event. | ||
| 207 | * | ||
| 208 | * This connection handles output; if we get a message straight to us, | ||
| 209 | * forward it on to our XmppDaemon listener for processing. | ||
| 210 | * | ||
| 211 | * @param $pl | ||
| 212 | */ | ||
| 213 | function forward_message(&$pl) | ||
| 214 | { | ||
| 215 | if ($pl['type'] != 'chat') { | ||
| 216 | common_log(LOG_DEBUG, 'Ignoring message of type ' . $pl['type'] . ' from ' . $pl['from']); | ||
| 217 | return; | ||
| 218 | } | ||
| 219 | $listener = $this->listener(); | ||
| 220 | if (strtolower($listener) == strtolower($pl['from'])) { | ||
| 221 | common_log(LOG_WARNING, 'Ignoring loop message.'); | ||
| 222 | return; | ||
| 223 | } | ||
| 224 | common_log(LOG_INFO, 'Forwarding message from ' . $pl['from'] . ' to ' . $listener); | ||
| 225 | $this->conn->message($this->listener(), $pl['body'], 'chat', null, $this->ofrom($pl['from'])); | ||
| 226 | } | ||
| 227 | |||
| 228 | /** | ||
| 229 | * Build an <addresses> block with an ofrom entry for forwarded messages | ||
| 230 | * | ||
| 231 | * @param string $from Jabber ID of original sender | ||
| 232 | * @return string XML fragment | ||
| 233 | */ | ||
| 234 | protected function ofrom($from) | ||
| 235 | { | ||
| 236 | $address = "<addresses xmlns='http://jabber.org/protocol/address'>\n"; | ||
| 237 | $address .= "<address type='ofrom' jid='$from' />\n"; | ||
| 238 | $address .= "</addresses>\n"; | ||
| 239 | return $address; | ||
| 240 | } | ||
| 241 | |||
| 242 | /** | ||
| 243 | * Build the complete JID of the XmppDaemon process which | ||
| 244 | * handles primary XMPP input for this site. | ||
| 245 | * | ||
| 246 | * @return string Jabber ID | ||
| 247 | */ | ||
| 248 | protected function listener() | ||
| 249 | { | ||
| 250 | if (common_config('xmpp', 'listener')) { | ||
| 251 | return common_config('xmpp', 'listener'); | ||
| 252 | } else { | ||
| 253 | return jabber_daemon_address() . '/' . common_config('xmpp','resource') . 'daemon'; | ||
| 254 | } | ||
| 255 | } | ||
| 256 | |||
| 257 | protected function resource() | ||
| 258 | { | ||
| 259 | return 'queue' . posix_getpid(); // @fixme PIDs won't be host-unique | ||
| 260 | } | ||
| 261 | |||
| 262 | /** | ||
| 263 | * Make sure we're on the right site configuration | ||
| 264 | */ | ||
| 265 | protected function switchSite() | ||
| 266 | { | ||
| 267 | if ($this->site != common_config('site', 'server')) { | ||
| 268 | common_log(LOG_DEBUG, __METHOD__ . ": switching to site $this->site"); | ||
| 269 | $this->stats('switch'); | ||
| 270 | StatusNet::init($this->site); | ||
| 271 | } | ||
| 272 | } | ||
| 273 | } |
lib/xmppqueuehandler.php
(0 / 142)
|   | |||
| 1 | <?php | ||
| 2 | /* | ||
| 3 | * StatusNet - the distributed open-source microblogging tool | ||
| 4 | * Copyright (C) 2008, 2009, StatusNet, Inc. | ||
| 5 | * | ||
| 6 | * This program is free software: you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU Affero General Public License as published by | ||
| 8 | * the Free Software Foundation, either version 3 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU Affero General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Affero General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } | ||
| 21 | |||
| 22 | require_once(INSTALLDIR.'/lib/queuehandler.php'); | ||
| 23 | |||
| 24 | define('PING_INTERVAL', 120); | ||
| 25 | |||
| 26 | /** | ||
| 27 | * Common superclass for all XMPP-using queue handlers. They all need to | ||
| 28 | * service their message queues on idle, and forward any incoming messages | ||
| 29 | * to the XMPP listener connection. So, we abstract out common code to a | ||
| 30 | * superclass. | ||
| 31 | */ | ||
| 32 | |||
| 33 | class XmppQueueHandler extends QueueHandler | ||
| 34 | { | ||
| 35 | var $pingid = 0; | ||
| 36 | var $lastping = null; | ||
| 37 | |||
| 38 | function start() | ||
| 39 | { | ||
| 40 | # Low priority; we don't want to receive messages | ||
| 41 | |||
| 42 | $this->log(LOG_INFO, "INITIALIZE"); | ||
| 43 | $this->conn = jabber_connect($this->_id.$this->transport()); | ||
| 44 | |||
| 45 | if (empty($this->conn)) { | ||
| 46 | $this->log(LOG_ERR, "Couldn't connect to server."); | ||
| 47 | return false; | ||
| 48 | } | ||
| 49 | |||
| 50 | $this->conn->addEventHandler('message', 'forward_message', $this); | ||
| 51 | $this->conn->addEventHandler('reconnect', 'handle_reconnect', $this); | ||
| 52 | $this->conn->setReconnectTimeout(600); | ||
| 53 | jabber_send_presence("Send me a message to post a notice", 'available', null, 'available', -1); | ||
| 54 | |||
| 55 | return !is_null($this->conn); | ||
| 56 | } | ||
| 57 | |||
| 58 | function timeout() | ||
| 59 | { | ||
| 60 | return 10; | ||
| 61 | } | ||
| 62 | |||
| 63 | function handle_reconnect(&$pl) | ||
| 64 | { | ||
| 65 | $this->log(LOG_NOTICE, 'reconnected'); | ||
| 66 | |||
| 67 | $this->conn->processUntil('session_start'); | ||
| 68 | $this->conn->presence(null, 'available', null, 'available', -1); | ||
| 69 | } | ||
| 70 | |||
| 71 | function idle($timeout=0) | ||
| 72 | { | ||
| 73 | # Process the queue for as long as needed | ||
| 74 | try { | ||
| 75 | if ($this->conn) { | ||
| 76 | $this->log(LOG_DEBUG, "Servicing the XMPP queue."); | ||
| 77 | $this->conn->processTime($timeout); | ||
| 78 | $now = time(); | ||
| 79 | if (empty($this->lastping) || $now - $this->lastping > PING_INTERVAL) { | ||
| 80 | $this->sendPing(); | ||
| 81 | $this->lastping = $now; | ||
| 82 | } | ||
| 83 | } | ||
| 84 | } catch (XMPPHP_Exception $e) { | ||
| 85 | $this->log(LOG_ERR, "Got an XMPPHP_Exception: " . $e->getMessage()); | ||
| 86 | die($e->getMessage()); | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 90 | function sendPing() | ||
| 91 | { | ||
| 92 | $jid = jabber_daemon_address().'/'.$this->_id.$this->transport(); | ||
| 93 | $server = common_config('xmpp', 'server'); | ||
| 94 | |||
| 95 | if (!isset($this->pingid)) { | ||
| 96 | $this->pingid = 0; | ||
| 97 | } else { | ||
| 98 | $this->pingid++; | ||
| 99 | } | ||
| 100 | |||
| 101 | $this->log(LOG_DEBUG, "Sending ping #{$this->pingid}"); | ||
| 102 | |||
| 103 | $this->conn->send("<iq from='{$jid}' to='{$server}' id='ping_{$this->pingid}' type='get'><ping xmlns='urn:xmpp:ping'/></iq>"); | ||
| 104 | } | ||
| 105 | |||
| 106 | function forward_message(&$pl) | ||
| 107 | { | ||
| 108 | if ($pl['type'] != 'chat') { | ||
| 109 | $this->log(LOG_DEBUG, 'Ignoring message of type ' . $pl['type'] . ' from ' . $pl['from']); | ||
| 110 | return; | ||
| 111 | } | ||
| 112 | $listener = $this->listener(); | ||
| 113 | if (strtolower($listener) == strtolower($pl['from'])) { | ||
| 114 | $this->log(LOG_WARNING, 'Ignoring loop message.'); | ||
| 115 | return; | ||
| 116 | } | ||
| 117 | $this->log(LOG_INFO, 'Forwarding message from ' . $pl['from'] . ' to ' . $listener); | ||
| 118 | $this->conn->message($this->listener(), $pl['body'], 'chat', null, $this->ofrom($pl['from'])); | ||
| 119 | } | ||
| 120 | |||
| 121 | function ofrom($from) | ||
| 122 | { | ||
| 123 | $address = "<addresses xmlns='http://jabber.org/protocol/address'>\n"; | ||
| 124 | $address .= "<address type='ofrom' jid='$from' />\n"; | ||
| 125 | $address .= "</addresses>\n"; | ||
| 126 | return $address; | ||
| 127 | } | ||
| 128 | |||
| 129 | function listener() | ||
| 130 | { | ||
| 131 | if (common_config('xmpp', 'listener')) { | ||
| 132 | return common_config('xmpp', 'listener'); | ||
| 133 | } else { | ||
| 134 | return jabber_daemon_address() . '/' . common_config('xmpp','resource') . 'daemon'; | ||
| 135 | } | ||
| 136 | } | ||
| 137 | |||
| 138 | function getSockets() | ||
| 139 | { | ||
| 140 | return array($this->conn->getSocket()); | ||
| 141 | } | ||
| 142 | } |
plugins/Enjit/README
(5 / 0)
|   | |||
| 1 | This doesn't seem to have been functional for a while; can't find other references | ||
| 2 | to the enjit configuration or transport enqueuing. Keeping it in case someone | ||
| 3 | wants to bring it up to date. | ||
| 4 | |||
| 5 | -- brion vibber <brion@status.net> 2009-12-03 |
|   | |||
| 1 | <?php | ||
| 2 | /* | ||
| 3 | * StatusNet - the distributed open-source microblogging tool | ||
| 4 | * Copyright (C) 2008, 2009, StatusNet, Inc. | ||
| 5 | * | ||
| 6 | * This program is free software: you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU Affero General Public License as published by | ||
| 8 | * the Free Software Foundation, either version 3 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU Affero General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Affero General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | if (!defined('STATUSNET') && !defined('LACONICA')) { | ||
| 21 | exit(1); | ||
| 22 | } | ||
| 23 | |||
| 24 | /** | ||
| 25 | * Queue handler for watching new notices and posting to enjit. | ||
| 26 | * @fixme is this actually being used/functional atm? | ||
| 27 | */ | ||
| 28 | class EnjitQueueHandler extends QueueHandler | ||
| 29 | { | ||
| 30 | function transport() | ||
| 31 | { | ||
| 32 | return 'enjit'; | ||
| 33 | } | ||
| 34 | |||
| 35 | function start() | ||
| 36 | { | ||
| 37 | $this->log(LOG_INFO, "Starting EnjitQueueHandler"); | ||
| 38 | $this->log(LOG_INFO, "Broadcasting to ".common_config('enjit', 'apiurl')); | ||
| 39 | return true; | ||
| 40 | } | ||
| 41 | |||
| 42 | function handle_notice($notice) | ||
| 43 | { | ||
| 44 | |||
| 45 | $profile = Profile::staticGet($notice->profile_id); | ||
| 46 | |||
| 47 | $this->log(LOG_INFO, "Posting Notice ".$notice->id." from ".$profile->nickname); | ||
| 48 | |||
| 49 | if ( ! $notice->is_local ) { | ||
| 50 | $this->log(LOG_INFO, "Skipping remote notice"); | ||
| 51 | return "skipped"; | ||
| 52 | } | ||
| 53 | |||
| 54 | # | ||
| 55 | # Build an Atom message from the notice | ||
| 56 | # | ||
| 57 | $noticeurl = common_local_url('shownotice', array('notice' => $notice->id)); | ||
| 58 | $msg = $profile->nickname . ': ' . $notice->content; | ||
| 59 | |||
| 60 | $atom = "<entry xmlns='http://www.w3.org/2005/Atom'>\n"; | ||
| 61 | $atom .= "<apisource>".common_config('enjit','source')."</apisource>\n"; | ||
| 62 | $atom .= "<source>\n"; | ||
| 63 | $atom .= "<title>" . $profile->nickname . " - " . common_config('site', 'name') . "</title>\n"; | ||
| 64 | $atom .= "<link href='" . $profile->profileurl . "'/>\n"; | ||
| 65 | $atom .= "<link rel='self' type='application/rss+xml' href='" . common_local_url('userrss', array('nickname' => $profile->nickname)) . "'/>\n"; | ||
| 66 | $atom .= "<author><name>" . $profile->nickname . "</name></author>\n"; | ||
| 67 | $atom .= "<icon>" . $profile->avatarUrl(AVATAR_PROFILE_SIZE) . "</icon>\n"; | ||
| 68 | $atom .= "</source>\n"; | ||
| 69 | $atom .= "<title>" . htmlspecialchars($msg) . "</title>\n"; | ||
| 70 | $atom .= "<summary>" . htmlspecialchars($msg) . "</summary>\n"; | ||
| 71 | $atom .= "<link rel='alternate' href='" . $noticeurl . "' />\n"; | ||
| 72 | $atom .= "<id>". $notice->uri . "</id>\n"; | ||
| 73 | $atom .= "<published>".common_date_w3dtf($notice->created)."</published>\n"; | ||
| 74 | $atom .= "<updated>".common_date_w3dtf($notice->modified)."</updated>\n"; | ||
| 75 | $atom .= "</entry>\n"; | ||
| 76 | |||
| 77 | $url = common_config('enjit', 'apiurl') . "/submit/". common_config('enjit','apikey'); | ||
| 78 | $data = array( | ||
| 79 | 'msg' => $atom, | ||
| 80 | ); | ||
| 81 | |||
| 82 | # | ||
| 83 | # POST the message to $config['enjit']['apiurl'] | ||
| 84 | # | ||
| 85 | $request = HTTPClient::start(); | ||
| 86 | $response = $request->post($url, null, $data); | ||
| 87 | |||
| 88 | return $response->isOk(); | ||
| 89 | } | ||
| 90 | |||
| 91 | } |
|   | |||
| 114 | 114 | case 'FBCSettingsNav': | |
| 115 | 115 | include_once INSTALLDIR . '/plugins/Facebook/FBCSettingsNav.php'; | |
| 116 | 116 | return false; | |
| 117 | case 'FacebookQueueHandler': | ||
| 118 | include_once INSTALLDIR . '/plugins/Facebook/facebookqueuehandler.php'; | ||
| 119 | return false; | ||
| 117 | 120 | default: | |
| 118 | 121 | return true; | |
| 119 | 122 | } | |
| … | … | ||
| 511 | 511 | } | |
| 512 | 512 | ||
| 513 | 513 | /** | |
| 514 | * broadcast the message when not using queuehandler | ||
| 514 | * Register Facebook notice queue handler | ||
| 515 | 515 | * | |
| 516 | * @param Notice &$notice the notice | ||
| 517 | * @param array $queue destination queue | ||
| 516 | * @param QueueManager $manager | ||
| 518 | 517 | * | |
| 519 | 518 | * @return boolean hook return | |
| 520 | 519 | */ | |
| 521 | |||
| 522 | function onUnqueueHandleNotice(&$notice, $queue) | ||
| 520 | function onEndInitializeQueueManager($manager) | ||
| 523 | 521 | { | |
| 524 | if (($queue == 'facebook') && ($this->_isLocal($notice))) { | ||
| 525 | facebookBroadcastNotice($notice); | ||
| 526 | return false; | ||
| 527 | } | ||
| 528 | return true; | ||
| 529 | } | ||
| 530 | |||
| 531 | /** | ||
| 532 | * Determine whether the notice was locally created | ||
| 533 | * | ||
| 534 | * @param Notice $notice the notice | ||
| 535 | * | ||
| 536 | * @return boolean locality | ||
| 537 | */ | ||
| 538 | |||
| 539 | function _isLocal($notice) | ||
| 540 | { | ||
| 541 | return ($notice->is_local == Notice::LOCAL_PUBLIC || | ||
| 542 | $notice->is_local == Notice::LOCAL_NONPUBLIC); | ||
| 543 | } | ||
| 544 | |||
| 545 | /** | ||
| 546 | * Add Facebook queuehandler to the list of daemons to start | ||
| 547 | * | ||
| 548 | * @param array $daemons the list fo daemons to run | ||
| 549 | * | ||
| 550 | * @return boolean hook return | ||
| 551 | * | ||
| 552 | */ | ||
| 553 | |||
| 554 | function onGetValidDaemons($daemons) | ||
| 555 | { | ||
| 556 | array_push($daemons, INSTALLDIR . | ||
| 557 | '/plugins/Facebook/facebookqueuehandler.php'); | ||
| 522 | $manager->connect('facebook', 'FacebookQueueHandler'); | ||
| 558 | 523 | return true; | |
| 559 | 524 | } | |
| 560 | 525 |
|   | |||
| 1 | #!/usr/bin/env php | ||
| 2 | 1 | <?php | |
| 3 | 2 | /* | |
| 4 | 3 | * StatusNet - the distributed open-source microblogging tool | |
| … | … | ||
| 17 | 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| 18 | 18 | */ | |
| 19 | 19 | ||
| 20 | define('INSTALLDIR', realpath(dirname(__FILE__) . '/../..')); | ||
| 20 | if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } | ||
| 21 | 21 | ||
| 22 | $shortoptions = 'i::'; | ||
| 23 | $longoptions = array('id::'); | ||
| 24 | |||
| 25 | $helptext = <<<END_OF_FACEBOOK_HELP | ||
| 26 | Daemon script for pushing new notices to Facebook. | ||
| 27 | |||
| 28 | -i --id Identity (default none) | ||
| 29 | |||
| 30 | END_OF_FACEBOOK_HELP; | ||
| 31 | |||
| 32 | require_once INSTALLDIR . '/scripts/commandline.inc'; | ||
| 33 | 22 | require_once INSTALLDIR . '/plugins/Facebook/facebookutil.php'; | |
| 34 | require_once INSTALLDIR . '/lib/queuehandler.php'; | ||
| 35 | 23 | ||
| 36 | 24 | class FacebookQueueHandler extends QueueHandler | |
| 37 | 25 | { | |
| … | … | ||
| 28 | 28 | return 'facebook'; | |
| 29 | 29 | } | |
| 30 | 30 | ||
| 31 | function start() | ||
| 31 | function handle_notice($notice) | ||
| 32 | 32 | { | |
| 33 | $this->log(LOG_INFO, "INITIALIZE"); | ||
| 33 | if ($this->_isLocal($notice)) { | ||
| 34 | return facebookBroadcastNotice($notice); | ||
| 35 | } | ||
| 34 | 36 | return true; | |
| 35 | 37 | } | |
| 36 | 38 | ||
| 37 | function handle_notice($notice) | ||
| 39 | /** | ||
| 40 | * Determine whether the notice was locally created | ||
| 41 | * | ||
| 42 | * @param Notice $notice the notice | ||
| 43 | * | ||
| 44 | * @return boolean locality | ||
| 45 | */ | ||
| 46 | function _isLocal($notice) | ||
| 38 | 47 | { | |
| 39 | return facebookBroadcastNotice($notice); | ||
| 48 | return ($notice->is_local == Notice::LOCAL_PUBLIC || | ||
| 49 | $notice->is_local == Notice::LOCAL_NONPUBLIC); | ||
| 40 | 50 | } | |
| 41 | |||
| 42 | function finish() | ||
| 43 | { | ||
| 44 | } | ||
| 45 | |||
| 46 | 51 | } | |
| 47 | |||
| 48 | if (have_option('i')) { | ||
| 49 | $id = get_option_value('i'); | ||
| 50 | } else if (have_option('--id')) { | ||
| 51 | $id = get_option_value('--id'); | ||
| 52 | } else if (count($args) > 0) { | ||
| 53 | $id = $args[0]; | ||
| 54 | } else { | ||
| 55 | $id = null; | ||
| 56 | } | ||
| 57 | |||
| 58 | $handler = new FacebookQueueHandler($id); | ||
| 59 | |||
| 60 | $handler->runOnce(); |
plugins/MemcachePlugin.php
(17 / 0)
|   | |||
| 133 | 133 | return false; | |
| 134 | 134 | } | |
| 135 | 135 | ||
| 136 | function onStartCacheReconnect(&$success) | ||
| 137 | { | ||
| 138 | if (empty($this->_conn)) { | ||
| 139 | // nothing to do | ||
| 140 | return true; | ||
| 141 | } | ||
| 142 | if ($this->persistent) { | ||
| 143 | common_log(LOG_ERR, "Cannot close persistent memcached connection"); | ||
| 144 | $success = false; | ||
| 145 | } else { | ||
| 146 | common_log(LOG_INFO, "Closing memcached connection"); | ||
| 147 | $success = $this->_conn->close(); | ||
| 148 | $this->_conn = null; | ||
| 149 | } | ||
| 150 | return false; | ||
| 151 | } | ||
| 152 | |||
| 136 | 153 | /** | |
| 137 | 154 | * Ensure that a connection exists | |
| 138 | 155 | * |
|   | |||
| 112 | 112 | strtolower(mb_substr($cls, 0, -6)) . '.php'; | |
| 113 | 113 | return false; | |
| 114 | 114 | case 'TwitterOAuthClient': | |
| 115 | include_once INSTALLDIR . '/plugins/TwitterBridge/twitteroauthclient.php'; | ||
| 115 | case 'TwitterQueueHandler': | ||
| 116 | include_once INSTALLDIR . '/plugins/TwitterBridge/' . | ||
| 117 | strtolower($cls) . '.php'; | ||
| 116 | 118 | return false; | |
| 117 | 119 | default: | |
| 118 | 120 | return true; | |
| … | … | ||
| 141 | 141 | } | |
| 142 | 142 | ||
| 143 | 143 | /** | |
| 144 | * broadcast the message when not using queuehandler | ||
| 145 | * | ||
| 146 | * @param Notice &$notice the notice | ||
| 147 | * @param array $queue destination queue | ||
| 148 | * | ||
| 149 | * @return boolean hook return | ||
| 150 | */ | ||
| 151 | function onUnqueueHandleNotice(&$notice, $queue) | ||
| 152 | { | ||
| 153 | if (($queue == 'twitter') && ($this->_isLocal($notice))) { | ||
| 154 | broadcast_twitter($notice); | ||
| 155 | return false; | ||
| 156 | } | ||
| 157 | return true; | ||
| 158 | } | ||
| 159 | |||
| 160 | /** | ||
| 161 | * Determine whether the notice was locally created | ||
| 162 | * | ||
| 163 | * @param Notice $notice | ||
| 164 | * | ||
| 165 | * @return boolean locality | ||
| 166 | */ | ||
| 167 | function _isLocal($notice) | ||
| 168 | { | ||
| 169 | return ($notice->is_local == Notice::LOCAL_PUBLIC || | ||
| 170 | $notice->is_local == Notice::LOCAL_NONPUBLIC); | ||
| 171 | } | ||
| 172 | |||
| 173 | /** | ||
| 174 | 144 | * Add Twitter bridge daemons to the list of daemons to start | |
| 175 | 145 | * | |
| 176 | 146 | * @param array $daemons the list fo daemons to run | |
| 177 | 147 | * | |
| 178 | 148 | * @return boolean hook return | |
| 179 | * | ||
| 180 | 149 | */ | |
| 181 | 150 | function onGetValidDaemons($daemons) | |
| 182 | 151 | { | |
| 183 | 152 | array_push($daemons, INSTALLDIR . | |
| 184 | '/plugins/TwitterBridge/daemons/twitterqueuehandler.php'); | ||
| 185 | array_push($daemons, INSTALLDIR . | ||
| 186 | 153 | '/plugins/TwitterBridge/daemons/synctwitterfriends.php'); | |
| 187 | 154 | ||
| 188 | 155 | if (common_config('twitterimport', 'enabled')) { | |
| … | … | ||
| 157 | 157 | . '/plugins/TwitterBridge/daemons/twitterstatusfetcher.php'); | |
| 158 | 158 | } | |
| 159 | 159 | ||
| 160 | return true; | ||
| 161 | } | ||
| 162 | |||
| 163 | /** | ||
| 164 | * Register Twitter notice queue handler | ||
| 165 | * | ||
| 166 | * @param QueueManager $manager | ||
| 167 | * | ||
| 168 | * @return boolean hook return | ||
| 169 | */ | ||
| 170 | function onEndInitializeQueueManager($manager) | ||
| 171 | { | ||
| 172 | $manager->connect('twitter', 'TwitterQueueHandler'); | ||
| 160 | 173 | return true; | |
| 161 | 174 | } | |
| 162 | 175 |
|   | |||
| 1 | #!/usr/bin/env php | ||
| 2 | <?php | ||
| 3 | /* | ||
| 4 | * StatusNet - the distributed open-source microblogging tool | ||
| 5 | * Copyright (C) 2008, 2009, StatusNet, Inc. | ||
| 6 | * | ||
| 7 | * This program is free software: you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU Affero General Public License as published by | ||
| 9 | * the Free Software Foundation, either version 3 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU Affero General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Affero General Public License | ||
| 18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | */ | ||
| 20 | |||
| 21 | define('INSTALLDIR', realpath(dirname(__FILE__) . '/../../..')); | ||
| 22 | |||
| 23 | $shortoptions = 'i::'; | ||
| 24 | $longoptions = array('id::'); | ||
| 25 | |||
| 26 | $helptext = <<<END_OF_ENJIT_HELP | ||
| 27 | Daemon script for pushing new notices to Twitter. | ||
| 28 | |||
| 29 | -i --id Identity (default none) | ||
| 30 | |||
| 31 | END_OF_ENJIT_HELP; | ||
| 32 | |||
| 33 | require_once INSTALLDIR . '/scripts/commandline.inc'; | ||
| 34 | require_once INSTALLDIR . '/lib/queuehandler.php'; | ||
| 35 | require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php'; | ||
| 36 | |||
| 37 | class TwitterQueueHandler extends QueueHandler | ||
| 38 | { | ||
| 39 | function transport() | ||
| 40 | { | ||
| 41 | return 'twitter'; | ||
| 42 | } | ||
| 43 | |||
| 44 | function start() | ||
| 45 | { | ||
| 46 | $this->log(LOG_INFO, "INITIALIZE"); | ||
| 47 | return true; | ||
| 48 | } | ||
| 49 | |||
| 50 | function handle_notice($notice) | ||
| 51 | { | ||
| 52 | return broadcast_twitter($notice); | ||
| 53 | } | ||
| 54 | |||
| 55 | function finish() | ||
| 56 | { | ||
| 57 | } | ||
| 58 | |||
| 59 | } | ||
| 60 | |||
| 61 | if (have_option('i')) { | ||
| 62 | $id = get_option_value('i'); | ||
| 63 | } else if (have_option('--id')) { | ||
| 64 | $id = get_option_value('--id'); | ||
| 65 | } else if (count($args) > 0) { | ||
| 66 | $id = $args[0]; | ||
| 67 | } else { | ||
| 68 | $id = null; | ||
| 69 | } | ||
| 70 | |||
| 71 | $handler = new TwitterQueueHandler($id); | ||
| 72 | |||
| 73 | $handler->runOnce(); |
|   | |||
| 1 | <?php | ||
| 2 | /* | ||
| 3 | * StatusNet - the distributed open-source microblogging tool | ||
| 4 | * Copyright (C) 2008, 2009, StatusNet, Inc. | ||
| 5 | * | ||
| 6 | * This program is free software: you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU Affero General Public License as published by | ||
| 8 | * the Free Software Foundation, either version 3 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU Affero General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Affero General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } | ||
| 21 | |||
| 22 | require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php'; | ||
| 23 | |||
| 24 | class TwitterQueueHandler extends QueueHandler | ||
| 25 | { | ||
| 26 | function transport() | ||
| 27 | { | ||
| 28 | return 'twitter'; | ||
| 29 | } | ||
| 30 | |||
| 31 | function handle_notice($notice) | ||
| 32 | { | ||
| 33 | return broadcast_twitter($notice); | ||
| 34 | } | ||
| 35 | } |
scripts/enjitqueuehandler.php
(0 / 121)
|   | |||
| 1 | #!/usr/bin/env php | ||
| 2 | <?php | ||
| 3 | /* | ||
| 4 | * StatusNet - the distributed open-source microblogging tool | ||
| 5 | * Copyright (C) 2008, 2009, StatusNet, Inc. | ||
| 6 | * | ||
| 7 | * This program is free software: you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU Affero General Public License as published by | ||
| 9 | * the Free Software Foundation, either version 3 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU Affero General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Affero General Public License | ||
| 18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | */ | ||
| 20 | |||
| 21 | define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); | ||
| 22 | |||
| 23 | $shortoptions = 'i::'; | ||
| 24 | $longoptions = array('id::'); | ||
| 25 | |||
| 26 | $helptext = <<<END_OF_ENJIT_HELP | ||
| 27 | Daemon script for watching new notices and posting to enjit. | ||
| 28 | |||
| 29 | -i --id Identity (default none) | ||
| 30 | |||
| 31 | END_OF_ENJIT_HELP; | ||
| 32 | |||
| 33 | require_once INSTALLDIR.'/scripts/commandline.inc'; | ||
| 34 | |||
| 35 | require_once INSTALLDIR . '/lib/mail.php'; | ||
| 36 | require_once INSTALLDIR . '/lib/queuehandler.php'; | ||
| 37 | |||
| 38 | set_error_handler('common_error_handler'); | ||
| 39 | |||
| 40 | class EnjitQueueHandler extends QueueHandler | ||
| 41 | { | ||
| 42 | function transport() | ||
| 43 | { | ||
| 44 | return 'enjit'; | ||
| 45 | } | ||
| 46 | |||
| 47 | function start() | ||
| 48 | { | ||
| 49 | $this->log(LOG_INFO, "Starting EnjitQueueHandler"); | ||
| 50 | $this->log(LOG_INFO, "Broadcasting to ".common_config('enjit', 'apiurl')); | ||
| 51 | return true; | ||
| 52 | } | ||
| 53 | |||
| 54 | function handle_notice($notice) | ||
| 55 | { | ||
| 56 | |||
| 57 | $profile = Profile::staticGet($notice->profile_id); | ||
| 58 | |||
| 59 | $this->log(LOG_INFO, "Posting Notice ".$notice->id." from ".$profile->nickname); | ||
| 60 | |||
| 61 | if ( ! $notice->is_local ) { | ||
| 62 | $this->log(LOG_INFO, "Skipping remote notice"); | ||
| 63 | return "skipped"; | ||
| 64 | } | ||
| 65 | |||
| 66 | # | ||
| 67 | # Build an Atom message from the notice | ||
| 68 | # | ||
| 69 | $noticeurl = common_local_url('shownotice', array('notice' => $notice->id)); | ||
| 70 | $msg = $profile->nickname . ': ' . $notice->content; | ||
| 71 | |||
| 72 | $atom = "<entry xmlns='http://www.w3.org/2005/Atom'>\n"; | ||
| 73 | $atom .= "<apisource>".common_config('enjit','source')."</apisource>\n"; | ||
| 74 | $atom .= "<source>\n"; | ||
| 75 | $atom .= "<title>" . $profile->nickname . " - " . common_config('site', 'name') . "</title>\n"; | ||
| 76 | $atom .= "<link href='" . $profile->profileurl . "'/>\n"; | ||
| 77 | $atom .= "<link rel='self' type='application/rss+xml' href='" . common_local_url('userrss', array('nickname' => $profile->nickname)) . "'/>\n"; | ||
| 78 | $atom .= "<author><name>" . $profile->nickname . "</name></author>\n"; | ||
| 79 | $atom .= "<icon>" . $profile->avatarUrl(AVATAR_PROFILE_SIZE) . "</icon>\n"; | ||
| 80 | $atom .= "</source>\n"; | ||
| 81 | $atom .= "<title>" . htmlspecialchars($msg) . "</title>\n"; | ||
| 82 | $atom .= "<summary>" . htmlspecialchars($msg) . "</summary>\n"; | ||
| 83 | $atom .= "<link rel='alternate' href='" . $noticeurl . "' />\n"; | ||
| 84 | $atom .= "<id>". $notice->uri . "</id>\n"; | ||
| 85 | $atom .= "<published>".common_date_w3dtf($notice->created)."</published>\n"; | ||
| 86 | $atom .= "<updated>".common_date_w3dtf($notice->modified)."</updated>\n"; | ||
| 87 | $atom .= "</entry>\n"; | ||
| 88 | |||
| 89 | $url = common_config('enjit', 'apiurl') . "/submit/". common_config('enjit','apikey'); | ||
| 90 | $data = array( | ||
| 91 | 'msg' => $atom, | ||
| 92 | ); | ||
| 93 | |||
| 94 | # | ||
| 95 | # POST the message to $config['enjit']['apiurl'] | ||
| 96 | # | ||
| 97 | $request = HTTPClient::start(); | ||
| 98 | $response = $request->post($url, null, $data); | ||
| 99 | |||
| 100 | return $response->isOk(); | ||
| 101 | } | ||
| 102 | |||
| 103 | } | ||
| 104 | |||
| 105 | if (have_option('-i')) { | ||
| 106 | $id = get_option_value('-i'); | ||
| 107 | } else if (have_option('--id')) { | ||
| 108 | $id = get_option_value('--id'); | ||
| 109 | } else if (count($args) > 0) { | ||
| 110 | $id = $args[0]; | ||
| 111 | } else { | ||
| 112 | $id = null; | ||
| 113 | } | ||
| 114 | |||
| 115 | $handler = new EnjitQueueHandler($id); | ||
| 116 | |||
| 117 | if ($handler->start()) { | ||
| 118 | $handler->handle_queue(); | ||
| 119 | } | ||
| 120 | |||
| 121 | $handler->finish(); |
scripts/getvaliddaemons.php
(1 / 10)
|   | |||
| 37 | 37 | ||
| 38 | 38 | $daemons = array(); | |
| 39 | 39 | ||
| 40 | $daemons[] = INSTALLDIR.'/scripts/pluginqueuehandler.php'; | ||
| 41 | $daemons[] = INSTALLDIR.'/scripts/ombqueuehandler.php'; | ||
| 42 | $daemons[] = INSTALLDIR.'/scripts/pingqueuehandler.php'; | ||
| 40 | $daemons[] = INSTALLDIR.'/scripts/queuedaemon.php'; | ||
| 43 | 41 | ||
| 44 | 42 | if(common_config('xmpp','enabled')) { | |
| 45 | 43 | $daemons[] = INSTALLDIR.'/scripts/xmppdaemon.php'; | |
| 46 | $daemons[] = INSTALLDIR.'/scripts/jabberqueuehandler.php'; | ||
| 47 | $daemons[] = INSTALLDIR.'/scripts/publicqueuehandler.php'; | ||
| 48 | $daemons[] = INSTALLDIR.'/scripts/xmppconfirmhandler.php'; | ||
| 49 | } | ||
| 50 | |||
| 51 | if (common_config('sms', 'enabled')) { | ||
| 52 | $daemons[] = INSTALLDIR.'/scripts/smsqueuehandler.php'; | ||
| 53 | 44 | } | |
| 54 | 45 | ||
| 55 | 46 | if (Event::handle('GetValidDaemons', array(&$daemons))) { |
scripts/handlequeued.php
(56 / 0)
|   | |||
| 1 | #!/usr/bin/env php | ||
| 2 | <?php | ||
| 3 | /* | ||
| 4 | * StatusNet - the distributed open-source microblogging tool | ||
| 5 | * Copyright (C) 2008, 2009, StatusNet, Inc. | ||
| 6 | * | ||
| 7 | * This program is free software: you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU Affero General Public License as published by | ||
| 9 | * the Free Software Foundation, either version 3 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU Affero General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Affero General Public License | ||
| 18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | */ | ||
| 20 | |||
| 21 | define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); | ||
| 22 | |||
| 23 | $helptext = <<<END_OF_QUEUE_HELP | ||
| 24 | USAGE: handlequeued.php <queue> <notice id> | ||
| 25 | Run a single queued notice through background processing | ||
| 26 | as if it were being run through the queue. | ||
| 27 | |||
| 28 | |||
| 29 | END_OF_QUEUE_HELP; | ||
| 30 | |||
| 31 | require_once INSTALLDIR.'/scripts/commandline.inc'; | ||
| 32 | |||
| 33 | if (count($args) != 2) { | ||
| 34 | show_help(); | ||
| 35 | } | ||
| 36 | |||
| 37 | $queue = trim($args[0]); | ||
| 38 | $noticeId = intval($args[1]); | ||
| 39 | |||
| 40 | $qm = QueueManager::get(); | ||
| 41 | $handler = $qm->getHandler($queue); | ||
| 42 | if (!$handler) { | ||
| 43 | print "No handler for queue '$queue'.\n"; | ||
| 44 | exit(1); | ||
| 45 | } | ||
| 46 | |||
| 47 | $notice = Notice::staticGet('id', $noticeId); | ||
| 48 | if (empty($notice)) { | ||
| 49 | print "Invalid notice id $noticeId\n"; | ||
| 50 | exit(1); | ||
| 51 | } | ||
| 52 | |||
| 53 | if (!$handler->handle_notice($notice)) { | ||
| 54 | print "Failed to handle notice id $noticeId on queue '$queue'.\n"; | ||
| 55 | exit(1); | ||
| 56 | } |
scripts/jabberqueuehandler.php
(0 / 78)
|   | |||
| 1 | #!/usr/bin/env php | ||
| 2 | <?php | ||
| 3 | /* | ||
| 4 | * StatusNet - the distributed open-source microblogging tool | ||
| 5 | * Copyright (C) 2008, 2009, StatusNet, Inc. | ||
| 6 | * | ||
| 7 | * This program is free software: you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU Affero General Public License as published by | ||
| 9 | * the Free Software Foundation, either version 3 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU Affero General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Affero General Public License | ||
| 18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | */ | ||
| 20 | |||
| 21 | define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); | ||
| 22 | |||
| 23 | $shortoptions = 'i::'; | ||
| 24 | $longoptions = array('id::'); | ||
| 25 | |||
| 26 | $helptext = <<<END_OF_JABBER_HELP | ||
| 27 | Daemon script for pushing new notices to Jabber users. | ||
| 28 | |||
| 29 | -i --id Identity (default none) | ||
| 30 | |||
| 31 | END_OF_JABBER_HELP; | ||
| 32 | |||
| 33 | require_once INSTALLDIR.'/scripts/commandline.inc'; | ||
| 34 | |||
| 35 | require_once INSTALLDIR . '/lib/common.php'; | ||
| 36 | require_once INSTALLDIR . '/lib/jabber.php'; | ||
| 37 | require_once INSTALLDIR . '/lib/xmppqueuehandler.php'; | ||
| 38 | |||
| 39 | class JabberQueueHandler extends XmppQueueHandler | ||
| 40 | { | ||
| 41 | var $conn = null; | ||
| 42 | |||
| 43 | function transport() | ||
| 44 | { | ||
| 45 | return 'jabber'; | ||
| 46 | } | ||
| 47 | |||
| 48 | function handle_notice($notice) | ||
| 49 | { | ||
| 50 | try { | ||
| 51 | return jabber_broadcast_notice($notice); | ||
| 52 | } catch (XMPPHP_Exception $e) { | ||
| 53 | $this->log(LOG_ERR, "Got an XMPPHP_Exception: " . $e->getMessage()); | ||
| 54 | exit(1); | ||
| 55 | } | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | // Abort immediately if xmpp is not enabled, otherwise the daemon chews up | ||
| 60 | // lots of CPU trying to connect to unconfigured servers | ||
| 61 | if (common_config('xmpp','enabled')==false) { | ||
| 62 | print "Aborting daemon - xmpp is disabled\n"; | ||
| 63 | exit(); | ||
| 64 | } | ||
| 65 | |||
| 66 | if (have_option('i')) { | ||
| 67 | $id = get_option_value('i'); | ||
| 68 | } else if (have_option('--id')) { | ||
| 69 | $id = get_option_value('--id'); | ||
| 70 | } else if (count($args) > 0) { | ||
| 71 | $id = $args[0]; | ||
| 72 | } else { | ||
| 73 | $id = null; | ||
| 74 | } | ||
| 75 | |||
| 76 | $handler = new JabberQueueHandler($id); | ||
| 77 | |||
| 78 | $handler->runOnce(); |
scripts/ombqueuehandler.php
(0 / 87)
|   | |||
| 1 | #!/usr/bin/env php | ||
| 2 | <?php | ||
| 3 | /* | ||
| 4 | * StatusNet - the distributed open-source microblogging tool | ||
| 5 | * Copyright (C) 2008, 2009, StatusNet, Inc. | ||
| 6 | * | ||
| 7 | * This program is free software: you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU Affero General Public License as published by | ||
| 9 | * the Free Software Foundation, either version 3 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU Affero General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Affero General Public License | ||
| 18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | */ | ||
| 20 | |||
| 21 | define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); | ||
| 22 | |||
| 23 | $shortoptions = 'i::'; | ||
| 24 | $longoptions = array('id::'); | ||
| 25 | |||
| 26 | $helptext = <<<END_OF_OMB_HELP | ||
| 27 | Daemon script for pushing new notices to OpenMicroBlogging subscribers. | ||
| 28 | |||
| 29 | -i --id Identity (default none) | ||
| 30 | |||
| 31 | END_OF_OMB_HELP; | ||
| 32 | |||
| 33 | require_once INSTALLDIR.'/scripts/commandline.inc'; | ||
| 34 | |||
| 35 | require_once INSTALLDIR . '/lib/omb.php'; | ||
| 36 | require_once INSTALLDIR . '/lib/queuehandler.php'; | ||
| 37 | |||
| 38 | set_error_handler('common_error_handler'); | ||
| 39 | |||
| 40 | class OmbQueueHandler extends QueueHandler | ||
| 41 | { | ||
| 42 | |||
| 43 | function transport() | ||
| 44 | { | ||
| 45 | return 'omb'; | ||
| 46 | } | ||
| 47 | |||
| 48 | function start() | ||
| 49 | { | ||
| 50 | $this->log(LOG_INFO, "INITIALIZE"); | ||
| 51 | return true; | ||
| 52 | } | ||
| 53 | |||
| 54 | function handle_notice($notice) | ||
| 55 | { | ||
| 56 | if ($this->is_remote($notice)) { | ||
| 57 | $this->log(LOG_DEBUG, 'Ignoring remote notice ' . $notice->id); | ||
| 58 | return true; | ||
| 59 | } else { | ||
| 60 | return omb_broadcast_notice($notice); | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | function finish() | ||
| 65 | { | ||
| 66 | } | ||
| 67 | |||
| 68 | function is_remote($notice) | ||
| 69 | { | ||
| 70 | $user = User::staticGet($notice->profile_id); | ||
| 71 | return is_null($user); | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | if (have_option('i')) { | ||
| 76 | $id = get_option_value('i'); | ||
| 77 | } else if (have_option('--id')) { | ||
| 78 | $id = get_option_value('--id'); | ||
| 79 | } else if (count($args) > 0) { | ||
| 80 | $id = $args[0]; | ||
| 81 | } else { | ||
| 82 | $id = null; | ||
| 83 | } | ||
| 84 | |||
| 85 | $handler = new OmbQueueHandler($id); | ||
| 86 | |||
| 87 | $handler->runOnce(); |
scripts/pingqueuehandler.php
(0 / 69)
|   | |||
| 1 | #!/usr/bin/env php | ||
| 2 | <?php | ||
| 3 | /* | ||
| 4 | * StatusNet - the distributed open-source microblogging tool | ||
| 5 | * Copyright (C) 2008, 2009, StatusNet, Inc. | ||
| 6 | * | ||
| 7 | * This program is free software: you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU Affero General Public License as published by | ||
| 9 | * the Free Software Foundation, either version 3 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU Affero General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Affero General Public License | ||
| 18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | */ | ||
| 20 | |||
| 21 | define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); | ||
| 22 | |||
| 23 | $shortoptions = 'i::'; | ||
| 24 | $longoptions = array('id::'); | ||
| 25 | |||
| 26 | $helptext = <<<END_OF_PING_HELP | ||
| 27 | Daemon script for pushing new notices to ping servers. | ||
| 28 | |||
| 29 | -i --id Identity (default none) | ||
| 30 | |||
| 31 | END_OF_PING_HELP; | ||
| 32 | |||
| 33 | require_once INSTALLDIR.'/scripts/commandline.inc'; | ||
| 34 | |||
| 35 | require_once INSTALLDIR . '/lib/ping.php'; | ||
| 36 | require_once INSTALLDIR . '/lib/queuehandler.php'; | ||
| 37 | |||
| 38 | class PingQueueHandler extends QueueHandler { | ||
| 39 | |||
| 40 | function transport() { | ||
| 41 | return 'ping'; | ||
| 42 | } | ||
| 43 | |||
| 44 | function start() { | ||
| 45 | $this->log(LOG_INFO, "INITIALIZE"); | ||
| 46 | return true; | ||
| 47 | } | ||
| 48 | |||
| 49 | function handle_notice($notice) { | ||
| 50 | return ping_broadcast_notice($notice); | ||
| 51 | } | ||
| 52 | |||
| 53 | function finish() { | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | if (have_option('i')) { | ||
| 58 | $id = get_option_value('i'); | ||
| 59 | } else if (have_option('--id')) { | ||
| 60 | $id = get_option_value('--id'); | ||
| 61 | } else if (count($args) > 0) { | ||
| 62 | $id = $args[0]; | ||
| 63 | } else { | ||
| 64 | $id = null; | ||
| 65 | } | ||
| 66 | |||
| 67 | $handler = new PingQueueHandler($id); | ||
| 68 | |||
| 69 | $handler->runOnce(); |
scripts/pluginqueuehandler.php
(0 / 64)
|   | |||
| 1 | #!/usr/bin/env php | ||
| 2 | <?php | ||
| 3 | /* | ||
| 4 | * StatusNet - the distributed open-source microblogging tool | ||
| 5 | * Copyright (C) 2008, 2009, StatusNet, Inc. | ||
| 6 | * | ||
| 7 | * This program is free software: you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU Affero General Public License as published by | ||
| 9 | * the Free Software Foundation, either version 3 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU Affero General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Affero General Public License | ||
| 18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | */ | ||
| 20 | |||
| 21 | define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); | ||
| 22 | |||
| 23 | $shortoptions = 'i::'; | ||
| 24 | $longoptions = array('id::'); | ||
| 25 | |||
| 26 | $helptext = <<<END_OF_OMB_HELP | ||
| 27 | Daemon script for letting plugins handle stuff at queue time | ||
| 28 | |||
| 29 | -i --id Identity (default none) | ||
| 30 | |||
| 31 | END_OF_OMB_HELP; | ||
| 32 | |||
| 33 | require_once INSTALLDIR.'/scripts/commandline.inc'; | ||
| 34 | require_once INSTALLDIR . '/lib/queuehandler.php'; | ||
| 35 | |||
| 36 | class PluginQueueHandler extends QueueHandler | ||
| 37 | { | ||
| 38 | |||
| 39 | function transport() | ||
| 40 | { | ||
| 41 | return 'plugin'; | ||
| 42 | } | ||
| 43 | |||
| 44 | function start() | ||
| 45 | { | ||
| 46 | $this->log(LOG_INFO, "INITIALIZE"); | ||
| 47 | return true; | ||
| 48 | } | ||
| 49 | |||
| 50 | function handle_notice($notice) | ||
| 51 | { | ||
| 52 | Event::handle('HandleQueuedNotice', array(&$notice)); | ||
| 53 | return true; | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | if (have_option('i', 'id')) { | ||
| 58 | $id = get_option_value('i', 'id'); | ||
| 59 | } else { | ||
| 60 | $id = null; | ||
| 61 | } | ||
| 62 | |||
| 63 | $handler = new PluginQueueHandler($id); | ||
| 64 | $handler->runOnce(); |
scripts/publicqueuehandler.php
(0 / 76)
|   | |||
| 1 | #!/usr/bin/env php | ||
| 2 | <?php | ||
| 3 | /* | ||
| 4 | * StatusNet - the distributed open-source microblogging tool | ||
| 5 | * Copyright (C) 2008, 2009, StatusNet, Inc. | ||
| 6 | * | ||
| 7 | * This program is free software: you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU Affero General Public License as published by | ||
| 9 | * the Free Software Foundation, either version 3 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU Affero General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Affero General Public License | ||
| 18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | */ | ||
| 20 | |||
| 21 | define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); | ||
| 22 | |||
| 23 | $shortoptions = 'i::'; | ||
| 24 | $longoptions = array('id::'); | ||
| 25 | |||
| 26 | $helptext = <<<END_OF_PUBLIC_HELP | ||
| 27 | Daemon script for pushing new notices to public XMPP subscribers. | ||
| 28 | |||
| 29 | -i --id Identity (default none) | ||
| 30 | |||
| 31 | END_OF_PUBLIC_HELP; | ||
| 32 | |||
| 33 | require_once INSTALLDIR.'/scripts/commandline.inc'; | ||
| 34 | |||
| 35 | require_once INSTALLDIR . '/lib/jabber.php'; | ||
| 36 | require_once INSTALLDIR . '/lib/xmppqueuehandler.php'; | ||
| 37 | |||
| 38 | class PublicQueueHandler extends XmppQueueHandler | ||
| 39 | { | ||
| 40 | |||
| 41 | function transport() | ||
| 42 | { | ||
| 43 | return 'public'; | ||
| 44 | } | ||
| 45 | |||
| 46 | function handle_notice($notice) | ||
| 47 | { | ||
| 48 | try { | ||
| 49 | return jabber_public_notice($notice); | ||
| 50 | } catch (XMPPHP_Exception $e) { | ||
| 51 | $this->log(LOG_ERR, "Got an XMPPHP_Exception: " . $e->getMessage()); | ||
| 52 | die($e->getMessage()); | ||
| 53 | } | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | // Abort immediately if xmpp is not enabled, otherwise the daemon chews up | ||
| 58 | // lots of CPU trying to connect to unconfigured servers | ||
| 59 | if (common_config('xmpp','enabled')==false) { | ||
| 60 | print "Aborting daemon - xmpp is disabled\n"; | ||
| 61 | exit(); | ||
| 62 | } | ||
| 63 | |||
| 64 | if (have_option('i')) { | ||
| 65 | $id = get_option_value('i'); | ||
| 66 | } else if (have_option('--id')) { | ||
| 67 | $id = get_option_value('--id'); | ||
| 68 | } else if (count($args) > 0) { | ||
| 69 | $id = $args[0]; | ||
| 70 | } else { | ||
| 71 | $id = null; | ||
| 72 | } | ||
| 73 | |||
| 74 | $handler = new PublicQueueHandler($id); | ||
| 75 | |||
| 76 | $handler->runOnce(); |
scripts/queuedaemon.php
(264 / 0)
|   | |||
| 1 | #!/usr/bin/env php | ||
| 2 | <?php | ||
| 3 | /* | ||
| 4 | * StatusNet - the distributed open-source microblogging tool | ||
| 5 | * Copyright (C) 2008, 2009, StatusNet, Inc. | ||
| 6 | * | ||
| 7 | * This program is free software: you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU Affero General Public License as published by | ||
| 9 | * the Free Software Foundation, either version 3 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU Affero General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Affero General Public License | ||
| 18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | */ | ||
| 20 | |||
| 21 | define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); | ||
| 22 | |||
| 23 | $shortoptions = 'fi:at:'; | ||
| 24 | $longoptions = array('id=', 'foreground', 'all', 'threads='); | ||
| 25 | |||
| 26 | /** | ||
| 27 | * Attempts to get a count of the processors available on the current system | ||
| 28 | * to fan out multiple threads. | ||
| 29 | * | ||
| 30 | * Recognizes Linux and Mac OS X; others will return default of 1. | ||
| 31 | * | ||
| 32 | * @return intval | ||
| 33 | */ | ||
| 34 | function getProcessorCount() | ||
| 35 | { | ||
| 36 | $cpus = 0; | ||
| 37 | switch (PHP_OS) { | ||
| 38 | case 'Linux': | ||
| 39 | $cpuinfo = file('/proc/cpuinfo'); | ||
| 40 | foreach (file('/proc/cpuinfo') as $line) { | ||
| 41 | if (preg_match('/^processor\s+:\s+(\d+)\s?$/', $line)) { | ||
| 42 | $cpus++; | ||
| 43 | } | ||
| 44 | } | ||
| 45 | break; | ||
| 46 | case 'Darwin': | ||
| 47 | $cpus = intval(shell_exec("/usr/sbin/sysctl -n hw.ncpu 2>/dev/null")); | ||
| 48 | break; | ||
| 49 | } | ||
| 50 | if ($cpus) { | ||
| 51 | return $cpus; | ||
| 52 | } | ||
| 53 | return 1; | ||
| 54 | } | ||
| 55 | |||
| 56 | $threads = getProcessorCount(); | ||
| 57 | $helptext = <<<END_OF_QUEUE_HELP | ||
| 58 | Daemon script for running queued items. | ||
| 59 | |||
| 60 | -i --id Identity (default none) | ||
| 61 | -f --foreground Stay in the foreground (default background) | ||
| 62 | -a --all Handle queues for all local sites | ||
| 63 | (requires Stomp queue handler, status_network setup) | ||
| 64 | -t --threads=<n> Spawn <n> processing threads (default $threads) | ||
| 65 | |||
| 66 | |||
| 67 | END_OF_QUEUE_HELP; | ||
| 68 | |||
| 69 | require_once INSTALLDIR.'/scripts/commandline.inc'; | ||
| 70 | |||
| 71 | require_once(INSTALLDIR.'/lib/daemon.php'); | ||
| 72 | require_once(INSTALLDIR.'/classes/Queue_item.php'); | ||
| 73 | require_once(INSTALLDIR.'/classes/Notice.php'); | ||
| 74 | |||
| 75 | define('CLAIM_TIMEOUT', 1200); | ||
| 76 | |||
| 77 | /** | ||
| 78 | * Queue handling daemon... | ||
| 79 | * | ||
| 80 | * The queue daemon by default launches in the background, at which point | ||
| 81 | * it'll pass control to the configured QueueManager class to poll for updates. | ||
| 82 | * | ||
| 83 | * We can then pass individual items through the QueueHandler subclasses | ||
| 84 | * they belong to. | ||
| 85 | */ | ||
| 86 | class QueueDaemon extends Daemon | ||
| 87 | { | ||
| 88 | protected $allsites; | ||
| 89 | protected $threads=1; | ||
| 90 | |||
| 91 | function __construct($id=null, $daemonize=true, $threads=1, $allsites=false) | ||
| 92 | { | ||
| 93 | parent::__construct($daemonize); | ||
| 94 | |||
| 95 | if ($id) { | ||
| 96 | $this->set_id($id); | ||
| 97 | } | ||
| 98 | $this->all = $allsites; | ||
| 99 | $this->threads = $threads; | ||
| 100 | } | ||
| 101 | |||
| 102 | /** | ||
| 103 | * How many seconds a polling-based queue manager should wait between | ||
| 104 | * checks for new items to handle. | ||
| 105 | * | ||
| 106 | * Defaults to 60 seconds; override to speed up or slow down. | ||
| 107 | * | ||
| 108 | * @return int timeout in seconds | ||
| 109 | */ | ||
| 110 | function timeout() | ||
| 111 | { | ||
| 112 | return 60; | ||
| 113 | } | ||
| 114 | |||
| 115 | function name() | ||
| 116 | { | ||
| 117 | return strtolower(get_class($this).'.'.$this->get_id()); | ||
| 118 | } | ||
| 119 | |||
| 120 | function run() | ||
| 121 | { | ||
| 122 | if ($this->threads > 1) { | ||
| 123 | return $this->runThreads(); | ||
| 124 | } else { | ||
| 125 | return $this->runLoop(); | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | function runThreads() | ||
| 130 | { | ||
| 131 | $children = array(); | ||
| 132 | for ($i = 1; $i <= $this->threads; $i++) { | ||
| 133 | $pid = pcntl_fork(); | ||
| 134 | if ($pid < 0) { | ||
| 135 | print "Couldn't fork for thread $i; aborting\n"; | ||
| 136 | exit(1); | ||
| 137 | } else if ($pid == 0) { | ||
| 138 | $this->runChild($i); | ||
| 139 | exit(0); | ||
| 140 | } else { | ||
| 141 | $this->log(LOG_INFO, "Spawned thread $i as pid $pid"); | ||
| 142 | $children[$i] = $pid; | ||
| 143 | } | ||
| 144 | } | ||
| 145 | |||
| 146 | $this->log(LOG_INFO, "Waiting for children to complete."); | ||
| 147 | while (count($children) > 0) { | ||
| 148 | $status = null; | ||
| 149 | $pid = pcntl_wait($status); | ||
| 150 | if ($pid > 0) { | ||
| 151 | $i = array_search($pid, $children); | ||
| 152 | if ($i === false) { | ||
| 153 | $this->log(LOG_ERR, "Unrecognized child pid $pid exited!"); | ||
| 154 | continue; | ||
| 155 | } | ||
| 156 | unset($children[$i]); | ||
| 157 | $this->log(LOG_INFO, "Thread $i pid $pid exited."); | ||
| 158 | |||
| 159 | $pid = pcntl_fork(); | ||
| 160 | if ($pid < 0) { | ||
| 161 | print "Couldn't fork to respawn thread $i; aborting thread.\n"; | ||
| 162 | } else if ($pid == 0) { | ||
| 163 | $this->runChild($i); | ||
| 164 | exit(0); | ||
| 165 | } else { | ||
| 166 | $this->log(LOG_INFO, "Respawned thread $i as pid $pid"); | ||
| 167 | $children[$i] = $pid; | ||
| 168 | } | ||
| 169 | } | ||
| 170 | } | ||
| 171 | $this->log(LOG_INFO, "All child processes complete."); | ||
| 172 | return true; | ||
| 173 | } | ||
| 174 | |||
| 175 | function runChild($thread) | ||
| 176 | { | ||
| 177 | $this->set_id($this->get_id() . "." . $thread); | ||
| 178 | $this->resetDb(); | ||
| 179 | $this->runLoop(); | ||
| 180 | } | ||
| 181 | |||
| 182 | /** | ||
| 183 | * Reconnect to the database for each child process, | ||
| 184 | * or they'll get very confused trying to use the | ||
| 185 | * same socket. | ||
| 186 | */ | ||
| 187 | function resetDb() | ||
| 188 | { | ||
| 189 | // @fixme do we need to explicitly open the db too | ||
| 190 | // or is this implied? | ||
| 191 | global $_DB_DATAOBJECT; | ||
| 192 | unset($_DB_DATAOBJECT['CONNECTIONS']); | ||
| 193 | |||
| 194 | // Reconnect main memcached, or threads will stomp on | ||
| 195 | // each other and corrupt their requests. | ||
| 196 | $cache = common_memcache(); | ||
| 197 | if ($cache) { | ||
| 198 | $cache->reconnect(); | ||
| 199 | } | ||
| 200 | |||
| 201 | // Also reconnect memcached for status_network table. | ||
| 202 | if (!empty(Status_network::$cache)) { | ||
| 203 | Status_network::$cache->close(); | ||
| 204 | Status_network::$cache = null; | ||
| 205 | } | ||
| 206 | } | ||
| 207 | |||
| 208 | /** | ||
| 209 | * Setup and start of run loop for this queue handler as a daemon. | ||
| 210 | * Most of the heavy lifting is passed on to the QueueManager's service() | ||
| 211 | * method, which passes control on to the QueueHandler's handle_notice() | ||
| 212 | * method for each notice that comes in on the queue. | ||
| 213 | * | ||
| 214 | * Most of the time this won't need to be overridden in a subclass. | ||
| 215 | * | ||
| 216 | * @return boolean true on success, false on failure | ||
| 217 | */ | ||
| 218 | function runLoop() | ||
| 219 | { | ||
| 220 | $this->log(LOG_INFO, 'checking for queued notices'); | ||
| 221 | |||
| 222 | $master = new IoMaster($this->get_id()); | ||
| 223 | $master->init($this->all); | ||
| 224 | $master->service(); | ||
| 225 | |||
| 226 | $this->log(LOG_INFO, 'finished servicing the queue'); | ||
| 227 | |||
| 228 | $this->log(LOG_INFO, 'terminating normally'); | ||
| 229 | |||
| 230 | return true; | ||
| 231 | } | ||
| 232 | |||
| 233 | function log($level, $msg) | ||
| 234 | { | ||
| 235 | common_log($level, get_class($this) . ' ('. $this->get_id() .'): '.$msg); | ||
| 236 | } | ||
| 237 | } | ||
| 238 | |||
| 239 | if (have_option('i')) { | ||
| 240 | $id = get_option_value('i'); | ||
| 241 | } else if (have_option('--id')) { | ||
| 242 | $id = get_option_value('--id'); | ||
| 243 | } else if (count($args) > 0) { | ||
| 244 | $id = $args[0]; | ||
| 245 | } else { | ||
| 246 | $id = null; | ||
| 247 | } | ||
| 248 | |||
| 249 | if (have_option('t')) { | ||
| 250 | $threads = intval(get_option_value('t')); | ||
| 251 | } else if (have_option('--threads')) { | ||
| 252 | $threads = intval(get_option_value('--threads')); | ||
| 253 | } else { | ||
| 254 | $threads = 0; | ||
| 255 | } | ||
| 256 | if (!$threads) { | ||
| 257 | $threads = getProcessorCount(); | ||
| 258 | } | ||
| 259 | |||
| 260 | $daemonize = !(have_option('f') || have_option('--foreground')); | ||
| 261 | $all = have_option('a') || have_option('--all'); | ||
| 262 | |||
| 263 | $daemon = new QueueDaemon($id, $daemonize, $threads, $all); | ||
| 264 | $daemon->runOnce(); |
scripts/smsqueuehandler.php
(0 / 73)
|   | |||
| 1 | #!/usr/bin/env php | ||
| 2 | <?php | ||
| 3 | /* | ||
| 4 | * StatusNet - the distributed open-source microblogging tool | ||
| 5 | * Copyright (C) 2008, 2009, StatusNet, Inc. | ||
| 6 | * | ||
| 7 | * This program is free software: you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU Affero General Public License as published by | ||
| 9 | * the Free Software Foundation, either version 3 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU Affero General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Affero General Public License | ||
| 18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | */ | ||
| 20 | |||
| 21 | define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); | ||
| 22 | |||
| 23 | $shortoptions = 'i::'; | ||
| 24 | $longoptions = array('id::'); | ||
| 25 | |||
| 26 | $helptext = <<<END_OF_SMS_HELP | ||
| 27 | Daemon script for pushing new notices to local subscribers using SMS. | ||
| 28 | |||
| 29 | -i --id Identity (default none) | ||
| 30 | |||
| 31 | END_OF_SMS_HELP; | ||
| 32 | |||
| 33 | require_once INSTALLDIR.'/scripts/commandline.inc'; | ||
| 34 | |||
| 35 | require_once INSTALLDIR . '/lib/mail.php'; | ||
| 36 | require_once INSTALLDIR . '/lib/queuehandler.php'; | ||
| 37 | |||
| 38 | class SmsQueueHandler extends QueueHandler | ||
| 39 | { | ||
| 40 | function transport() | ||
| 41 | { | ||
| 42 | return 'sms'; | ||
| 43 | } | ||
| 44 | |||
| 45 | function start() | ||
| 46 | { | ||
| 47 | $this->log(LOG_INFO, "INITIALIZE"); | ||
| 48 | return true; | ||
| 49 | } | ||
| 50 | |||
| 51 | function handle_notice($notice) | ||
| 52 | { | ||
| 53 | return mail_broadcast_notice_sms($notice); | ||
| 54 | } | ||
| 55 | |||
| 56 | function finish() | ||
| 57 | { | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | if (have_option('i')) { | ||
| 62 | $id = get_option_value('i'); | ||
| 63 | } else if (have_option('--id')) { | ||
| 64 | $id = get_option_value('--id'); | ||
| 65 | } else if (count($args) > 0) { | ||
| 66 | $id = $args[0]; | ||
| 67 | } else { | ||
| 68 | $id = null; | ||
| 69 | } | ||
| 70 | |||
| 71 | $handler = new SmsQueueHandler($id); | ||
| 72 | |||
| 73 | $handler->runOnce(); |
scripts/xmppconfirmhandler.php
(0 / 160)
|   | |||
| 1 | #!/usr/bin/env php | ||
| 2 | <?php | ||
| 3 | /* | ||
| 4 | * StatusNet - the distributed open-source microblogging tool | ||
| 5 | * Copyright (C) 2008, 2009, StatusNet, Inc. | ||
| 6 | * | ||
| 7 | * This program is free software: you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU Affero General Public License as published by | ||
| 9 | * the Free Software Foundation, either version 3 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU Affero General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Affero General Public License | ||
| 18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | */ | ||
| 20 | |||
| 21 | define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); | ||
| 22 | |||
| 23 | $shortoptions = 'i::'; | ||
| 24 | $longoptions = array('id::'); | ||
| 25 | |||
| 26 | $helptext = <<<END_OF_JABBER_HELP | ||
| 27 | Daemon script for pushing new confirmations to Jabber users. | ||
| 28 | |||
| 29 | -i --id Identity (default none) | ||
| 30 | |||
| 31 | END_OF_JABBER_HELP; | ||
| 32 | |||
| 33 | require_once INSTALLDIR.'/scripts/commandline.inc'; | ||
| 34 | require_once INSTALLDIR . '/lib/jabber.php'; | ||
| 35 | require_once INSTALLDIR . '/lib/xmppqueuehandler.php'; | ||
| 36 | |||
| 37 | class XmppConfirmHandler extends XmppQueueHandler | ||
| 38 | { | ||
| 39 | var $_id = 'confirm'; | ||
| 40 | |||
| 41 | function class_name() | ||
| 42 | { | ||
| 43 | return 'XmppConfirmHandler'; | ||
| 44 | } | ||
| 45 | |||
| 46 | function run() | ||
| 47 | { | ||
| 48 | if (!$this->start()) { | ||
| 49 | return false; | ||
| 50 | } | ||
| 51 | $this->log(LOG_INFO, 'checking for queued confirmations'); | ||
| 52 | do { | ||
| 53 | $confirm = $this->next_confirm(); | ||
| 54 | if ($confirm) { | ||
| 55 | $this->log(LOG_INFO, 'Sending confirmation for ' . $confirm->address); | ||
| 56 | $user = User::staticGet($confirm->user_id); | ||
| 57 | if (!$user) { | ||
| 58 | $this->log(LOG_WARNING, 'Confirmation for unknown user ' . $confirm->user_id); | ||
| 59 | continue; | ||
| 60 | } | ||
| 61 | $success = jabber_confirm_address($confirm->code, | ||
| 62 | $user->nickname, | ||
| 63 | $confirm->address); | ||
| 64 | if (!$success) { | ||
| 65 | $this->log(LOG_ERR, 'Confirmation failed for ' . $confirm->address); | ||
| 66 | # Just let the claim age out; hopefully things work then | ||
| 67 | continue; | ||
| 68 | } else { | ||
| 69 | $this->log(LOG_INFO, 'Confirmation sent for ' . $confirm->address); | ||
| 70 | # Mark confirmation sent; need a dupe so we don't have the WHERE clause | ||
| 71 | $dupe = Confirm_address::staticGet('code', $confirm->code); | ||
| 72 | if (!$dupe) { | ||
| 73 | common_log(LOG_WARNING, 'Could not refetch confirm', __FILE__); | ||
| 74 | continue; | ||
| 75 | } | ||
| 76 | $orig = clone($dupe); | ||
| 77 | $dupe->sent = $dupe->claimed; | ||
| 78 | $result = $dupe->update($orig); | ||
| 79 | if (!$result) { | ||
| 80 | common_log_db_error($dupe, 'UPDATE', __FILE__); | ||
| 81 | # Just let the claim age out; hopefully things work then | ||
| 82 | continue; | ||
| 83 | } | ||
| 84 | $dupe->free(); | ||
| 85 | unset($dupe); | ||
| 86 | } | ||
| 87 | $user->free(); | ||
| 88 | unset($user); | ||
| 89 | $confirm->free(); | ||
| 90 | unset($confirm); | ||
| 91 | $this->idle(0); | ||
| 92 | } else { | ||
| 93 | # $this->clear_old_confirm_claims(); | ||
| 94 | $this->idle(10); | ||
| 95 | } | ||
| 96 | } while (true); | ||
| 97 | if (!$this->finish()) { | ||
| 98 | return false; | ||
| 99 | } | ||
| 100 | return true; | ||
| 101 | } | ||
| 102 | |||
| 103 | function next_confirm() | ||
| 104 | { | ||
| 105 | $confirm = new Confirm_address(); | ||
| 106 | $confirm->whereAdd('claimed IS null'); | ||
| 107 | $confirm->whereAdd('sent IS null'); | ||
| 108 | # XXX: eventually we could do other confirmations in the queue, too | ||
| 109 | $confirm->address_type = 'jabber'; | ||
| 110 | $confirm->orderBy('modified DESC'); | ||
| 111 | $confirm->limit(1); | ||
| 112 | if ($confirm->find(true)) { | ||
| 113 | $this->log(LOG_INFO, 'Claiming confirmation for ' . $confirm->address); | ||
| 114 | # working around some weird DB_DataObject behaviour | ||
| 115 | $confirm->whereAdd(''); # clears where stuff | ||
| 116 | $original = clone($confirm); | ||
| 117 | $confirm->claimed = common_sql_now(); | ||
| 118 | $result = $confirm->update($original); | ||
| 119 | if ($result) { | ||
| 120 | $this->log(LOG_INFO, 'Succeeded in claim! '. $result); | ||
| 121 | return $confirm; | ||
| 122 | } else { | ||
| 123 | $this->log(LOG_INFO, 'Failed in claim!'); | ||
| 124 | return false; | ||
| 125 | } | ||
| 126 | } | ||
| 127 | return null; | ||
| 128 | } | ||
| 129 | |||
| 130 | function clear_old_confirm_claims() | ||
| 131 | { | ||
| 132 | $confirm = new Confirm(); | ||
| 133 | $confirm->claimed = null; | ||
| 134 | $confirm->whereAdd('now() - claimed > '.CLAIM_TIMEOUT); | ||
| 135 | $confirm->update(DB_DATAOBJECT_WHEREADD_ONLY); | ||
| 136 | $confirm->free(); | ||
| 137 | unset($confirm); | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 141 | // Abort immediately if xmpp is not enabled, otherwise the daemon chews up | ||
| 142 | // lots of CPU trying to connect to unconfigured servers | ||
| 143 | if (common_config('xmpp','enabled')==false) { | ||
| 144 | print "Aborting daemon - xmpp is disabled\n"; | ||
| 145 | exit(); | ||
| 146 | } | ||
| 147 | |||
| 148 | if (have_option('i')) { | ||
| 149 | $id = get_option_value('i'); | ||
| 150 | } else if (have_option('--id')) { | ||
| 151 | $id = get_option_value('--id'); | ||
| 152 | } else if (count($args) > 0) { | ||
| 153 | $id = $args[0]; | ||
| 154 | } else { | ||
| 155 | $id = null; | ||
| 156 | } | ||
| 157 | |||
| 158 | $handler = new XmppConfirmHandler($id); | ||
| 159 | |||
| 160 | $handler->runOnce(); |

