sip messages: отложенная доставка
Непорядок!
Работать будем с asterisk 11, с установленным FreePBX. Традиционно «без конфигов» в этот раз не получится :(
Итак, разрешаем работу messages и указываем контекст обработки оных, в разделе вебморды Settings → Asterisk SIP Settings. В самом низу добавляем кастомные поля для sip.conf и указываем: accept_outofcall_message = yes
outofcall_message_context = messages
auth_message_requests = no
Создаем в extensions_custom.conf этот контекст: [messages]
exten => _.,1,Set(MSG_TO=${CUT(MESSAGE(to),@,1)})
exten => _.,n,MessageSend(${MSG_TO},${MESSAGE(from)})
exten => _.,n,GotoIf($["${MESSAGE_SEND_STATUS}" != "SUCCESS"]?sendfailedmsg)
exten => _.,n,Hangup()
exten => _.,n(sendfailedmsg),Set(MSG_TMP=${CUT(MESSAGE(from),<,2)})
exten => _.,n,Set(MSG_FROM=${CUT(MSG_TMP,@,1)})
exten => _.,n,Set(ODBC_SAVE_MESSAGE("${MESSAGE(from)}","${MSG_TO}","${MESSAGE(body)}")=1)
exten => _.,n,Set(MESSAGE(body)="[${STRFTIME(${EPOCH},,%d%m%Y-%H:%M:%S)}] Ваше сообщение для ${EXTEN} не доставлено. Оно будет доставлено, когда абонент появится в сети.")
exten => _.,n,MessageSend(${MSG_FROM}, SYSTEM)
exten => _.,n,Hangup()
В этом контексте присутствует вызов ODBC-функции, которая сохраняет «SMS-ку» в СУБД MySQL. Чтобы не морочится с отдельными базами и DSN, я создал таблицу в имеющейся базе asteriskcdrdb:
CREATE TABLE IF NOT EXISTS `messages` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`dt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`mfrom` varchar(100) CHARACTER SET utf8 NOT NULL,
`mto` varchar(100) CHARACTER SET utf8 NOT NULL,
`mbody` text CHARACTER SET utf8 NOT NULL,
`delivered` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
В файле func_odbc.conf добавим саму ODBC_функцию: [SAVE_MESSAGE]
writesql = INSERT INTO messages (mfrom,mto,mbody) VALUES ('${ARG1}','${ARG2}','${BASE64_ENCODE(${ARG3})}')
dsn = asteriskcdrdb
Как видим, текст сообщения перед сохранением кодируется в base_64. Таким нехитрым образом я обхожу глюки с кириллицей. Кстати, передачу текста в контексте messages обязательно заключать в кавычки, иначе при появлении например запятой в тексте диалпан считает это разделителем параметров :)
Итак, сообщения у нас сохраняются в базу при отсутствии абонента в сети. Осталось настроить механизм доставки ему сего сообщения. Делать будем на php, скрипт я положил в /etc/asterisk/send_delayes_messages.php:
В качестве метки для факта доставки я использую поле delivered типа timestamp, если там нули — то сообщение нуждается в доставке. Таким образом, пробегая по сохраненным недоставленным сообщениям, мы проверям по каждому наличие регистрации пира через команду cli, и если он в сети — создаем outgoing call file, который и производит доставку сего сообщения. После этого скрипт помечает в базе сообщение, устанавливая дату отправки.
Останется прикрутить скрипт через php -f /etc/asterisk/send_delayes_messages.php в поминутный крон и раз в минуту будет производится проверка и попытка доставки сообщения.
Какие минусы у этой реализации? Первый — регистрация статуса пира держится какое то время после обрыва, и вполне возможна ситуация, когда пир кратковременно зарегистрируется и отвалится, а система «отправит» в течение минуты ему сообщение, и будет считать его доставленным. Выкрутится можно, использовав не Application в call-файле, а передачу данных в контекст с проверкой статуса переменной ${MESSAGE_SEND_STATUS}. Наверное, возможно будет использовать имеющийся контекст, задав переменные через Set в call-файле.
Но я пока остановился на этом: некогда.
Удачи!