X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=plugins%2FIrc%2Fircmanager.php;h=3c0a504eb06c80a384e5c39ae271c017c1a312f0;hb=c97048d01bea468e0cf8865b60c3c250b4515c39;hp=8042ae24c2633a079812f1c4c14cbbefcfd099d8;hpb=3c1d7d81cf76fbd358885ed4ec540871236072f8;p=quix0rs-gnu-social.git diff --git a/plugins/Irc/ircmanager.php b/plugins/Irc/ircmanager.php index 8042ae24c2..3c0a504eb0 100644 --- a/plugins/Irc/ircmanager.php +++ b/plugins/Irc/ircmanager.php @@ -23,17 +23,21 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } * IRC background connection manager for IRC-using queue handlers, * allowing them to send outgoing messages on the right connection. * - * Input is handled during socket select loop, keepalive pings during idle. - * Any incoming messages will be handled. + * Input is handled during socket select loop, Any incoming messages will be handled. * * In a multi-site queuedaemon.php run, one connection will be instantiated * for each site being handled by the current process that has IRC enabled. */ - class IrcManager extends ImManager { - public $conn = null; - public $regchecks = array(); - public $regchecksLookup = array(); + protected $conn = null; + protected $lastPing = null; + protected $messageWaiting = true; + protected $lastMessage = null; + + protected $regChecks = array(); + protected $regChecksLookup = array(); + + protected $connected = false; /** * Initialize connection to server. @@ -64,29 +68,73 @@ class IrcManager extends ImManager { } } - + /** + * Request a maximum timeout for listeners before the next idle period. + * + * @return integer Maximum timeout + */ + public function timeout() { + if ($this->messageWaiting) { + return 1; + } else { + return $this->plugin->pinginterval; + } + } /** * Idle processing for io manager's execution loop. - * Send keepalive pings to server. * * @return void */ public function idle() { - // Call Phergie's doTick methods if necessary - $this->conn->handleEvents(); + // Send a ping if necessary + if (empty($this->lastPing) || time() - $this->lastPing > $this->plugin->pinginterval) { + $this->sendPing(); + } + + if ($this->connected) { + // Send a waiting message if appropriate + if ($this->messageWaiting && time() - $this->lastMessage > 1) { + $wm = Irc_waiting_message::top(); + if ($wm === NULL) { + $this->messageWaiting = false; + return; + } + + $data = unserialize($wm->data); + $wm->incAttempts(); + + if ($this->send_raw_message($data)) { + $wm->delete(); + } else { + if ($wm->attempts <= common_config('queue', 'max_retries')) { + // Try again next idle + $wm->releaseClaim(); + } else { + // Exceeded the maximum number of retries + $wm->delete(); + } + } + } + } } /** * Process IRC events that have come in over the wire. * - * @param resource $socket + * @param resource $socket Socket to handle input on * @return void */ public function handleInput($socket) { common_log(LOG_DEBUG, 'Servicing the IRC queue.'); $this->stats('irc_process'); - $this->conn->handleEvents(); + + try { + $this->conn->handleEvents(); + } catch (Phergie_Driver_Exception $e) { + $this->connected = false; + $this->conn->reconnect(); + } } /** @@ -128,7 +176,8 @@ class IrcManager extends ImManager { 'plugins.autoload' => true, - 'ui.enabled' => true, + // Uncomment to enable debugging output + //'ui.enabled' => true, 'nickserv.password' => $this->plugin->nickservpassword, 'nickserv.identify_message' => $this->plugin->nickservidentifyregexp, @@ -137,6 +186,7 @@ class IrcManager extends ImManager { 'statusnet.messagecallback' => array($this, 'handle_irc_message'), 'statusnet.regcallback' => array($this, 'handle_reg_response'), + 'statusnet.connectedcallback' => array($this, 'handle_connected'), 'statusnet.unregregexp' => $this->plugin->unregregexp, 'statusnet.regregexp' => $this->plugin->regregexp ) @@ -144,20 +194,21 @@ class IrcManager extends ImManager { $this->conn->setConfig($config); $this->conn->connect(); + $this->lastPing = time(); + $this->lastMessage = time(); } return $this->conn; } /** * Called via a callback when a message is received - * * Passes it back to the queuing system * * @param array $data Data * @return boolean */ public function handle_irc_message($data) { - $this->plugin->enqueue_incoming_raw($data); + $this->plugin->enqueueIncomingRaw($data); return true; } @@ -171,15 +222,16 @@ class IrcManager extends ImManager { public function handle_reg_response($data) { // Retrieve data $screenname = $data['screenname']; - $nickdata = $this->regchecks[$screenname]; + $nickdata = $this->regChecks[$screenname]; $usernick = $nickdata['user']->nickname; - if (isset($this->regchecksLookup[$usernick])) { + if (isset($this->regChecksLookup[$usernick])) { if ($data['registered']) { // Send message - $this->plugin->send_confirmation_code($screenname, $nickdata['code'], $nickdata['user'], true); + $this->plugin->sendConfirmationCode($screenname, $nickdata['code'], $nickdata['user'], true); } else { - $this->plugin->send_message($screenname, _m('Your nickname is not registered so IRC connectivity cannot be enabled')); + // TRANS: Message given when using an unregistered IRC nickname. + $this->plugin->sendMessage($screenname, _m('Your nickname is not registered so IRC connectivity cannot be enabled.')); $confirm = new Confirm_address(); @@ -191,25 +243,59 @@ class IrcManager extends ImManager { if (!$result) { common_log_db_error($confirm, 'DELETE', __FILE__); - // TRANS: Server error thrown on database error canceling IM address confirmation. - $this->serverError(_('Couldn\'t delete confirmation.')); + // TRANS: Server error thrown on database error when deleting IRC nickname confirmation. + $this->serverError(_m('Could not delete confirmation.')); return; } } } // Unset lookup value - unset($this->regchecksLookup[$usernick]); + unset($this->regChecksLookup[$usernick]); // Unset data - unset($this->regchecks[$screename]); + unset($this->regChecks[$screename]); } } + /** + * Called when the connection is established + * + * @return void + */ + public function handle_connected() { + $this->connected = true; + } + + /** + * Enters a message into the database for sending when ready + * + * @param string $command Command + * @param array $args Arguments + * @return boolean + */ + protected function enqueue_waiting_message($data) { + $wm = new Irc_waiting_message(); + + $wm->data = serialize($data); + $wm->prioritise = $data['prioritise']; + $wm->attempts = 0; + $wm->created = common_sql_now(); + $result = $wm->insert(); + + if (!$result) { + common_log_db_error($wm, 'INSERT', __FILE__); + // TRANS: Server exception thrown when an IRC waiting queue item could not be added to the database. + throw new ServerException(_m('Database error inserting IRC waiting queue item.')); + } + + return true; + } + /** * Send a message using the daemon * - * @param $data Message + * @param $data Message data * @return boolean true on success */ public function send_raw_message($data) { @@ -218,32 +304,55 @@ class IrcManager extends ImManager { return false; } - if ($data['type'] != 'message') { - // Nick checking - $nickdata = $data['nickdata']; - $usernick = $nickdata['user']->nickname; - $screenname = $nickdata['screenname']; + if ($data['type'] != 'delayedmessage') { + if ($data['type'] != 'message') { + // Nick checking + $nickdata = $data['nickdata']; + $usernick = $nickdata['user']->nickname; + $screenname = $nickdata['screenname']; + + // Cancel any existing checks for this user + if (isset($this->regChecksLookup[$usernick])) { + unset($this->regChecks[$this->regChecksLookup[$usernick]]); + } - // Cancel any existing checks for this user - if (isset($this->regchecksLookup[$usernick])) { - unset($this->regchecks[$this->regchecksLookup[$usernick]]); + $this->regChecks[$screenname] = $nickdata; + $this->regChecksLookup[$usernick] = $screenname; } - $this->regchecks[$screenname] = $nickdata; - $this->regchecksLookup[$usernick] = $screenname; + // If there is a backlog or we need to wait, queue the message + if ($this->messageWaiting || time() - $this->lastMessage < 1) { + $this->enqueue_waiting_message( + array( + 'type' => 'delayedmessage', + 'prioritise' => $data['prioritise'], + 'data' => $data['data'] + ) + ); + $this->messageWaiting = true; + return true; + } } - $args = $data['data']['args']; - $lines = explode("\n", $args[1]); try { - foreach ($lines as $line) { - $this->conn->send($data['data']['command'], array($args[0], $line)); - } + $this->conn->send($data['data']['command'], $data['data']['args']); } catch (Phergie_Driver_Exception $e) { + $this->connected = false; $this->conn->reconnect(); return false; } + $this->lastMessage = time(); return true; } + + /** + * Sends a ping + * + * @return void + */ + protected function sendPing() { + $this->lastPing = time(); + $this->conn->send('PING', $this->lastPing); + } }