Организовать разрыв соединения по условию
Сообщений: 27
|
Организовать разрыв соединения по условию
Здравтсвуйте, уважаемое сообщество! Вопрос такой: Набрал абонент номер, вызвалось приложение Dial(), установилось соединение, идет разговор. Хочется например, каждую минуту проверять какое-либо условие, и при его выполнении разрывать звонок. Как это можно реализовать в диалплане? Спасибо.
|
Сообщений: 866
|
Re: Организовать разрыв соединения по условию
думаю что сбоку надо это делать а не в диалплане.
т.е. какой-нибудь вечнокрутящийся демон который по AMI астериск мучает - берет текущий список разговоров, проверяет все что ему нужно и если пора - шлет команду на разрыв.
|
Сообщений: 27
|
Re: Организовать разрыв соединения по условию
2Dimas: спасибо за ответ!
2All: Немного уточню. В ODBC-базе есть запись пользователя, (карточки), есть поле кредитс, и вот, когда идет сеанс связи необходимо это поле раз в минуту моджифицировать, и если оно 0 то делать разрыв...
|
Откуда: Уфа
Сообщений: 5856
|
Re: Организовать разрыв соединения по условию
ну да, только отдельным демоном.
я бы написал скрипт, который по крону парсит show channels concise, читает/пишет в базу все что надо и дропит нужные каналы. работы на полдня, загрузка процессора - ни о чем.
т.е. тоже самое что и предложил dimas
|
Сообщений: 27
|
Re: Организовать разрыв соединения по условию
Ок, всем спасибо, уже пробую писать нечто подобное. Для вновь читающих - любые Ваши мысли и соображения приветствуются!
|
Сообщений: 27
|
Re: Организовать разрыв соединения по условию
Вот, примерно такой получился код. Планирую запускать по крону с частотой аз в 30 секунд.
<?php
require_once('phpagi-asmanager.php');
$asm=new AGI_AsteriskManager();
if($asm->connect())
{
$link = mysql_connect('localhost', 'root', 'parol') or die("connect DB - bad: ".mysql_error());
mysql_select_db('asterisk') or die("choose DB - bad: ".mysql_error());
$call=$asm->send_request('Command', array('Command'=>"show channels concise"));
$chan=explode("\n", $call['data']);
for($i=1;$i<count($chan)-1;$i++)
{
$chan[$i]=substr($chan[$i], 0, strpos($chan[$i], "!", 0));
$call=$asm->GetVar($chan[$i],"PIN_ENTERED");
$reschan[$i]['Channel']=$chan[$i];
$reschan[$i]['Pin']=$call['Value'];
echo $reschan[$i]['Channel']."***".$reschan[$i]['Pin']."<BR>";
}
for($i=1;$i<=count($reschan);$i++)
{
if($reschan[$i]['Pin']!="" & $reschan[$i]['Pin']!=null){
$sql="SELECT credits FROM cards WHERE pin=".$reschan[$i]['Pin'];
$res=mysql_query($sql);
$r=mysql_fetch_array($res);
if($r['credits']>0){
$r['credits']--;
$sql="UPDATE cards SET credits=".$r['credits']." WHERE pin=".$reschan[$i]['Pin'];
$res=mysql_query($sql);
} else {
$sql="DELETE FROM cards WHERE pin=".$reschan[$i]['Pin'];
$res=mysql_query($sql);
}
}
}
$asm->disconnect();
mysql_close($link);
die("");
}
?>
|
Сообщений: 866
|
Re: Организовать разрыв соединения по условию
ну для меня вообще новость что крон с шагом меньше минуты умеет что-то запускать... Ну и поле credit тоже тогда должно не в минутах быть а в 30 секундных интервалах...
Да и зачем вообще крон тут? стартуйте один раз и крутитесь в цикле со sleep. Опять же к базе один раз законнектились и этот же коннект реюзается.
Ну и главное: это конечно дело вкуса как подобный биллинг реализовывать но по мне так такая схема порочна в принципе т.к.:
1. звонки меньше минуты имеют все шансы быть неучтенными
2. на больщом количестве звонков когда время работы самого скрипта становится больше секунды - начинает убегать время, сначала он запустится в 13:25:00, потом не в 13:26:00 а в 14:26:01 и так далее - опять же бесплатные секунды всем желающим. (Это все верно если таки демон сам крутится, ибо если по крону то такой проблемы нет, но первая - есть).
Я бы делал совсемм по другому:
1. завел бы табличку current_calls типа
(channel varchar(255), call_start datetime not null, last_update datetime not null, pin varchar(50) not null)
2. раз в минуту бы дергал core show channels. Для каналов которых еще нет в current_calls считывал бы из переменных пин и время начала звонка и добавлял бы запись в current_calls.
3. если звонок уже есть в current_calls - обновлял бы last_updated=NOW()
4. сделалл бы вьюшку v_current_calls которая делает селект из этой таблицы + добавляет колонку - разницу в минутах между last_update и call_start - это текущая продолжителльность данного звонка.
5. сделал бы вьюшку v_card_credit которая селектит cards и пересекает ее с v_current_calls причем из колонки credit таблицы cards вычитается суммарный duration всех звонков с этим пином из v_current_calls - что дает кредит за вычетом того что уже набежало по текущим активным разговорам.
6. по этой вьюшке пас бы пины которые надо замочить (у которых кредит обнулился)
7. по окончании звонка (exten h) подчищал бы сurrent_calls - удалял бы запись из таблицы предварительно "продавив" ее в cards - уменьшив кредит там на нужное число минут.
8. Если по-хорошему делать, то нужно еще и данные из Астериском сгенеренного CDR время от времени вливать - ибо всякое может быть. Реалтайм обрывалка звонков может сломаться по какой-то причине и тогда все звонки уйдут неучтенными. А если данные из CDR вливаются хотя бы раз в час тогда пока все хорошо (реалтаймовая обрывалка работает), все пишется и обновляется каждую минуту, это нормальный режим. Но даже если все умерло - то через час вольются данные из CDR и хоть так звонки учттутся. Худшее что случится - кто-то получит час разговоров. Но это всяко лучше чем год пока вы обнаружите что скрипт умер :) Естествено нужно позвботится о том чтобы то что уже посчиталось реалтайм демоном не было второй раз учтено по CDR.
но что-то мне подсказывает что этот велосипед уже изобрели...
|
Откуда: Уфа
Сообщений: 5856
|
Re: Организовать разрыв соединения по условию
что-то dimas заморочено придумал:
четыре select+update вместо одного. Возможно даст выигрыш при большом кол-ве звонков, и если вынести БД и все обработки на отдельную машину. Хотя ни что не мешает вынести скрипт на отдельную машину с биллингом.
по поводу задержки: как-то делал подобный скрипт, но он тупо обрабатывал текущие вызовы для статистики, пихал все сведения о текущих звонках в базу. Тестировал на 100 одновременных вызовах (примерно) скрипт запускался каждые 5 секунд по крону и отрабатывал очень быстро.
если нужно запускать чаще чем каждую минуту по крону, то делаешь глобальный цикл, в котором есть sleep, например, 10 и 5 итераций. скрипт будет выполняться каждые 6 секунд и будет синхронизирован во времени. ±1..2 секунды врядли имеет значение
|
Сообщений: 866
|
Re: Организовать разрыв соединения по условию
четыре select+update вместо одного
ну одним тут не обойтись полюбасу.
по мне все схемы с декрементами порочны по определению. ибо БД есть вещь асинхронная без гарантированного времени реакции. Очень хорошо что сто запросов она обработала без задержек, а на сто первом апдейте ее заколбасит на десять секунд и все - досвидос. И все доводы тут сводятся к "я ни разу не видел чтобы она вдруг медленнее обработала запрос чем за 0.01 секунды" и "нет причин чтобы такое случилось" - это все в пользу бедных. Может и все тут. Меня учили писать так чтобы подобное никак на точности биллинга не сказывалось.
|
Сообщений: 866
|
Re: Организовать разрыв соединения по условию
ps: к тому же где четыре-то?
1. для каждого канала - UPDATE чтобы проставить last_update=NOW.
если rows_affected вернул 0 значит нет такого канала в базе - делаем INSERT. При этом инсерт делается только для канала который мы увидели впервые, для повторного все ограничивается апдейтом.
2. один SELECT из v_card_credit where pin IN (... набор пинов активных каналов...) AND credit <= 0 это чтобы найти активные каналы у которых до нуля кредит дошел.
|
|