]> git.mxchange.org Git - quix0rs-gnu-social.git/blobdiff - plugins/Irc/ircmanager.php
Localisation updates from http://translatewiki.net.
[quix0rs-gnu-social.git] / plugins / Irc / ircmanager.php
index 8c04da68fcba19fb0a8dbb28d9dce02713f3de0b..d9637352515d291a6408fb8b67f01281f2cfc2a4 100644 (file)
@@ -23,17 +23,22 @@ 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,16 +69,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.
+     *
+     * @return void
+     */
+    public function idle() {
+        // 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->receive();
+
+        try {
+            $this->conn->handleEvents();
+        } catch (Phergie_Driver_Exception $e) {
+            $this->connected = false;
+            $this->conn->reconnect();
+        }
     }
 
     /**
@@ -91,7 +153,7 @@ class IrcManager extends ImManager {
                     'connections' => array(
                         array(
                             'host' => $this->plugin->host,
-                            'port' => $port,
+                            'port' => $this->plugin->port,
                             'username' => $this->plugin->username,
                             'realname' => $this->plugin->realname,
                             'nick' => $this->plugin->nick,
@@ -104,7 +166,7 @@ class IrcManager extends ImManager {
                     'driver' => 'statusnet',
 
                     'processor' => 'async',
-                    'processor.options' => array('usec' => 0),
+                    'processor.options' => array('sec' => 0, 'usec' => 0),
 
                     'plugins' => array(
                         'Pong',
@@ -115,31 +177,39 @@ 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,
+
                     'autojoin.channels' => $this->plugin->channels,
+
                     'statusnet.messagecallback' => array($this, 'handle_irc_message'),
-                    'statusnet.regcallback' => array($this, 'handle_reg_response')
+                    'statusnet.regcallback' => array($this, 'handle_reg_response'),
+                    'statusnet.connectedcallback' => array($this, 'handle_connected'),
+                    'statusnet.unregregexp' => $this->plugin->unregregexp,
+                    'statusnet.regregexp' => $this->plugin->regregexp
                 )
             );
 
             $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;
     }
 
@@ -153,15 +223,15 @@ 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'));
+                $this->plugin->sendMessage($screenname, _m('Your nickname is not registered so IRC connectivity cannot be enabled'));
 
                 $confirm = new Confirm_address();
 
@@ -174,24 +244,57 @@ 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.'));
+                        $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__);
+            throw new ServerException('DB 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) {
@@ -200,28 +303,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;
+            }
         }
 
         try {
             $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);
+    }
 }