В предыдущем посте мы писали о том, каким образом интегрировали WhatsApp в Битрикс24. Как и обещали, в данном посте речь пойдет о технической стороне вопроса.
Изучая возможность интеграции WhatsApp в Битрикс24 посредством агрегаторов мессенджеров, мы обнаружили, что идеальным способом такой интеграции являлся бы механизм открытых линий. Открытые линии – действительно мощный и удобный механизм. Сообщения в них приходят через коннекторы (каналы коммуникации), которые и реализуют взаимодействие Битрикса с внешними системами.
Рис.1 Коннекторы открытых линий в Битрикс24
К сожалению, документации по данной теме недостаточно, и нам не удалось найти возможность создания и работы с собственными коннекторами открытых линий в текущем REST-API Битрикс. Наиболее близкой альтернативой является использование чат-ботов. REST-API Битрикс24 прекрасно с ними работает, поэтому мы решили реализовать общение с внешним агрегатором мессенджеров через закрытые чаты и чат бота.
Создаем новое приложение Битрикс24. В требуемых scopes выбираем messageservice, crm, imbot, im, imopenlines, user, disk. Точка входа в приложении реализует маршрутизацию запросов к нему. Первым делом создаем интерфейс, отображающий настройки приложения, и обеспечивающий их сохранение.
Рис2. Часть интерфейса формы настроек приложения.
Тут необходимо учитывать, что если Вы пишете приложение под Маркетплейс Битрикс24 – необходимо подумать об использовании приложения различными доменами, и хранении настроек индивидуально для каждого домена. В нашем случае было организовано хранение настроек в серилизованных записях БД. При каждом обращении к приложению, определялся домен, опрашивающий приложение и для него загружались собственные настройки.
Следующим шагом стала регистрация чат-бота в Битрикс. На самом деле, во многих случаях это будет первым шагом, но в нашем случае чат не может работать функционально, пока не сделаны настройки приложения (не получен токен от агрегатора мессенджеров). Поэтому мы устанавливаем чат-бота только после внесения верных настроек.
BX24.callMethod( 'imbot.register', { 'CODE':bot['code'], 'TYPE':bot['type'], 'EVENT_MESSAGE_ADD':BX24APP.PATH, 'EVENT_WELCOME_MESSAGE':BX24APP.PATH, 'EVENT_BOT_DELETE':BX24APP.PATH, 'PROPERTIES' :{ 'NAME':bot['name'], 'LAST_NAME' :'', 'COLOR' :'AQUA', 'PERSONAL_PHOTO':bot['avatar'], }, }, function(result) { } );
Интересным моментом здесь является то, что аватар бота должен быть передан в виде картинке, закодированной в формате base64. Делается это в PHP с помощью вот такого не хитрого кода:
base64_encode(file_get_contents($url));
На выходе получится длинная строка с закодированными данными. Ее и указываем в PERSONAL_PHOTO. События бота – маршрутизируем на точку входа нашего приложения.
После этого, в контактах мессенджера Битрикс24 появится новый чат бот. Чат бот будет привязан к Вашему приложению. Когда кто-либо пишет чат-боту сообщение, информация об этом будет передаваться Вашему приложению по событию ONIMBOTMESSAGEADD. Здесь наша задача – посмотреть из какого чата это сообщение пришло, и передать его внешней системе. Для получения сообщений из внешней системы – указываем в ней в качестве вебхука — точку входа нашего приложения, с обязательным указанием домена, чтобы понимать какому именно порталу пришло сообщение.
Таким образом у нас теперь приложение перехватывает и входящие и исходящие сообщения. Осталось отобразить их пользователям. Для этого мы создали дополнительную таблицу в БД где храним информацию о диалогах чат-бота. При поступлении нового входящего сообщения мы проверяем его по этой таблице, и если это новый диалог – создаем в Битриксе закрытый чат с помощью команды ‘im.chat.add’. Чтобы «пометить» чат, и иметь возможность быстро определять что это чат для внешней системы – используйте поля ENTITY_TYPE и ENTITY_ID. Например в ENTITY_TYPE пишите «EXT_SYSTEM» а в ENTITY_ID «ид диалога во внешней системе». Тогда легко можно обойтись без лишних запросов к БД.
В чат приглашаем специального пользователя, участвующего во всех диалогах (нужно для того, чтобы диалоги не оказались «брошенными», если из них выйдет пользователь), чат бота, и пользователя который будет общаться в этом диалоге.
Далее общение происходит в рамках чата, чат-бот перехватывает сообщения пользователя и передает их в приложение, которое передает их в агрегатор. Агрегатор отправляет сообщение в WhatsApp или в другой мессенджер клиенту. При поступлении ответа – передает его назад приложению, а приложение доводит его до пользователя через чат-бота. Каждому клиенту соответсвует свой диалог.
Важным вопросом в любом приложении для Битрикс24 является вопрос хранения авторизации. Мы в нашем случае решили его так: При установке приложения сохраняем авторизацию пользователя, установившего приложение в базе данных. Обычно это кто-то обладающий высоким уровнем доступа. В авторизации хранится текущий токен и токен для обновления авторизации. Текущий токен живет очень не долго. Если запрос к REST-API Битрикс24 возвращает ошибку ‘expired_token’ или ‘invalid_token’ — обновляем токен с помощью токена для обновления авторизации:
$auth=array(); $url="https://"; $url.=$this->DOMAIN."/oauth/token/?grant_type=refresh_token"; $url.="&client_id=".$this->CLIENT_ID; $url.="&client_secret=".$this->CLIENT_SECRET; if($this->CONFIG['AUTH']['REFRESH_TOKEN']) $url.="&refresh_token=". $this->CONFIG['AUTH']['REFRESH_TOKEN']; if($this->CONFIG['AUTH']['refresh_token']) $url.="&refresh_token=". $this->CONFIG['AUTH']['refresh_token'];
Как видите, данный код принудительно вызывает страницу OAuth авторизации и передает ей код для обновления авторизации. Страница возвращает новые параметры авторизации. Их сохраняем и повторяем запрос с новыми параметрами авторизации.
Остается один нюанс – код для обновления авторизации тоже имеет срок жизни. Он составляет что-то около месяца. То есть, если Ваше приложение за месяц не сделает ни одного запроса в RET-API авторизация будет безвозвратно потеряна. Для решения этой проблемы – мы используем принудительное периодическое обновление авторизации раз в 10 дней (по cron).
Следующий интересный момент. Когда вы работаете с curl через https – необходимо задумываться о способе шифрования. Дело в том, что разные сервера (например сервер агрегатора мессенджеров) могут использовать разный набор доступных шифрований. При этом этот набор может не совпадать с вашим набором. В таком случае curl будет выдавать ошибку и работать не будет. Провести анализ доступных шифрований на удаленном сервере можно с помощью вот такого сервиса:
https://www.ssllabs.com/ssltest/analyze.html?d=имя_сервера
Соответсвенно, в вашем curl вы должны использовать шифрование из списка доступных на удаленном сервере. В PHP задавать способ шифрования можно с помощью:
curl_setopt_array(CURLOPT_SSL_CIPHER_LIST=>’способ шифрования’);