Asterisk™: будущее телефонии Второе издание
Шрифт:
Теперь мы уже рассмотрели два разных языка программирования с целью продемонстрировать, что общего в написании сценария AGI на PHP и Perl и чем они отличаются. При создании сценария AGI на PHP помните, что необходимо:
• Запускать PHP с ключом -q; это отключает HTML в сообщениях об ошибках.
• Отключить ограничение по времени или задать для него приемлемое значение (более новые версии PHP автоматически отключают ограничение по времени при запуске PHP из командной строки).
• Отключить буферизацию вывода с помощью команды ob_implicit_ flush(false).
• Открыть
• Прочитать переменные из STDIN, используя функцию fgets.
• Использовать функцию fwrite для записи данных в STDOUT и STDERR.
• Всегда вызывать функцию fflush после записи в STDOUT или STDERR.
Библиотека AGI для PHP
Для более продвинутого программирования AGI на PHP, вероятно, пригодится проект PHPAGI, который можно найти по адресу http:// phpagi.sourceforge.net. Изначально он был написан Мэттью Ашамом (Matthew Asham) и дорабатывался несколькими членами сообщества разработчиков Asterisk.
Написание сценариев AGI на Python
Сценарий AGI, который мы напишем на Python, называется «Игра в вычитание». Источником идей для его написания стала программа на Perl, созданная Эдом Гаем (Ed Guy) и представленная им на конференции AstriCon в 2004 году. Эд рассказывал, в какой восторг он пришел от мощи и простоты Asterisk, когда обнаружил, что может написать короткий сценарий на Perl, чтобы помочь своей дочери с математикой. Поскольку мы уже написали Perl-программу, использующую AGI и Эд создал свою математическую программу на Perl, мы решили заняться реализацией этой задачи на Python! Итак, разберем наш сценарий на Python: #!/usr/bin/python
Данная строка указывает системе выполнять этот сценарий в интерпретаторе Python. Для небольших сценариев в эту строку можно добавить опцию -u, что обеспечит выполнение Python в режиме без буферизации. Однако это не рекомендуется для больших или часто используемых сценариев AGI, поскольку может сказаться на производительности системы. import sys import re import time import random
Здесь импортируются несколько библиотек, которые будут использоваться в сценарии AGI.
# Читаем и игнорируем среду AGI (читать до пустой строки)
env = {} tests = 0;
while 1:
line = sys.stdin.readline.strip
if line == '': break
key,data = line.split(':') if key[:4] <> 'agi_':
# игнорируем ввод, который начинается не с agi_ sys.stderr.write("Did not work!\n"); sys.stderr.flush continue key = key.strip data = data.strip if key <> '':
env[key] = data
sys.stderr.write("AGI Environment Dump:\n");
sys.stderr.flush
for key in env.keys:
sys.stderr.write(" -- %s = %s\n" % (key, env[key])) sys.stderr.flush
Данный фрагмент кода читает переменные, передаваемые в сценарий из Asterisk, и сохраняет их в словарь env. Затем эти значения записываются в STDERR для целей отладки.
def checkresult (params): params = params.rstrip if re.search('"200',params): result = re.search('result=(\d+)',params) if (not result):
sys.stderr.write("FAIL ('%s')\n" % params) sys.stderr.flush return -1 else:
result = result.group(1)
#debug("Result:%s Params:%s" % (result, params)) sys.stderr.write("PASS (%s)\n" % result) sys.stderr.flush return result
else:
sys.stderr.write("FAIL (unexpected result '%s')\n" % params)
sys.stderr.flush
return -2
Функция checkresult
по своему назначению практически идентична подпрограмме checkresult в примере AGI-сценария на Perl, который рассматривался ранее в этой главе. Она читает результат выполнения команды Asterisk, проводит синтаксический разбор результата и сообщает, была команда выполнена успешно или нет. def sayit (params):sys.stderr.write("STREAM FILE %s \"\"\n" % str(params)) sys.stderr.flush
sys.stdout.write("STREAM FILE %s \"\"\n" % str(params)) sys.stdout.flush
result = sys.stdin.readline.strip checkresult(result)
Функция sayit - это просто оболочка для команды STREAM FILE.
def saynumber (params):
sys.stderr.write("SAY NUMBER %s \"\"\n" % params) sys.stderr.flush
sys.stdout.write("SAY NUMBER %s \"\"\n" % params) sys.stdout.flush
result = sys.stdin.readline.strip checkresult(result)
Функция saynumber - это просто оболочка для команды SAY NUMBER.
def getnumber (prompt, timelimit, digcount):
sys.stderr.write("GET DATA %s %d %d\n" % (prompt, timelimit, digcount)) sys.stderr.flush
sys.stdout.write("GET DATA %s %d %d\n" % (prompt, timelimit, digcount)) sys.stdout.flush
result = sys.stdin.readline.strip result = checkresult(result) sys.stderr.write("digits are %s\n" % result) sys.stderr.flush if result:
return result else:
result = -1
Функция getnumber вызывает команду GET DATA для получения DTMF-вво- да от вызывающего абонента. Она используется в нашей программе для получения ответов абонента на поставленные задачи по вычитанию.
limit=20
digitcount=2
score=0
count=0
ttanswer=5000
Здесь выполняется задание исходных значений нескольким переменным, которые будут использоваться в программе.
starttime = time.time t = time.time - starttime
В этих строках переменной starttime задается текущее время, а переменной t - начальное значение 0. Переменная t будет использоваться для отсчета времени с момента запуска сценария AGI в секундах.
sayit("subtraction-game-welcome")
Далее, мы рады приветствовать абонента в нашей игре на вычитание.
while ( t < 180 ):
big = random.randint(0,limit+1) big += 10
subt= random.randint(0,big) ans = big - subt count += 1
#постановка задачи:
sayit("subtraction-game-next");
saynumber(big);
sayit("minus");
saynumber(subt);
res = getnumber("equals",ttanswer,digitcount);
if (int(res) == ans) : score+=1
sayit("subtraction-game-good"); else :
sayit("subtraction-game-wrong"); saynumber(ans);