extensions.ael
Сообщений: 6521
|
Re: extensions.ael
М-м, я предлагаю ещё более усушить: конфиги в extensions.ael компилировать в бинарный код, для экономии места на экране.
|
Откуда: Уфа
Сообщений: 5856
|
Re: extensions.ael
я вообще 90% задач решаю sql запросами в базу
а диалплан в обычной нотации просто привычней.
возможно со временем переведу на ael...
другое дело, что новая нотация редко юзаецо.
|
Сообщений: 866
|
Re: extensions.ael
У меня все на AEL и я этому рад. Хоть читать и понимать что написано могу - диалплан становится похож на все нормальные языки.
AEL это конечно все равно не язык. Это редкий кастрат и надстройка над обычным диалпланом, это правда. Мне лично очень не хватает нормальных функций любого языка - человеческой работы со строками, ассоциативных массивов (hashtable) но так ведь и в extensions.conf их тоже нет. AEL не делает ничего хуже чем extensions.conf. Наоборот, он делает "программу" диалплана хоть чуть более похожей на программу в привычном смысле этого слова. И как важное следствие - человеку знакомому с "нормальными" языками требуется гораздо меньше подготовки для того чтобы сопровождать потом AEL. Ну и не требуется выворачивать мозг шестислойными GoTo...
Как язык (точнее недоязык), AEL, повторюсь, очень ограничен (так же как и extensions.conf). И если требуется запрограммировать что-то реально сложное то очень быстро захочется застрелиться. Так что мы сейчас будем пробовать перетащить диалпллан на Ruby. Есть такая штука - Adhearsion, по сути представляет из себя FastAGI + AMI только все очень цивильно сделано - остается ощущение что ты пишешь именно диалплан.
Так что для меня bottom line простой - хочешь нормальный язык - используй его (какой хочешь) через AGI+AMI. Пока реалььная нужда не ткнула - пиши средствами астериска - ael/dialplan. Но из этих двух AEL гораздо приятней.
|
Откуда: Уфа
Сообщений: 5856
|
Re: extensions.ael
Интересно, что такое ты напрограммил, если у тебя шестислойные goto.
Я почти полностью реализовал функционал основных модулей freepbx и на каждый контекст у меня максимум 2 goto. Традиционный диалплан выглядит просто, компактно и лаконично, вся обработка строго линейна. и ни одного AGI скрипта, ибо agi при высоких загрузках тратит кучу ресурсов на вызовы интерпретатора.
Недавно спорил с партнером по поводу технологии и языка, на котором писать морду. У него идея фикс - дотнет и моно и визуалстудио, типа там есть классы, визуальный редактор и все такое. Я посидел, подумал, накидал примеры на ПХП, разработал подход, при котором без всяких классов можно очень быстро и очень легко всю морду написать.
в общем - язык это или недоязык - все равно. Важен правильный подход.
|
Сообщений: 866
|
Re: extensions.ael
Ну про подход согласен 100%. Можно говнокод даже на самом строгом языке писать, а можно и на перле аккуратно.
Касательно 6-слойных goto, такого уже не осталось конечно, но суть та же все равно. Чтобы предметно было - я внизу привожу свое макро которое для MeetMe конференций используется.
Пререквизиты:
1. PIN конференции состоит из двух частей - номер конфереции (первые две цифры) и пароль. Сделано чтобы было наподобие всяких сервисов типа freeconference.com к которым народ привык. Там нет номера конференции И пина, есть только пин который однозначно определяет конференцию.
2. проверку PIN'а делаем руками - т.е. в meetme отдается уже аутентифицированный юзер. Так что из реалтайма из таблички meetme приходится прочитать запись ручками и найти в ней все нужные поля, сверить пароль и все такое.
3. лоченье конференций (lock) у нас тоже руками делается - не через meetme lock XX а засовыванием в ASTDB флага и проверкой его перед джоином. Причина - нам нужно в веб интерфейсе показывать статус лока - есть или нет, а узнать статус лока поставленного через meetme lock - командами CLI/AMI нельзя (AFAIK).
4. Макро можно вызвать сразу с ПИНом или без оного - тогда юзеру предлагается интерактивно его ввести.
macro conference(code) {
retries = 3;
while (${retries}) {
if (${LEN(${code})} == 0) {
Read(code,conf-getpin);
}
if ("${code}" == "") {
// User entered nothing. Stop, no retries
retries = 0;
break;
}
confno = ${code:0:2};
pin = ${code:2};
code = "";
Set(row="${REALTIME(meetme,confno,${confno},*,~)}");
if ("${row}" != "") {
for (i=1; 1; i = ${i} + 1) {
Set(pair=${CUT(row,"*",${i})});
if ("${pair}" = "")
break;
Set(name=${CUT(pair,"~",1)});
Set(value=${CUT(pair,"~",2)});
if ("${name}" == "userpin")
confpin = "${value}";
else if ("${name}" == "options")
confopts = "${value}";
}
if ("${pin}" == "${confpin}") {
// Ok both the confno and confpin are valid
break;
}
}
retries = ${retries} - 1;
if (${retries} > 0)
Playback(conf-invalidpin);
}
if (${retries} < 1) {
return;
}
locked = "${DB(Conference/${confno}/Locked)}";
if ("${locked}" == "1") {
Playback(conf-locked);
return;
}
Noop(Conference: ${confno});
// We need to let users activate recording (our "monitor" dynamic feature).
// Since features can only be activated on bridged channels, we need to call
// MeetMe using Local channel instead of executing it directly.
_DYNAMIC_FEATURES = "monitor-caller#monitor-callee";
// Provide identification data to monitor
_DST_TYPE = "conference";
_DST_ADDR = "${confno}";
// Pass data necessary to join conference
_CONF_NO = "${confno}";
_CONF_OPTS = "${confopts}";
Dial(Local/join@meetme/j);
};
context meetme {
join => {
if (${LEN(${CONF_INVITED_NUM})} > 0) {
CALLERID(num) = "${CONF_INVITED_NUM}";
CALLERID(name) = "${CONF_INVITED_NAME}";
}
UserEvent(Conference!Connecting!${CHANNEL}!${CDR(uniqueid)}!${CONF_NO}!${CALLERID(num)}!${CALLERID(name)});
MeetMe(${CONF_NO},FT${CONF_OPTS});
};
}
Вот скопипастил и вижу что волосня недетская. Но у каждого куска тут реально есть свое предназначение. UserEvent например непосредственно к сабжу отношения не имеют - это концы от http://asterisk-support.ru/forum/topics/5242/ торчат.
Установка сallerid из переменным - это чтобы приглашенные через веб юзеры правильные имена и номера имели ну и так далее.
|
Откуда: Уфа
Сообщений: 5856
|
Re: extensions.ael
мда, красиво.
но ты пользуешься этим синтаксисом как обычным языком.
Как я понял, в коде есть фрагмент, который, вроде как, парсит в переменные возвращенные поля с помощью цикла. я подхожу к этому проще. Вот пример контекста, который на входе имеет набираемый номер, а на выходе - транк, через который направить звонок:
[outbound]
exten => _X.,1,ExecIf($["${allow_external}" = "NO"]|macro|access-deny,s,1)
exten => _X.,n,Set(Query=${OUTBOUND_ROUTE(${EXTEN})})
exten => _X.,n,ExecIf($["${Query}" = ""]|macro|query-fail,s,1)
exten => _X.,n,Set(__Bnumber=${EXTEN})
exten => _X.,n,Set(__route_id=${CUT(Query,\,,1)})
exten => _X.,n,Set(intra_company=${CUT(Query,\,,2)})
exten => _X.,n,Set(moh_class=${CUT(Query,\,,3)})
exten => _X.,n,Set(caller_id_num=${CUT(Query,\,,4)})
exten => _X.,n,Set(caller_id_name=${CUT(Query,\,,5)})
exten => _X.,n,Set(item_type=${CUT(Query,\,,6)})
exten => _X.,n,Set(item_id=${CUT(Query,\,,7)})
exten => _X.,n,Set(record_out=${CUT(Query,\,,8)})
exten => _X.,n,Set(max_calls=${CUT(Query,\,,9)})
exten => _X.,n,Set(curr_calls=${CUT(Query,\,,10)})
exten => _X.,n,Set(secure=${CUT(Query,\,,11)})
exten => _X.,n,Set(Query=)
exten => _X.,n,ExecIf($["${intra_company}" = "YES"]|Set|CALLERID(num)=${caller_id_num}${CALLERID(num)})
exten => _X.,n,ExecIf($["${intra_company}" = "YES"]|Set|CALLERID(name)=${caller_id_name}${CALLERID(name)})
exten => _X.,n,ExecIf($["${intra_company}" = "NO"]|Set|CALLERID(num)=${caller_id_num})
exten => _X.,n,ExecIf($["${intra_company}" = "NO"]|Set|CALLERID(name)=${caller_id_name})
exten => _X.,n,ExecIf($["${record_out}" = "YES"]|MixMonitor|${STRFTIME(${EPOCH},,%Y%m%d-%H%M%S)}-${UNIQUEID}.wav)
exten => _X.,n,ExecIf($["${moh_class}" != ""]|Set|CHANNEL(musicclass)=${moh_class})
exten => _X.,n,ExecIf($["${item_type}" = "trunk"]|GoTo|trunks,${item_id},1)
exten => h,1,macro(hangupcall)
после запроса попросту парсим то, что вернулось. Соответственно все по-людски называется и без документирования понятно, что на входе и что на выходе.
|
Сообщений: 866
|
Re: extensions.ael
да, пользуюсь как обычным языком - я об этом и писал выше говоря что главный плюс AEL это то что он хоть как-то синтаксисом напоминает нормальный язык.
Твой код линеен только по той причине что извлекаешь из результата поля по индексу (позиции) а не по имени как делаю я. Я имел достаточно приятных моментов в жизни когда кто-то менял cторед процедуру или вьюшку в базе, какие-то колонки удалялись, а для каких-то менлся порядок. И весь код продолжал работать нормально кроме одной разнесчастной утилиты которая запускается рвз в месяц, которая читает колонки по индексу и которая не понимает что что-то не так и не выдает никакой диагностики потому колонки которые она считывает физически присутствуют в результате но данные в них уже не те что должны быть. Мне хватило. По позициям хорошо когда дисциплина как в армии или ты все девелопишь один. А когда есть команда - надо писать код так чтобы компенсировать промахи других. В общем там где я могу использовать имена - я их и использую.
Второе что дает линейность это то что ты используешь ExecIf а не GotoIf. Это прокатывает когда есть пара действий которые надо сделать по какому-то условию - типа Set|CALLERID(num)) плюс Set|CALLERID(name)). А если таких действий десяток это просто жесткий копипаст будет. Тут уже дело вкуса конечно но мне лично, невзлюбившему диалплан за exten => _X.,n,
в начале каждой строчки можешь представить какие эмоции вызывает exten => _X.,n,ExecIf($["${intra_company}" = "NO"]
в начале каждой из подряд идущих 10 строк :)
|
Откуда: Уфа
Сообщений: 5856
|
Re: extensions.ael
гыыыыы
а как ты по имени поля вытаскиваешь? у тебя денормированные таблицы?
не хватает, блин, в астере ассоциативных массивов...
|
Сообщений: 866
|
Re: extensions.ael
ммм. не совсем понял.
у меня нормальная таблица. просто поля из результата выборки я беру по именам, а ты по позициям.
Т.е. если бы был SELECT callerid, name FROM sometable
то ты берешь callerid как первое значение из query, а name - как второе. А я же не завязываюсь на порядок, разбираю все пары имя/значение и ищу те имена которые мне нужны.
"${REALTIME(meetme,confno,${confno},*,~)}" вытаскивает строку из таблицы разделяя колонки звездой и отделяя имя от значения тильдой. То есть для вышеприведенной таблицы результат будет что-то вроде
callerid~234*name~abc
|
Откуда: Уфа
Сообщений: 5856
|
Re: extensions.ael
а-а-а
ну у меня возвращаются значения, разделенные запятыми.
Еслиб были имена, то многое упростилось бы...
|
|