Разработка сценариев Asterisk AGI на Python, PHP и Node.js: протокол и отладка
- Ошибка
AGI Script script.php completed, returning -1и мгновенный разрыв соединения. - Asterisk зависает при выполнении AGI команды (Deadlock / Broken Pipe).
- Скрипт завершается с ошибкой
Permission deniedили не имеет прав на исполнение. - Переменные канала Asterisk не передаются в стороннюю CRM-систему.
1. Архитектура протокола Asterisk Gateway Interface (AGI)
Asterisk запускает AGI-скрипт как дочерний процесс, передавая системные переменные вызова в STDIN. Скрипт отправляет команды ядру Asterisk через STDOUT и получает результат выполнения каждой команды через STDIN.
2. Разработка AGI на Python 3 (без сторонних библиотек)
Создайте исполняемый скрипт /var/lib/asterisk/agi-bin/crm_lookup.py:
#!/usr/bin/env python3
import sys
def agi_read():
env = {}
while True:
line = sys.stdin.readline().strip()
if not line:
break
key, _, val = line.partition(':')
env[key.strip()] = val.strip()
return env
def agi_command(cmd):
sys.stdout.write(f"{cmd}\n")
sys.stdout.flush()
return sys.stdin.readline().strip()
def main():
env = agi_read()
caller_id = env.get('agi_callerid', 'unknown')
# Имитация запроса в CRM
vip_client = True if caller_id == "79991234567" else False
if vip_client:
agi_command('SET VARIABLE CRM_ROUTE "VIP"')
agi_command('VERBOSE "Client is VIP! Routing to Senior Queue" 1')
else:
agi_command('SET VARIABLE CRM_ROUTE "DEFAULT"')
if __name__ == '__main__':
main()chmod +x /var/lib/asterisk/agi-bin/crm_lookup.py
chown asterisk:asterisk /var/lib/asterisk/agi-bin/crm_lookup.py3. Вызов AGI из диалплана extensions.conf
[from-trunk]
exten => _X.,1,NoOp(Inbound call with AGI CRM Check)
same => n,Answer()
same => n,AGI(crm_lookup.py)
same => n,GotoIf($["${CRM_ROUTE}" = "VIP"]?vip_queue:standard_queue)
same => n(vip_queue),Queue(vip_support_queue)
same => n,Hangup()
same => n(standard_queue),Queue(general_support_queue)
same => n,Hangup()4. Включение отладки в консоли Asterisk CLI
asterisk -rx "agi set debug on" Частые вопросы (FAQ)
Почему обязателен sys.stdout.flush() / fflush(STDOUT) в AGI?
Стандартный вывод языков программирования буферизуется. Без принудительного сброса буфера (flush) Asterisk не получит отправленную команду вовремя, и процесс зависнет в ожидании ответа.
Что такое FastAGI и когда его следует использовать?
Обычный AGI форкает новый процесс ОС (fork/exec) на каждый звонок, что создает высокую нагрузку при 50+ вызовах/сек. FastAGI (agi://host:4573/script) работает как постоянно запущенный сетевой демон через TCP-сокеты без оверхеда на создание процессов.
Как передать аргументы в AGI скрипт из диалплана?
Передавайте аргументы через запятую: same => n,AGI(script.py,arg1,arg2). В скрипте они будут доступны в стандартном массиве sys.argv (Python) или $argv (PHP).
Что делать, если AGI скрипт прерывается при преждевременном сбросе трубки звонящим?
При сбросе вызова Asterisk отправляет сигнал SIGHUP скрипту. В скрипте необходимо установить перехватчик сигналов (Signal Handler), чтобы корректно закрыть подключения к БД и освободить дескрипторы.