Как стать автором
Обновить

ICQ баг-информер на PHP + ActiveMQ

Время на прочтение9 мин
Количество просмотров9.8K
Я являюсь разработчиком и смотрителем довольно крупной системы он-лайн бронирования одного из московских туроператоров. Поскольку к этой системе предъявляются весьма высокие требования в плане надежности и безопасности, мне приходится отслеживать все возникающие в ней ошибки, однако постоянно заходить и просматривать, нет ли новых отчетов, не очень удобно и поэтому возникла необходимость в неком средстве мгновенного оповещения, причем оно должно поддерживать возможность отправки сообщений как из веб-части, так и из десктопных приложений.

В этой статье я хочу рассказать о своем опыте написания скрипта для мгновенного оповещения о возникающих в системе ошибках посредством ICQ сообщений. В качестве промежуточного звена и накопителя репортов используется брокер сообщений ActiveMQ, я расскажу как его установить и настроить для работы с MySQL. Главная часть — это ICQ-бот, написанный на PHP, в его обязанности входит прослушивание определенного канала в брокере и пересылка сообщений на указанные номера ICQ. Также я расскажу как запустить этот PHP скрипт в качестве службы Windows.


Схема работы данной системы следующая: приложение (веб или десктопное) при возникновении ошибки формирует некое XML-сообщение, в котором содержится краткое описание ошибки и ICQ-номер получателя. Это сообщение отправляется по STOMP протоколу брокеру ActiveMQ и попадает в очередь. На другом конце света или на той же машине находится ICQ-бот, который слушает эту очередь и при попадании в нее сообщения тут же пересылает его по указанному адресу. А теперь в деталях.

Установка и настройка ActiveMQ


Все программы будут ставиться под Windows. Пару слов о самом ActiceMQ, он представляет собой брокер сообщений, в котором есть 2 основных понятия: очереди (Queue) и темы (Topic).
Topic предназначен для оповещения большого числа подписчиков о каком-нибудь событии, например новость или выход очередного патча.
Queue представляет собой очередь заданий, на нее может быть подписано несколько слушателей, но любое сообщение получит только один из подписчиков, это как раз нам подходит.

Для начала качаем дистрибутив. Установка сводится к распаковке архива в какую-нибудь далекую папку. Для удобства работы установим его как службу Windows, для этого необходимо запустить скрипт ActiveMQ\bin\win32\InstallService.bat, наличие установленной JAVA машины предполагается само собой.
Проверить работоспособность можно через «Администрирование» -> «Службы», но только подождите секунд 10 после запуска и обновите список, на Win 2003 server у меня возникла проблема: служба вроде запускалась, но сразу же падала, долгое копание в логах и гуглах привело к простому решению – необходимо создать папку work в каталоге ActiveMQ\bin\win32.

Для настройки ActiveMQ необходимо открыть файл \conf\activemq.xml
Описываем наш брокер:
<broker xmlns="activemq.apache.org/schema/core" brokerName="localhost" dataDirectory="${activemq.base}/data" destroyApplicationContextOnStop="true" persistent="true" useShutdownHook="false">

Обратите внимание на параметр persistent, он отвечает за то, что все ваши сообщения будут хранится в БД и не пропадут после перезапуска службы. Надо это вам или нет решайте сами, я эту функцию подключил, причем перенастроил со встроенной kahaDB на более понятную и прозрачную MySQL. Делается это следующим образом:
Скачиваем коннектор для явы, из него берем mysql-connector-java-5.1.14-bin.jar и закидываем его в папку \lib. В самой MySQL создаем БД с названием activemq, для нее создадим пользователя activemq с таким же паролем. Опишем это все в конфиге:
<persistenceAdapter>        <br/>
   <jdbcPersistenceAdapter dataSource="#mysql-ds"/>            <br/>
</persistenceAdapter><br/>
 <br/>
