Asterisk: Лимитирование звонков по каналу.


Т.к. некоторые SIP/VoIP провайдеры далют халяву с некоторыми ограничениями (на пример sipnet) на количество звонков и их общую продолжительность, захотелось этим воспользоваться, но при этом не попадать на деньги.

Нарисовал 2-а макроса. Первый для учета количества звонков и их длительности, второй для выбора  необходимого транка.

1. Учет звонков.

Учитываем только отвеченные

[macro-count_dial_from_trunk]
exten => s,1,NoOp(${CDR(duration)} ${CDR(billsec)})

; Enable call limit control ?
exten => s,n,GotoIf($[${DB(trunk/${NAME_TRUNK}/day/limit-enable)} = 1 ]?:noanswer)
exten => s,n,GotoIf($[${DIALSTATUS} = ANSWER ]?:noanswer)

exten => s,n,Set(foo=${CUT(CDR(dstchannel),,1)})
exten => s,n,Set(foo=${CUT(foo,/,2)})

exten => s,n,GotoIf($[${ISNULL(${DB(trunk/${foo}/day/call-time)})}]?:continue_call-time)
exten => s,n,Set(DB(trunk/${foo}/day/call-time)=0)
exten => s,n(continue_call-time),Set(DB(trunk/${foo}/day/call-time)=$[${DB(trunk/${foo}/day/call-time)}+${CDR(billsec)}])

exten => s,n,GotoIf($[${ISNULL(${DB(trunk/${foo}/day/call)})}]?:continue_call)
exten => s,n,Set(DB(trunk/${foo}/day/call)=0)
exten => s,n(continue_call),Set(DB(trunk/${foo}/day/call)=$[ ${DB(trunk/${foo}/day/call)} + 1 ])

exten => s,n(noanswer),Verbose(4,Call count:${DB(trunk/${foo}/day/call)} - time(s):${DB(trunk/${foo}/day/call-time)})

2. Проверка превышения лимита

[macro-call_limit_control]
; arg1 - trunk_control
; arg2 - context no limit exceeded
; arg3 - context limit exceeded
exten => s,1,Set(NAME_TRUNK=${CUT(ARG1,/,2)})
exten => s,n,Set(CONTEXT_OK=${ARG2})
exten => s,n,Set(CONTEXT_LIMIT_EXCEEDED=${ARG3})

; Enable call limit control ?
exten => s,n,GotoIf($[${DB(trunk/${NAME_TRUNK}/day/limit-enable)} = 1 ]?:no_call_time-limit)

; Get call limit
exten => s,n,Set(CALL=${DB(trunk/${NAME_TRUNK}/day/call)})
exten => s,n,GotoIf($[${ISNULL(${CALL})}]?:continue_call)
exten => s,n,Set(CALL=0)
exten => s,n(continue_call),NoOp(Set call = ${CALL})

exten => s,n,Set(CALL-LIMIT=${DB(trunk/${NAME_TRUNK}/day/call-limit)})
exten => s,n,GotoIf($[${ISNULL(${CALL-LIMIT})}]?:continue_call-limit)
exten => s,n,Set(CALL-LIMIT=0)
exten => s,n,Set(DB(trunk/${NAME_TRUNK}/day/call-limit)=0)
exten => s,n(continue_call-limit),NoOp(Call limit = ${CALL-LIMIT})

; Get call time limit
exten => s,n,Set(CALL-TIME=${DB(trunk/${NAME_TRUNK}/day/call-time)})
exten => s,n,GotoIf($[${ISNULL(${CALL-TIME})}]?:continue_call_time)
exten => s,n,Set(CALL-TIME=0)
exten => s,n(continue_call_time),NoOp(Set call time = ${CALL-TIME})

exten => s,n,Set(CALL-TIME-LIMIT=${DB(trunk/${NAME_TRUNK}/day/call-time-limit)})
exten => s,n,GotoIf($[${ISNULL(${CALL-TIME-LIMIT})}]?:continue_call_time-limit)
exten => s,n,Set(CALL-TIME-LIMIT=0)
exten => s,n,Set(DB(trunk/${NAME_TRUNK}/day/call-time-limit)=0)
exten => s,n(continue_call_time-limit),NoOp(Set call time limit = ${CALL-TIME-LIMIT})

; Control Limit Call
exten => s,n,GotoIf($[${CALL-LIMIT} = 0]?ctrl_time_limit)
exten => s,n,GotoIf($[${CALL} < ${CALL-LIMIT}]?:${CONTEXT_LIMIT_EXCEEDED},${MACRO_EXTEN},1)

; Control Limit Call time
exten => s,n(ctrl_time_limit),GotoIf($[${CALL-TIME-LIMIT} = 0]?no_call_time-limit)
exten => s,n,GotoIf($[${CALL} < ${CALL-LIMIT}]?:${CONTEXT_LIMIT_EXCEEDED},${MACRO_EXTEN},1)

exten => s,n(no_call_time-limit),Goto(${CONTEXT_OK},${MACRO_EXTEN},1)

Вызывается с параметрами:

  1. Контролируемый канал
  2. Контекст в который передать управление если лимит не исчерпан
  3. Контекст в случае исчерпания лимита

Если лимит не выставлен или не превышен, то управление передается в первый контекст, 1-й приоритет того же экстеншена. Иначе во второй контекст.

Соответственно, все лимиты выставляются в AstDB следующим образом:

asterisk -rx "database put trunk/trunk_name/day call-limit 10"
asterisk -rx "database put trunk/trunk_name/day call-time-limit 3600"
asterisk -rx "database put trunk/trunk_name/day limit-enable 1"

Соответственно макрос проверки лимитов вызывается из контекста обработки экстеншенов, а макрос учета звонков и времени вызывается из контекста, откуда будет происходить звонок и вешается на экстеншен h.

Единственное, чего не хватает, это возвращения оставщегося времени, для ограничения длительности звонка.