3 * StatusNet - the distributed open-source microblogging tool
\r
4 * Copyright (C) 2008, 2009, StatusNet, Inc.
\r
6 * This program is free software: you can redistribute it and/or modify
\r
7 * it under the terms of the GNU Affero General Public License as published by
\r
8 * the Free Software Foundation, either version 3 of the License, or
\r
9 * (at your option) any later version.
\r
11 * This program is distributed in the hope that it will be useful,
\r
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
14 * GNU Affero General Public License for more details.
\r
16 * You should have received a copy of the GNU Affero General Public License
\r
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
\r
20 if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
\r
23 * MSN background connection manager for MSN-using queue handlers,
\r
24 * allowing them to send outgoing messages on the right connection.
\r
26 * Input is handled during socket select loop, keepalive pings during idle.
\r
27 * Any incoming messages will be handled.
\r
29 * In a multi-site queuedaemon.php run, one connection will be instantiated
\r
30 * for each site being handled by the current process that has MSN enabled.
\r
32 class MsnManager extends ImManager {
\r
33 public $conn = null;
\r
34 protected $lastPing = null;
\r
35 protected $pingInterval;
\r
38 * Initialise connection to server.
\r
40 * @return boolean true on success
\r
42 public function start($master) {
\r
43 if (parent::start($master)) {
\r
44 $this->requeue_waiting_messages();
\r
53 * Return any open sockets that the run loop should listen
\r
56 * @return array Array of socket resources
\r
58 public function getSockets() {
\r
61 return $this->conn->getSockets();
\r
68 * Idle processing for io manager's execution loop.
\r
69 * Send keepalive pings to server.
\r
73 public function idle($timeout = 0) {
\r
74 if (empty($this->lastPing) || time() - $this->lastPing > $this->pingInterval) {
\r
80 * Message pump is triggered on socket input, so we only need an idle()
\r
81 * call often enough to trigger our outgoing pings.
\r
83 public function timeout() {
\r
84 return $this->pingInterval;
\r
88 * Process MSN events that have come in over the wire.
\r
90 * @param resource $socket Socket ready
\r
93 public function handleInput($socket) {
\r
94 common_log(LOG_DEBUG, 'Servicing the MSN queue.');
\r
95 $this->stats('msn_process');
\r
96 $this->conn->receive();
\r
100 * Initiate connection
\r
104 public function connect() {
\r
105 if (!$this->conn) {
\r
106 $this->conn = new MSN(
\r
108 'user' => $this->plugin->user,
\r
109 'password' => $this->plugin->password,
\r
110 'alias' => $this->plugin->nickname,
\r
111 // TRANS: MSN bot status message.
\r
112 'psm' => _m('Send me a message to post a notice'),
\r
116 $this->conn->registerHandler('IMin', array($this, 'handle_msn_message'));
\r
117 $this->conn->registerHandler('SessionReady', array($this, 'handle_session_ready'));
\r
118 $this->conn->registerHandler('Pong', array($this, 'update_ping_time'));
\r
119 $this->conn->registerHandler('ConnectFailed', array($this, 'handle_connect_failed'));
\r
120 $this->conn->registerHandler('Reconnect', array($this, 'handle_reconnect'));
\r
121 $this->conn->signon();
\r
122 $this->lastPing = time();
\r
124 return $this->conn;
\r
128 * Called by the idle process to send a ping
\r
133 protected function send_ping() {
\r
135 if (!$this->conn) {
\r
139 $this->conn->sendPing();
\r
140 $this->lastPing = time();
\r
141 $this->pingInterval = 50;
\r
146 * Update the time till the next ping
\r
148 * @param $data Time till next ping
\r
151 public function update_ping_time($data) {
\r
152 $this->pingInterval = $data;
\r
156 * Called via a callback when a message is received
\r
158 * Passes it back to the queuing system
\r
160 * @param array $data Data
\r
163 public function handle_msn_message($data) {
\r
164 $this->plugin->enqueueIncomingRaw($data);
\r
169 * Called via a callback when a session becomes ready
\r
171 * @param array $data Data
\r
173 public function handle_session_ready($data) {
\r
174 $sessionFailed = false;
\r
175 $wm = Msn_waiting_message::top($data['to']);
\r
176 while ($wm != NULL) {
\r
177 if ($sessionFailed) {
\r
178 $this->plugin->sendMessage($wm->screenname, $wm->message);
\r
179 $sessionFailed = true;
\r
180 } elseif (!$this->conn->sendMessage($wm->screenname, $wm->message, $ignore)) {
\r
181 $this->plugin->sendMessage($wm->screenname, $wm->message);
\r
185 $wm = Msn_waiting_message::top($data['to']);
\r
190 * Requeue messages from the waiting table so we try
\r
191 * to send them again
\r
195 protected function requeue_waiting_messages() {
\r
196 $wm = Msn_waiting_message::top();
\r
197 while ($wm != NULL) {
\r
198 $this->plugin->sendMessage($wm->screenname, $wm->message);
\r
200 $wm = Msn_waiting_message::top();
\r
205 * Called by callback to log failure during connect
\r
207 * @param string $message error message reported
\r
210 public function handle_connect_failed($message) {
\r
211 common_log(LOG_NOTICE, 'MSN connect failed, retrying: ' . $message);
\r
215 * Called by callback to log reconnection
\r
217 * @param void $data Not used (there to keep callback happy)
\r
220 public function handle_reconnect($data) {
\r
221 common_log(LOG_NOTICE, 'MSN reconnecting');
\r
222 // Requeue messages waiting in the DB
\r
223 $this->requeue_waiting_messages();
\r
227 * Enters a message into the database for sending via a callback
\r
228 * when the session is established
\r
230 * @param string $to Intended recipient
\r
231 * @param string $message Message
\r
233 protected function enqueue_waiting_message($to, $message) {
\r
234 $wm = new Msn_waiting_message();
\r
236 $wm->screenname = $to;
\r
237 $wm->message = $message;
\r
238 $wm->created = common_sql_now();
\r
239 $result = $wm->insert();
\r
242 common_log_db_error($wm, 'INSERT', __FILE__);
\r
243 // TRANS: Server exception thrown when a message to be sent through MSN cannot be added to the database queue.
\r
244 throw new ServerException(_m('Database error inserting queue item.'));
\r
251 * Send a message using the daemon
\r
253 * @param $data Message data
\r
254 * @return boolean true on success
\r
256 public function send_raw_message($data) {
\r
258 if (!$this->conn) {
\r
262 $waitForSession = false;
\r
263 if (!$this->conn->sendMessage($data['to'], $data['message'], $waitForSession)) {
\r
264 if ($waitForSession) {
\r
265 $this->enqueue_waiting_message($data['to'], $data['message']);
\r
271 // Sending a command updates the time till next ping
\r
272 $this->lastPing = time();
\r
273 $this->pingInterval = 50;
\r