<bean id="mysql-ds" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"><br/>
   <property name="driverClassName" value="com.mysql.jdbc.Driver"/><br/>
   <property name="url" value="jdbc:mysql://localhost/activemq?relaxAutoCommit=true"/><br/>
   <property name="username" value="activemq"/><br/>
   <property name="password" value="activemq"/><br/>
   <property name="poolPreparedStatements" value="true"/><br/>
</bean>

Блок должен располагаться за пределами тега . После перезапуска службы в БД должны будут создаться 3 таблицы, если так и произошло, значит все сделано правильно.

Идем дальше по конфигу, настроим возможные подключения:
<transportConnectors><br/>
 <transportConnector name="openwire" uri="tcp://0.0.0.0:61616"/><br/>
 <transportConnector name="openwire2" uri="stomp://0.0.0.0:61613"/><br/>
</transportConnectors>
Здесь я задал 2 различных подключения по разным протоколам, это связано с тем, что на PHP для подключения я использую библиотеку STOMP, а под Delphi удалось найти компонент стабильно работающий по TCP.

Далее займемся авторизацией, в блок добавим следующий кусок:
<plugins><br/>
 <jaasAuthenticationPlugin configuration="activemq-domain" /><br/>
 <authorizationPlugin><br/>
  <map><br/>
   <authorizationMap><br/>
    <authorizationEntries><br/>
     <authorizationEntry queue=">" read="admins" write="admins" admin="admins" /><br/>
     <authorizationEntry queue="icq.>" read="users" write="users" admin="admins" /><br/>
     <authorizationEntry topic="ActiveMQ.Advisory.>" read="guests,users" write="guests,users" admin="guests,users" /><br/>
    </authorizationEntries><br/>
   </authorizationMap><br/>
  </map><br/>
 </authorizationPlugin><br/>
</plugins>

Теперь создаем файл groups.properties в папке /conf со следующим содержимым:
admins=system,sslclient,client,broker1,broker2
users=icq
guests=guest

Там же создадим файл users.properties и впишем в него:
system=password
icq=secret
Еще понадобится файл login.config, его проще скачать целиком и кинуть в папку /conf. После всех настроек перезапускаем службу и заходим на адрес http://localhost:8161/admin/, если все сделали правильно, вас встретит панель управления, если так, то заходим в Queues и там создаем очередь с названием icq.

Скрипт ICQ-бота


За основу бота я взял библиотеку WebIcqPro, она довольно простая и стабильная. Также понадобится библиотека для отправки сообщений брокеру, я нашел вполне стабильное решение на STOMP-протоколе, однако при разрыве соединения его вышибало, поэтому мне пришлось его немного модифицировать, чтобы появилась возможность реконнекта. Приводить весь код бота я здесь не буду, кому это действительно интересно могут скачать архив.

Для проверки работоспособности запустим бота через командную строку:
«C:\Program Files\PHP\php» C:\icqbot\icq.php
Если с настройками все в порядке, он должен установить соединение с ActiveMQ и сервером ICQ, после чего начать прослушивать канал «* Waiting for messages...». Для отправки пробного сообщения можно воспользоваться скриптом send.php из архива:
<?php<br/>
require_once 'Stomp.php';<br/>
$c = new StompConnection("localhost");<br/>
$result = $c->connect("icq", "bot");<br/>
 <br/>
$mess = '<?xml version="1.0" encoding="windows-1251"?><br/>
            <reference><br/>
            <type>send</type><br/>
            <to>111111111</to><br/>
            <from>Test send:</from><br/>
            <mes>Проверка русского message</mes><br/>
            </reference>'
;<br/>
 <br/>
$mess =  iconv('cp1251','UTF-8',$mess);<br/>
$c->send("/queue/icq", $mess, array('persistent' => 'true'));<br/>
$c->disconnect();<br/>
?>
Мне довольно долго пришлось возится с кодировками, чтобы можно было отправлять сообщения с русским текстом, поэтому не удивляйтесь когда в скриптах увидите каскадные преобразования в различные кодировки, по другому это все работать не хотело. После вызова send.php на указанный UIN придет сообщение и в логах этот факт также отразится.

Запускаем бота как службу Windows


