Сделали очень занятную вещь: 1С-пульт к софтфону. Смесь технологий, стандартов, смекалки и фана 🙂
Вышел целый квест. Рассказ будет длинный, но интересный. Дело было так…
При разработке проекта, нам в 1С понадобилась сторона софтфона. Подход с встраиванием SIP-клиента в 1С не устраивал, так как пользователи работают на сервере терминалов, а он очень плохо работает со звуком. Поэтому, звук должен обслуживаться софтфоном локального компьютера.
К тому же, для интеграции 1С и IP-АТС поставщик телефонии вместо стандартного AMI, дал Asterisk RESTfull Interface (ARI), который Digium усиленно «пилит» начиная с версии 12. RESTfull штука неплохая, развивается очень активно, но пока не дает той широты возможностей, которая есть в AMI.
Задачи
В общем, перед нами встали простые вопросы… Как из терминала поднять трубку локального софтфона, чтобы ответить на входящий звонок? Как сделать трансфер? Как сделать холд? То есть, типичные задачи, которые должны выполняться на стороне софтфона.
Средствами RESTfull-а это никак не решается без вклинивания в диалплан Asterisk, а это низззя. В итоге, задача была решена написанием системы удаленного управления софтфоном. Мы назвали ее — «пульт».
Решение
Сначала, рекомендую посмотреть результат — коротенькое видео, меньше минуты. Так вам будет намного понятнее о чем речь.
Схема
Идея состояла в том, чтобы сделать софтфон достаточно умным. Он должен уметь принимать удаленные команды и выполнять их. Ну и с безопасностью все должно быть хорошо.
Важное пояснение к схеме: 1С, АТС и рабочая станция находятся в 3-х разных местах.
Работает все это просто: 1С посредством ARI дает команду софтфону. Например, команду «Answer» — ответить на входящий звонок. Команды формируются по стандарту JSON-RPC, никаких велосипедов. Выглядит команда так:
1 |
{"jsonrpc": "2.0", "method": "answer", "params": {"time": 1445021164, "ttl": 5}} |
Каждая из команд имеет время жизни «ttl» (секунд) и время отправки «time» (в формате Unix). Некоторые команды имеют еще и дополнительный параметр с номером телефона «num».
Сторона софтфона приняв команду, проверяет валидность — а не прошел ли «срок годности» команды? И если все ОК, то выполняет ее.
Формат команд предельно простой и понятный. Оставалось только как-то передать их софтфону 🙂
Транспорт
По сути, для JSON-RPC совершенно не важно что именно будет транспортом- TCP, HTTP, WebSocket, SIP или что-то еще. Главное чтобы и клиент, и сервер его поддерживали.
В нашем конкретном случае, чтобы не заморачиваться, мы использовали уже готовый транспорт — SIP. А точнее, всего одну его часть: Simple (RFC 3428). Он предназначен для обмена сообщениями через SIP. И название хорошее, и под задачу подходит.
Отправка средствами RESTfull выглядит так:
1 |
http://<ip>:<port>/ari/endpoints/SIP/<exten>/sendMessage?from=SIP/<exten> |
Вместо <ip>, <port>, <exten> нужно вставить соответствующие значения, а само тело сообщения необходимо вставить в тело POST-запроса.
Безопасность
Чтобы софтфон выполнял команды только от доверенных отправителей, а не от кого попало, нужна какая-то система безопасности. Канал SIP-сообщений нельзя считать защищенным, значит будем шифровать.
Сначала, рассматривался HMAC — он именно для этого и придуман, но потом от него пришлось отказаться. Во-первых, HMAC требует использования сертификатов, а с ними возиться точно не хотелось. Во- вторых, PKCS#7 дает жуткий оверхед.
Вот как выглядит строка "Hello world!" в Base64, пропущенная через шифрование с использованием PKCS#7
1 2 3 4 5 6 7 8 9 |
MIIBoAYJKoZIhvcNAQcDoIIBkTCCAY0CAQAxggFLMIIBRwIBADAvMBsxGTAXBgNV BAMTEHd3dy5zaW1wbGl0LmluZm8CEDf1xijhK0yhSTDDr/v3tikwDQYJKoZIhvcN AQEBBQAEggEAD4j33nkNVLh/4ycMMe6VguFAoC3h9u4R69V4vU0Iv8A7+IoRVc4X tTrGSzvhuEv6wy4wWG2gRywt1foO6WleoupKLIqHADcETKYKydRqAv5slfRQ4Xkb IRBPz8dqrRLTD+82aMjeJ0HiFTBRZs7C5Y2LP1kSmqPg4OadcUbCQ6kjlXSrFjir 9nhER97hztKSh32bc9sqo9un9X1wkoaJXp6WaMDN4zjbHVFPIVKMh6Xk2O8us+BU RX9wMbtF6XiPK9VJi4vpnGKonK+ImmUn/z+/ppWBPe6pmczgzTR90zMeOWOfXeNz CbqkcozFXB9FxxmHD4xt8TRK4DZ8rWCOJTA5BgkqhkiG9w0BBwEwGgYIKoZIhvcN AwIwDgICAKAECK9Pgp997feMgBB6ZlSDRHQVW4MuI34bOo8q |
Жуть.
В итоге, была выбрана старая добрая классика — общий пароль шифрования, который известен обеим сторонам обмена. Теперь, «Hello world!» стал выглядеть намного лучше:
1 |
gwvoQi7+X0yxzuQM3HLvtQ== |
Оставалось только чем-то зашифровать 🙂 Вот сейчас пойдем в 1С, там же есть целый механизм «Криптография». Наивные…
Шифрование
Криптография в 1С не дает нам таких простых радостей жизни как «общий пароль шифрования». Сертификаты — это пожалуйста, хеширование — да без проблем, но шифрование по паролю — это 1С не умеет.
Ну ОК, придется научить. Быстренько написали внешнюю компоненту «SimpleCrypt» с 3-мя методами:
- УстановитьПароль
- Зашифровать
- Расшифровать
Софтфон
В роли софтфона — конечно же выступает наш Simple-Phone. На его стороне была добавлена криптография, обработка JSON и пара настроек. Например «Always on tray», чтобы он сидел тихо в трее и не бросался окнами при входящем звонке.
Итог
На выходе, мы получили тот профит, который хотели. По-другому и быть не могло — бренд Simplit обязывает 🙂
Правда, мы еще сами до конца не понимаем насколько этот «пульт» будет полезен и применим в других проектах. Жизнь покажет. Как минимум, проходить этот квест было весело 🙂