Asterisk: Общие сведения о настройке интеграции
Введение
Asterisk очень доступный инструмент для создания компьютерной телефонии внутри компании. Вместе с этим у Asterisk'a нет одного способа поставки и способа использования, поэтому настройка интеграции конкретной установки Asterisk должна производиться ответственным сотрудником компании.
Порядок действий при подключении
Получить от Qolio доступ к аккаунту админа в вашем кабинете.
Для начала со стороны телефонии нужно определить следующие вещи:
где будут храниться записи звонков и как к этим записям можно получить доступ по http(s). В системе есть возможность настроить доступ через S3 совместимое облачное хранилище и настроить доступ к хранилищу с basic http авторизацией.
по какому атрибуту будет привязываться звонок к оператору внутри Qolio. Для этой привязки используется поле operator_id в API запросе https://wiki.qolio.io/qolio-or-baza-znanii/integracii/podklyuchenie-po-api/sozdanie-i-upravlenie-polzovatelskimi-polyami-pri-integracii-po-api
Добавить пользователей, по которым будут приходить звонки в Qolio (если этого не сделать, звонки, переданные по API сохраняться не будут). Пользователь добавляет админ телефонии либо другой сотрудник компании.
Настроив пользователей вручную (https://wiki.qolio.io/qolio-or-baza-znanii/integracii/podklyuchenie-po-api/dobavlenie-i-nastroika-polzovatelei-cherez-api) или загрузив их через CSV файл (подробнее https://wiki.qolio.io/qolio-or-baza-znanii/integracii/podklyuchenie-po-api/dobavlenie-i-nastroika-polzovatelei-cherez-api) в настройках API интеграции
Создавать и настраивать пользователей через API (https://wiki.qolio.io/qolio-or-baza-znanii/integracii/podklyuchenie-po-api/sozdanie-csv-faila-dlya-dobavleniya-polzovatelei-pri-integracii-po-api, кроме этого в этой статье описано, как с помощью python скрипта настраивать пользователей через CSV файл)
Для импорта звонков пользователи должны быть загружены в систему DealApp, а так же быть активными и назначенными на отдел.
Далее следует настроить структуру компании и распределить пользователей по отделам. В дальнейшем звонки будут добавляться к тем отделам, в которых состоят пользователи.
Разработать расширение для телефонии, которая будет передавать через http запросы на DealApp API информацию о совершенных звонках на телефонии. Информацию про API запросы, которые нужно делать для импорта звонков телефонии. Так же можно попробовать делать запросы со страницы настройки интеграции. Далее в этой статье описан пример создания скрипта для синхронизации данных.
Для последующей эксплуатации необходимо продумать, как будут обновляться пользователи, какие роли будут в системе, как они будут взаимодействовать и так далее. На этом моменте технические задачи заканчиваются.
Пример создания скрипта для синхронизации данных Asterisk по API
Для успешной работы Qolio должен принимать данные о телефонных звонках через API по http(s). Для упрощения работы используется "Custom HTTP интеграция", подробности о которой можно почитать тут: https://wiki.qolio.io/qolio-or-baza-znanii/integracii/podklyuchenie-po-api/integraciya-po-api-dlya-ip-telefonii-i-chatov
Qolio необходимо принимать следующие данные о звонках:
ID оператора в системе (operator_id) - это идентификатор оператора в системе, с которым связан звонок.
Длительность (duration) и направление звонка (direction)
Номер звонящего клиента (client_phone_number)
URL Ссылку на запись разговора (media_url), по которой можно получить доступ к записи разговора. Эта ссылка будет передаваться в плеер сервиса Qolio.
Также есть возможность расширить набор этих данных через поле metacontent (custom_fields). Подробности можете прочитать в статье про Custom HTTP интеграцию.
В данной статье приводится пример работы, которую можно выполнить, чтобы подключить Asterisk к DealApp
Порядок работы
Самым популярным способом интеграции Asterisk с Qolio является следующий сценарий:
создается systemd сервис, который запускается периодически каждые пол часа как cron job
этот сервис запускает скрипт, который подключается к базе данных и вытаскивает данные о звонках за последнее время
далее скрипт преобразовывает данные из базы данных в необходимый JSON формат и отправляет их в Qolio
Далее будет приведен примеры сервисов, которые были созданы на основе Red Hat Linux (Linux ats 3.10.0) с Asterisk 13.32.0, Python 2.7.5 и Mysql 5.5 (Ver 15.1 Distrib 5.5.65-MariaDB). Python был выбран как скриптовой язык из-за того, что он с большой вероятностью будет находиться в дистрибутиве с Asterisk.
Чаще всего записи телефонных звонков доступны через сетевое хранилище и телефонный разговор в нем можно найти по названию файла, которое храниться в базе CDR.
Скрипт для загрузки телефонных звонков в DealApp
Первым делом подготовим папку и необходимые пакеты для работы скрипта:
// sudo pip install mysql-connector-python
sudo pip install requests
sudo mkdir -p /etc/dealapp-sync/bin
sudo touch /etc/dealapp-sync/bin/dealapp-sync
sudo chmod +x /etc/dealapp-sync/bin/dealapp-sync
В папке /etc/dealapp-sync
будет храниться все данные о синхронизации, в том числе и файлик со временем последней синхронизации.
Нам необходимо так же установить pip пакет mysql-connector-python
для работы с mysql базы данных и requests
для того, чтобы делать http запросы в DealApp сервис.
Далее рассмотрим сам скрипт для синхронизации. Данный скрипт является примером и в конкретном случае его скорее всего придется изменять.
Содержание скрипта /etc/dealapp-sync/bin/dealapp-sync
// #!/usr/bin/env python
import argparse, sys, time, re, logging, datetime, mysql.connector, json, os.path, glob, requests
from logging import critical, error, info, warning, debug
from datetime import datetime, timedelta
from os import path
INTEGRATION_URL="https://api.prod1.dealapp.io/api/v1/integrations/8a48a9d6-1930-47ca-a331-e60e1945d249/phone_calls"
AUTHORIZATION_TOKEN="253aac176651c106c7fcf57acf324559b8e5aa0a27ba1a2db88d325256a3df15fbff1eb353a036faf065d167a7c237d9eacfe217212306f554d541e8321acde1"
RECORDS_STORAGE_BASE_URL="https://ats-srv.local"
DEFAULT_CONFIG_PATH="/etc/dealapp-sync/last_export_timestamp"
INTERNAL_NUMBER_MATCHER=re.compile('^\d{3}$')
CDR_DATABASE_NAME="asteriskcdrdb"
class PhoneCall:
def __init__(self, clid, calldate, src, dst, billsec, recordingfile):
self.clid = clid
self.calldate = calldate
self.src = src
self.dst = dst
self.billsec = billsec
self.recordingfile = recordingfile
def is_valid(self):
return (bool(INTERNAL_NUMBER_MATCHER.match(self.dst)) or bool(INTERNAL_NUMBER_MATCHER.match(self.src))) and self.billsec > 0
def is_incoming(self):
return bool(INTERNAL_NUMBER_MATCHER.match(self.dst))
def direction(self):
return "incoming" if self.is_incoming() else "outcoming"
def operator_id(self):
return self.dst if self.is_incoming() else self.src
def client_phone_number(self):
return self.src if self.is_incoming() else self.dst
def duration(self):
return float(self.billsec)
def started_at(self):
return self.calldate.isoformat()
def media_url(self):
return "{}/{}/{}/{}/{}".format(RECORDS_STORAGE_BASE_URL, self.calldate.year, self.calldate.strftime("%m"), self.calldate.strftime("%d"), self.recordingfile)
def get_last_export_timestamp():
try:
with open(DEFAULT_CONFIG_PATH, 'r') as config_file:
return datetime.strptime(config_file.read(), "%Y-%m-%d %H:%M")
except:
print "Can not read config file with synchronization timestamp, exporting phone calls created 0.5h ago"
return datetime.now() - timedelta(hours = 26)
def save_last_export_timestamp(syncronization_start_time):
try:
with open(DEFAULT_CONFIG_PATH, 'w') as config_file:
config_file.write(syncronization_start_time.strftime("%Y-%m-%d %H:%M"))
except:
print "Can not save last export time into {}".format(DEFAULT_CONFIG_PATH)
def read_phone_calls_from_database(fetch_from_time):
cnx = mysql.connector.connect(database=CDR_DATABASE_NAME)
cursor = cnx.cursor()
query = ("SELECT clid, calldate, src, dst, billsec, recordingfile FROM cdr "
"WHERE calldate > %s "
"AND billsec > 0 "
"AND COALESCE (recordingfile, '') <> ''")
cursor.execute(query, (fetch_from_time,))
phone_calls = []
for (clid, calldate, src, dst, billsec, recordingfile) in cursor:
phone_calls.append(PhoneCall(clid, calldate, src, dst, billsec, recordingfile))
cursor.close()
cnx.close()
return phone_calls
def send_phone_calls_to_dealapp(phone_calls):
phone_calls_are_sent_successfully = True
headers = {'Content-Type': 'application/json', 'Authorization': AUTHORIZATION_TOKEN}
for phone_call in phone_calls:
if phone_call.is_valid():
serialized_phone_call = {
"operator_id": phone_call.operator_id(),
"direction": phone_call.direction(),
"duration": phone_call.duration(),
"started_at": phone_call.started_at(),
"client_phone_number": phone_call.client_phone_number(),
"media_url": phone_call.media_url()
}
try:
result = requests.post(url=INTEGRATION_URL, data=json.dumps(serialized_phone_call), headers=headers)
if(result.status_code != 200):
print("Phone call with clid {} can not be sent to DealApp".format(phone_call.clid))
print(result.text, "Reason")
except:
phone_calls_are_sent_successfully = False
print("Can't connect to DealApp service")
return phone_calls_are_sent_successfully
def main():
fetch_from_time = get_last_export_timestamp()
last_export_time = datetime.now()
phone_calls = read_phone_calls_from_database(fetch_from_time)
successeed = send_phone_calls_to_dealapp(phone_calls)
if(successeed):
save_last_export_timestamp(last_export_time)
if __name__ == '__main__':
main()
В этом скрипте есть следующие константы:
Константы
INTEGRATION_URL
Значение AUTHORIZATION_TOKEN берется из модального диалога интеграции (Токен интеграции)
AUTHORIZATION_TOKEN
Значение INTEGRATION_URL берется из модального диалога интеграции (URL интегрируемого приложения)
RECORDS_STORAGE_BASE_URL
Адрес сетевого хранилища записей. В этом виде может выступать адрес S3 bucket или ссылка nginx сервер, который раздает звонки
DEFAULT_CONFIG_PATH
Адрес на файл со временем последней синхронизации
INTERNAL_NUMBER_MATCHER
С помощью этого регулярного выражения проверяется являться данный телефонный разговор внутренним или нет
CDR_DATABASE_NAME
Название базы данных CDR, которое необходимо для подключения к этой базе. В общем случае это значение можно найти в файле /etc/asterisk/cdr_adaptive_odbc.conf
PhoneCall класс используется для того, чтобы принимать данные из базы данных и сериализовать их в значения, которые ожидает получить Qolio.
is_valid
Позволяет определить стоит ли экспортировать этот телефонный звонок (например, если звонок не состоялся или состоялся между внутренними номерами)
is_incoming
Определяет, является ли телефонный звонок входящим
direction
Возвращает значения "incoming" или "outcoming" в зависимости от направления разговора
duration
Длительность разговора в секундах. Обратите внимание, что здесь мы берем значение из поля billsec в базе данных, так как оно отображает реальную длительность разговора между оператором и клиентом без времени ожидания.
operator_id
Идентификатор оператора в системе. В нашем случае это значение его внутреннего номера, это значение должно быть настроено в системе DealApp.
client_phone_number
Телефонный номер клиента, с которым происходил разговор
started_at
Время разговора в ISO8601 формате
media_url
Ссылка на запись разговора, которая будет использоваться в плеере внутри DealApp. В нашем случае ссылка формируется из адреса хранилища данных, данных о дате звонка и названия записи
Описаний функций скрипта
get_last_export_timestamp
Получает время последней синхронизации с DealApp. Далее это время используется, чтобы доставать информацию о звонках из базы CDR
save_last_export_timestamp
Записывает время последней успешной синхронизации с DealApp в файл
read_phone_calls_from_database
Делает запрос в базу данных на получение записей после определенного времени и оборачивает результат в объекты типа PhoneCall
send_phone_calls_to_dealapp
Принимает список телефонных звонков, преобразует их в JSON и отправляет на сервис DealApp
Создание systemd сервиса для синхронизации
Сервис для вызова скрипта будет выглядеть следующим образом:
// # /etc/systemd/system/dealapp-sync.service
[Unit]
Description=Export Phone Calls from Asterisk CDR to DealApp
Wants=shopify-recent.timer
[Service]
WorkingDirectory=/etc/dealapp-sync
ExecStart=/etc/dealapp-sync/bin/dealapp-sync
User=root
Group=root
[Install]
WantedBy=multi-user.target
Сервис для периодического вызова скрипта для синхронизации будет выглядеть так:
// #/etc/systemd/system/dealapp-sync.timer
[Unit]
Description=Run export of Phone Calls from Asterisk CDR to DealApp every 30 minutes
Requires=dealapp-sync.service
[Timer]
Unit=dealapp-sync.service
OnUnitInactiveSec=30m
[Install]
WantedBy=timers.target
Затем создадим скрипты для systemd сервиса и таймера
// sudo systemctl daemon-reload
sudo systemctl enable dealapp-sync.timer
sudo systemctl start dealapp-sync.timer
Last updated
Was this helpful?