Для этого нам понадобится набор Windows NT Resource Kit, у кого нет качаем. Допустим все файлы бота у нас лежат в папке C:\icqbot. Открываем консоль и пишем
“C:\Program Files\Windows Resource Kits\Instsrv.exe” ICQBot “C:\Program Files\Windows Resource Kits\Srvany.exe”
Далее запускаем regedit и идем в раздел HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ICQBot внутри него создаем раздел Parameters и в нем параметр Application типа REG_SZ со значением «C:\Program Files\PHP\php.exe» C:\icqbot\icq.php
Далее идем в службы и запускаем оттуда нашего бота, теперь он полностью автономен.

Ловец ошибок для сайта


Наша конечная цель – отлавливать все ошибки, составлять подробный отчет и отправлять уведомление об этом на ICQ. Таким образом осталось описать только скрипт отлова этих ошибок, у меня он выглядит следующим образом и подключается во все скрипты где требуется контроль:
<?php<br/>
ini_set('display_errors',0);<br/>
error_reporting(2);<br/>
 <br/>
if($send_report){<br/>
  include_once("Stomp.php");<br/>
 <br/>
  function send_report($message, $to = '1212312', $from = 'SENDER'){<br/>
    global $send_report, $stomp_server, $stomp_url, $stomp_user, $stomp_psw;<br/>
    if(!$send_report)return false;<br/>
    $c = new StompConnection($stomp_server);<br/>
    $result = $c->connect($stomp_user, $stomp_psw);<br/>
    if(!is_array($to))$to = array($to);<br/>
    foreach($to as $i){<br/>
      $mess = '<?xml version="1.0" encoding="windows-1251"?><br/>
              <reference><br/>
              <type>send</type><br/>
              <to>'
.$i.'</to><br/>
              <from>'
.$from.'</from><br/>
              <mes>'
.$message.'</mes><br/>
              </reference>'
;<br/>
      $c->send($stomp_url, iconv('cp1251','UTF-8',$mess), array('persistent' => 'true'));<br/>
    }<br/>
    $c->disconnect();<br/>
  }<br/>
}<br/>
 <br/>
function user_log ($errno, $errmsg, $file, $line) {<br/>
  global $send_report;<br/>
  if($errno == 2){<br/>
    $filename = strftime('%d.%m.%Y %H-%M-%S_').$_REQUEST['PHPSESSID'].'.err';<br/>
    $fl = fopen('errors/'.$filename,'w');<br/>
    $_SESSION['ERROR_TEXT'] =  'WARNING: '.$errmsg.' in '.$file.' on line '.$line;<br/>
    $_SESSION['ERROR_TIME'] =  strftime('%d.%m.%Y %H-%M-%S');<br/>
    $_SESSION['ERROR_PHPSESSID'] =  $_REQUEST['PHPSESSID'];<br/>
    $_SESSION['ERROR_TYPE'] =  'PHP SCRIPT ERROR';<br/>
    fwrite($fl,serialize($_SESSION));<br/>
    fclose($fl);<br/>
    if($send_report)send_report($_SESSION['ERROR_TEXT']);<br/>
  }<br/>
}<br/>
 <br/>
set_error_handler('user_log');<br/>
?>
По понятным причинным все содержимое этих отчетов я криптую, что и всем советую делать.

Таким образом, получилась довольно стабильная, простая и универсальная схема оповещения, позволяющая отправлять сообщения на ICQ из любого приложения на любом языке, если для него описан один из протоколов взаимодействия с ActiveMQ.

Список используемых файлов
  1. ActiveMQ 5.4.2
  2. Конфиги для ActiveMQ
  3. Коннектор MySQL
  4. Библиотека WebICQPro для PHP
  5. Библиотека STOMP для PHP
  6. Готовый комплект скриптов бота и перехватчика ошибок
  7. Набор Windows NT Resource Kit
Теги:
Хабы:
Всего голосов 64: ↑57 и ↓7+50
Комментарии36

Публикации

Истории

Работа

PHP программист
148 вакансий

Ближайшие события