После инициализации и авторизации компонента на сервере Asterisk между компонентом и сервером устанавливается HTTP соединение, по которому сервер телефонии передает информацию о текущем состоянии каналов, вызовов, а так же результат выполнения различных команд. Полученные ответы разбираются компонентом при помощи встроенного XML парсера и вызывают в сеансе 1С:Предприятия встроенную функцию *ВнешнееСобытие*.
Таким образом, все события компонента можно обработать в любой открытой форме или в модуле обычного приложения. В качестве переменных используются 3 строковых параметра:
В параметр *Источник* всегда передается строка MikoAjamEvent которая позволяет однозначно идентифицировать события отправленные компонентой. В параметр *Событие* передается наименование события Asterisk или строки Error, Exeption, свидетельствующие о возникновении нештатной ситуации, например разрыв связи с Asterisk. В параметр *Данные* передается XML строка, содержащая весь пакет данных, полученных от сервера Acterisk без каких либо модификаций или техническую информацию о ошибке в работе компонента.
Стандартный вид обработки внешнего события компоненты выглядит так:
Процедура ВнешнееСобытие(Источник, Событие, Данные) Если Источник="MikoAjamEvent" Тогда // проверим ответ от нашей ли компоненты? Если Событие="Error" Возврат; // тут надо разбираться в причинах сбоя, иногда они штатные и требуют просто переподключения компоненты. КонецЕсли; //ПРИМЕР ОТВЕТА Попытка Если Событие="Hangup" Тогда //Положили трубку //ПРИМЕР ОТВЕТА В ПЕРЕМЕННОЙ "ДАННЫЕ" //<generic //event='Hangup' //privilege='call,all' //sequencenumber='53031' //file='channel.c' //line='1901' //func='ast_hangup' //channel='SIP/263-0000013c' //uniqueid='1322225501.546' //calleridnum='263' //calleridname='<unknown>' //cause='16' //cause_txt='Normal Clearing' ///> ИначеЕсли Событие="Bridge" Тогда //2 абонента соединились и разговаривают //ПРИМЕР ОТВЕТА В ПЕРЕМЕННОЙ "ДАННЫЕ" исходящий звонок с 263 на 04 //<generic //event='Bridge' //privilege='call,all' //sequencenumber='56804' //file='channel.c' //line='5345' //func='manager_bridge_event' //bridgestate='Link' //bridgetype='core' //channel1='SIP/263-0000014b' //channel2='SIP/04-0000014c' //uniqueid1='1322226827.577' //uniqueid2='1322226827.578' //callerid1='263' //callerid2='04' ///> //Пример ответа Входящий звонок с 79265557842 на мультифонтранк //<generic // event='Bridge' // privilege='call,all' // sequencenumber='67966' // file='channel.c' // line='5345' // func='manager_bridge_event' // bridgestate='Link' // bridgetype='core' // channel1='SIP/multifon-out-00000171' // channel2='SIP/263-00000172' // uniqueid1='1322297638.642' // uniqueid2='1322297638.643' // callerid1='79265557842' // callerid2='263' // /> ИначеЕсли Событие="Unlink" Тогда //ПРИМЕР ОТВЕТА В ПЕРЕМЕННОЙ "ДАННЫЕ" // <generic // event='Unlink' // privilege='call,all' // channel1='SIP/263-000000e0' // channel2='SIP/17-000000e1' // uniqueid1='1322828367.324' // uniqueid2='1322828367.325' // callerid1='263' // callerid2='17' // /> ИначеЕсли Событие="Dial" Тогда //Входящий звонок до поднятия трубочки //ПРИМЕР ОТВЕТА В ПЕРЕМЕННОЙ "ДАННЫЕ" при внешнем входящем звонке с номера 79265557842 на мультифон транк //<generic // event='Dial' // privilege='call,all' // sequencenumber='67955' // file='app_dial.c' // line='695' // func='senddialevent' // subevent='Begin' // channel='SIP/multifon-out-00000171' // destination='SIP/263-00000172' // calleridnum='79265557842' // calleridname='MIKOKONTRAGENT' // uniqueid='1322297638.642' // destuniqueid='1322297638.643' // dialstring='263' // /> ИначеЕсли Событие="PeerStatus" Тогда //ПРИМЕР ОТВЕТА В ПЕРЕМЕННОЙ "ДАННЫЕ" //<generic //event='PeerStatus' //privilege='system,all' //sequencenumber='56136' //file='chan_sip.c' //line='12937' //func='parse_register_contact' //channeltype='SIP' //peer='SIP/261' //peerstatus='Registered' //address='172.16.32.123' //port='51789' // /> ИначеЕсли Событие="VarSet" Тогда //ПРИМЕР ОТВЕТА В ПЕРЕМЕННОЙ "ДАННЫЕ" //<generic //event='VarSet' //privilege='dialplan,all' //sequencenumber='54665' //file='pbx.c' //line='9141' //func='pbx_builtin_setvar_helper' //channel='Local/79265557842@from-internal-74f9;2' //variable='MACRO_DEPTH' //value='1' //uniqueid='1322226019.562' // /> ИначеЕсли Событие="Newchannel" Тогда //ПРИМЕР ОТВЕТА В ПЕРЕМЕННОЙ "ДАННЫЕ" Звоню с номера 263 на номер 17 //<generic // event='Newchannel' // privilege='call,all' // sequencenumber='83247' // file='channel.c' // line='978' // func='__ast_channel_alloc_ap' // channel='SIP/263-000001ca' // channelstate='0' // channelstatedesc='Down' // calleridnum='263' // calleridname='device' // accountcode='' // exten='17' // context='from-internal' // uniqueid='1322315915.748' /> // /> //ПРИМЕР ОТВЕТА В ПЕРЕМЕННОЙ "ДАННЫЕ" Звоню с номера 74997623634 на номер 229-30-42 оператора МАНГО //<generic //event='Newchannel' //privilege='call,all' //channel='SIP/mangotrunk-0000016b' //channelstate='0' //channelstatedesc='Down' //calleridnum='74997623634' //calleridname='74997623634' //accountcode='' //exten='info' //context='from-trunk-sip-mangotrunk' //uniqueid='1323941846.598' /> ИначеЕсли Событие="Newstate" Тогда //ПРИМЕР ОТВЕТА В ПЕРЕМЕННОЙ "ДАННЫЕ" //<generic //event='Newstate' //privilege='call,all' //sequencenumber='56419' //file='channel.c' //line='5082' //func='ast_setstate' //channel='SIP/17-0000014a' //channelstate='5' //channelstatedesc='Ringing' //calleridnum='17' //calleridname='' //uniqueid='1322226729.576' // /> ИначеЕсли Событие="Newexten" Тогда //ПРИМЕР ОТВЕТА В ПЕРЕМЕННОЙ "ДАННЫЕ" //<generic //event='Newexten' //privilege='dialplan,all' //sequencenumber='53042' //file='pbx.c' //line='3725' //func='pbx_extension_helper' //channel='SIP/263-0000013b' //context='from-internal' //extension='h' //priority='1' //application='Hangup' //appdata='' //uniqueid='1322225501.545' ///> ИначеЕсли Событие="NewCallerid" Тогда //ПРИМЕР ОТВЕТА В ПЕРЕМЕННОЙ "ДАННЫЕ" //<generic //event='NewCallerid' //privilege='call,all' //sequencenumber='54753' //file='channel.c' //line='4727' //func='report_new_callerid' //channel='SIP/multifon-out-00000144' //calleridnum='79036288313' //calleridname='' //uniqueid='1322226019.564' //cid_callingpres='0 (Presentation Allowed, Not Screened)' // /> ИначеЕсли Событие="Registry" Тогда //ПРИМЕР ОТВЕТА В ПЕРЕМЕННОЙ "ДАННЫЕ" //<generic //event='Registry' //privilege='system,all' //sequencenumber='56138' //file='chan_sip.c' //line='18725' //func='handle_response_register' //channeltype='SIP' //domain='sbc.megafon.ru' //status='Registered' // /> ИначеЕсли Событие="ExtensionStatus" Тогда //ПРИМЕР ОТВЕТА В ПЕРЕМЕННОЙ "ДАННЫЕ" //<generic //event='ExtensionStatus' //privilege='call,all' //sequencenumber='54947' //file='manager.c' //line='3518' //func='manager_state_cb' //exten='02' //context='ext-local' //hint='SIP/02' //status='0' // /> ИначеЕсли Событие="Cdr" Тогда //ПРИМЕР ОТВЕТА В ПЕРЕМЕННОЙ "ДАННЫЕ" //<generic //event='Cdr' //privilege='cdr,all' //sequencenumber='53045' //file='cdr_manager.c' //line='189' //func='manager_log' //accountcode='' //source='263' //destination='263' //destinationcontext='from-internal' //callerid='"WORK Vasiliy Pupkin" <263>' //channel='SIP/263-0000013b' //destinationchannel='SIP/263-0000013c' //lastapplication='Dial' //lastdata='SIP/263,,tr' //starttime='2011-11-25 16:51:41' //answertime='' //endtime='2011-11-25 16:51:43' //duration='2' //billableseconds='0' //disposition='NO ANSWER' //amaflags='DOCUMENTATION' //uniqueid='1322225501.545' //userfield='' // /> ИначеЕсли Событие="SkypeBuddyStatus" Тогда //ПРИМЕР ОТВЕТА В ПЕРЕМЕННОЙ "ДАННЫЕ" //<generic //event='SkypeBuddyStatus' //privilege='system,all' //sequencenumber='54952' //file='chan_skype.c' //line='3239' //func='buddy_state_change' //buddy='Skype/miko_team@boffart' //buddystatus='Online' // /> ИначеЕсли Событие="SkypeChatMessage" Тогда //ПРИМЕР ОТВЕТА В ПЕРЕМЕННОЙ "ДАННЫЕ" //<generic //event='SkypeChatMessage' //privilege='system,all' //sequencenumber='56124' //file='chan_skype.c' //line='871' //func='new_chat_message' //to='miko_team' //from='jorikfon' //message='Privet Chuvak' // /> ИначеЕсли Событие="ReceiveFAX" Тогда //ПРИМЕР ОТВЕТА В ПЕРЕМЕННОЙ "ДАННЫЕ" //<generic // event='ReceiveFAX' // privilege='call,all' // sequencenumber='508724' // file='res_fax.c' // line='1654' // func='receivefax_exec' // channel='SIP/mangotrunk-00000a37' // context='ext-fax' // exten='s' // callerid='A16551705P1' // remotestationid='(null)' // localstationid='(null)' // pagestransferred='0' // resolution='(null)' // transferrate='(null)' // filename='/var/spool/asterisk/fax/1322812029.3901.tif' // /> ИначеЕсли Событие="SendFAX" Тогда //ПРИМЕР ОТВЕТА В ПЕРЕМЕННОЙ "ДАННЫЕ" // <generic // event='SendFAX' // privilege='call,all' // sequencenumber='506205' // file='res_fax.c' // line='2155' // func='sendfax_exec' // channel='SIP/263-00000a31' // context='amidll' // exten='333' // callerid='263' // remotestationid='(null)' // localstationid='(null)' // pagestransferred='0' // resolution='(null)' // transferrate='(null)' // filename='/var/spool/asterisk/tmp/SIP-261-fax.tif' // /> ИначеЕсли Событие="RTPReceiverStat" Тогда //ПРИМЕР ОТВЕТА В ПЕРЕМЕННОЙ "ДАННЫЕ" //<generic event='RTPReceiverStat' //privilege='reporting,all' //ssrc='0' //receivedpackets='0' //lostpackets='0' //jitter='0.0000' //transit='0.0000' //rrcount='0' /> ИначеЕсли Событие="RTPSenderStat" Тогда //ПРИМЕР ОТВЕТА В ПЕРЕМЕННОЙ "ДАННЫЕ" //<generic //event='RTPSenderStat' //privilege='reporting,all' //ssrc='901146673' //sentpackets='0' //lostpackets='0' //jitter='0' //srcount='0' //rtt='0.000000' ///> ИначеЕсли Событие="ChannelUpdate" Тогда //ПРИМЕР ОТВЕТА В ПЕРЕМЕННОЙ "ДАННЫЕ" //<generic //event='ChannelUpdate' //privilege='system,all' //channel='SIP/261-00000164' //uniqueid='1323940821.591' //channeltype='SIP' //sipcallid='NvKuRBoMgAVDmxHbntsStBfN9DbmGvMH' //sipfullcontact='sip:261@192.168.1.122:49935;transport=TCP' ///> КонецЕсли; // По виду события КонецЕсли; КонецПроцедуры
В приведенном выше коде мы проиллюстрировали возможный вариант обработки внешних событий компонента. Данные, переданные в параметр *Данные*, представляют из себя XML структуру, которую можно разобрать, используя функцию ЧтениеXML языка 1С:Предприятие 8.
Пример разбора ответа используя объект ЧтениеXML:
ЧтениеXML = Новый ЧтениеXML; ЧтениеXML.УстановитьСтроку(Данные); CallerID1 = ЧтениеXML.ЗначениеАтрибута("Callerid1"); CallerID2 = ЧтениеXML.ЗначениеАтрибута("Callerid2"); Channel1 = ЧтениеXML.ЗначениеАтрибута("Channel1"); Channel2 = ЧтениеXML.ЗначениеАтрибута("Channel2"); UniqueID1 = ЧтениеXML.ЗначениеАтрибута("Uniqueid1"); UniqueID2 = ЧтениеXML.ЗначениеАтрибута("Uniqueid2");
Например, при использовании WEB клиента Mozilla Firefox мы реализовали разбор ответа следующим образом:
&НаКлиенте Процедура ВнешнееСобытие(Источник, Событие, Данные) Если Источник="MikoAjamEvent" Тогда // проверим ответ от нашей ли компоненты? СтруктураПолей=РазобратьОтветАстериска(Данные); CallerID1 = СтруктураПолей.Получить("callerid1"); CallerID2 = СтруктураПолей.Получить("callerid2"); channel1 = СтруктураПолей.Получить("channel1"); КонецЕсли; Конецпроцедуры; &НаКлиенте // разбирает строку XML в соответсвие ключ - значение Функция РазобратьОтветАстериска(Данные) СимволДвоеточиеПробел="="; МассивПодстрок=РазложитьСтрокуВМассивПодстрок(Данные," "); ПараметрыОтвета=Новый Соответствие; Для к=0 по МассивПодстрок.Количество()-1 Цикл СтрокаДляРазбора = СокрЛП(МассивПодстрок[к]); ПозицияРазделителя = Найти(СтрокаДляРазбора,СимволДвоеточиеПробел); ДлинаСтроки = СтрДлина(СтрокаДляРазбора); Если ПозицияРазделителя<>0 Тогда Параметр=Лев(СтрокаДляРазбора,ПозицияРазделителя-1); Значение=Прав(СтрокаДляРазбора,ДлинаСтроки-ПозицияРазделителя-1); Значение=Лев(Значение,СтрДлина(Значение)-1); ПараметрыОтвета.Вставить(Параметр,Значение); КонецЕсли; КонецЦикла; Возврат ПараметрыОтвета; КонецФункции //РазобратьОтветАстериска &НаКлиенте //Переданную строку, разбивает в массив Функция РазложитьСтрокуВМассивПодстрок(Знач Стр, Разделитель = ",") Экспорт МассивСтрок = Новый Массив(); Если Разделитель = " " Тогда Стр = СокрЛП(Стр); Пока Истина Цикл Поз = Найти(Стр,Разделитель); Если Поз=0 Тогда МассивСтрок.Добавить(Стр); Возврат МассивСтрок; КонецЕсли; МассивСтрок.Добавить(Лев(Стр,Поз-1)); Стр = СокрЛ(Сред(Стр,Поз)); КонецЦикла; Иначе ДлинаРазделителя = СтрДлина(Разделитель); Пока Истина Цикл Поз = Найти(Стр,Разделитель); Если Поз=0 Тогда МассивСтрок.Добавить(Стр); Возврат МассивСтрок; КонецЕсли; МассивСтрок.Добавить(Лев(Стр,Поз-1)); Стр = Сред(Стр,Поз+ДлинаРазделителя); КонецЦикла; КонецЕсли; КонецФункции // РазложитьСтрокуВМассивПодстрок