Сервис автоматизированной отправки факсов

Имеем некий web-сервис, которому необходимо отправлять очень много факсов. Можно использовать сторонние сервисы, которые специализируются на этом. Но если факсов много, то это выливается в нехилую такую копеечку. Поэтому мы будем создавать свой сервис. Используя свой сервис, мы будем платить повременно за голосовой трафик. Сервис будет получать запрос на отправку факса и рапортовать нам о результатах.

Использовать будем Asterisk, может он не самый производительный, но хорошо известный. В нашей конфигурации мы будем использовать готовую сборку Elastix. Так же плюсом является наличие Apache и php. Доставлять пакеты не придется.

В Asterisk есть несколько способов отправки факсов: голосом через G.711 и с использованием T.38. Второй вариант предпочтительнее, т.к. вероятность доставки выше.

Так же есть 2 реализации отправки факсов:

  1. Spandsp OpenSource проект
    Spandsp уже включена в поставку Elastix.
  2. Digium Fax for Asterisk.
    Коммерческая реализация от авторов астериска, 1 конкурентная лицензия бесплатная. Подробности установки( http://docs.digium.com/FAX/fax_for_asterisk_admin_manual.pdf )

Логически систему можно разбить на 3 части.

  1. Прием запросов
  2. Ротация факсов
  3. Отправка факса и рапорт о результатах.

Прием запросов на отправку

Инициация отправки факса будет происходить посредством перемещения .call файла в папку выполения астериска. В call файле находятся все необходимые Asteriskу параметры для отправки.

faxsend.call
Callerid:"FaxSender"<1111>
Maxretries:maxRetries
Waittime:300
Context:faxsend-t38
Extension:faxout
RetryTime:50
Priority:1
SetVar: T38CALL=1
Set:RETURNURL={returnUrl}
Set:TAGLINE=Fax from CompanyName
Set:RECEIVER=Number Of Receiver
Set:FAX_ID={faxId}
Set:TIFF_2_SEND={faxId}.tif';

Создаем скрипт который будет принимать параметры и файл для отправки. Файл для отправки будем получать в PDF. Параметры на которые, думаю стоит обратить внимание:

  • maxRetries — количество попыток дозвона.
  • faxid – идентификатор факса для которого будет возвращаться статус.
  • returnUrl – адрес по которому будет возвращаться результат отправки.
index.php
<?php
define( "STATUS_SUCCESS", "success" );
define( "STATUS_ERROR", "fail" );
$pdfLocation = "//var//tmp//faxes//";
function sendStatus( $statusKind )
{
        header('Content-type: application/json');
        exit( "{\"status\": \"" . $statusKind . "\"}" );
}
 
$fax = $_REQUEST['fax'];
$faxId = $_REQUEST['faxId'];
$maxRetries = isset( $_REQUEST['maxRetries'] ) ? $_REQUEST['maxRetries']
: 0;
$returnUrl = $_REQUEST['returnUrl'];
$pdf = $faxId . '.pdf';
 
if ($fax == '' || $returnUrl == '' || $faxId == ''
)
{
        sendStatus( STATUS_ERROR );
}
 
if(!move_uploaded_file($_FILES['file']['tmp_name'], $pdfLocation .
$pdf))
{
        sendStatus( STATUS_ERROR );
}
 
$callFileBody = 'Channel:SIP/trunkname/{fax}
Callerid:"FaxSender"<1111>
Maxretries:{maxRetries}
Waittime:300
Context:faxsend-t38
Extension:faxout
RetryTime:50
Priority:1
SetVar: T38CALL=1
Set:RETURNURL={returnUrl}
Set:TAGLINE=Fax from Company
Set:RECEIVER={fax}
Set:FAX_ID={faxId}
Set:TIFF_2_SEND={faxId}.tif';
 
$callFileBody = str_replace("{fax}", $fax, $callFileBody);
$callFileBody = str_replace("{faxId}", $faxId, $callFileBody);
$callFileBody = str_replace("{maxRetries}", $maxRetries, $callFileBody);
$callFileBody = str_replace("{returnUrl}", $returnUrl, $callFileBody);
 
$callFilename = $faxId . ".call";
 
file_put_contents($pdfLocation . $callFilename, $callFileBody);
 
if (!file_exists($pdfLocation . $callFilename))
{
        sendStatus( STATUS_ERROR );
}
 
sendStatus( STATUS_SUCCESS );
 
?>

Таким образом в указанной папке pdfLocation появляется 2 файла: .call и .pdf. Данный скрипт можно поместить в какую-нибудь из подпапок в /var/www/html. Я создал папку faxservice. Таким образом наш сервис доступен по адресу http://serveradress/faxservice

По-умолчанию Elastix перенаправляет все запросы http на https. Что бы не заморачиваться с сертефикатами я этот редирект отключил:

/etc/httpd/conf.d/elastix.conf
# Apache-level configuration for Elastix administration interface
Timeout 300
# Default apache configuration specifies greater limits than these
#MaxClients       150
#MaxRequestsPerChild  1000
# Default apache User and Group diretives MUST be commented out
# in order for these to take effect.
User asterisk
Group asterisk
<Directory "/var/www/html">
    # Redirect administration interface to https
    #RewriteEngine off
    #RewriteCond %{HTTPS} off
    #RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
</Directory>

Просто закомментировал реврайты.

Ротация факсов

Нам необходим мониторинг этой папки на предмет появления новых заданий, и после появления заданий, передачи в очередь на отправку в Asterisk. Так же необходимо конвертация нашего pdf в tif Данный функционал мы реализуем с помощью bash скрипта:

rotare.sh
faxrotate
#!/bin/bash
SOURCEDIR="/var/tmp/faxes/"
for file in `ls $SOURCEDIR*.pdf `;
do
        callfile="${file/pdf/call}"
        if [ ! -e "$callfile" ]
        then
               continue
        fi 
        `gs -q -dNOPAUSE -dBATCH -sDEVICE=tiffg4 -sPAPERSIZE=letter -sOutputFile=${file/pdf/tif} $file`
        mv ${file/pdf/call} /var/spool/asterisk/outgoing
        rm $file
done

Подвешиваем выполнение данного скрипта каждую минуту от имени Asterisk.

«Отработанные» файлы tif будем удалять каждую ночь, хранить их будем 2 дня (на тот случай, если количество попыток будет большим, а промежутки между ними еще больше.):

/usr/bin/find /var/tmp/faxes -name "*tif" -mtime +2 –delete

Отправка факсов Asteriskом

Осталось теперь только научить Asterisk отправлять факсы через T.38 и рапортовать нам о результатах. Для начала необходимо «научить» Elastix работать с T.38

Для этого в sip_general_custom.conf добавляем:

t38pt_udptl=yes <file>
 
 
Примерный вид настроек транка:
<file lua>
[trunkname]
username=username
type=friend
transport=udp
secret=password
qualify=yes
nat=yes
insecure=port,invite
host=voip.host.com
disalow=all
directmedia=yes
context=from-pstn
canreinvite=yes
allow=ulaw&alaw

Далее необходимо создать контекст, который будет вызываться из call файла Его добавляем в

extensions_custom.conf
[faxsend-t38]
exten => faxout,1,Set(STARTTIME=${SHELL(date +%s)} )
exten => faxout,n,Wait(1)
exten => faxout,n,Playback(fax24,skip)
exten => faxout,n,Wait(1)
exten => faxout,n,NoOp(**** SENDING FAX ****)
; Set FAXOPTs
exten => faxout,n,NoOp(**** SETTING FAXOPT ****)
exten => faxout,n,Set(FAXFILE=${TIFF_2_SEND})
exten => faxout,n,Set(FAXOPT(ecm)=yes)
exten => faxout,n,Set(FAXOPT(headerinfo)=${TAGLINE})
exten => faxout,n,Set(FAXOPT(maxrate)=14400)
exten => faxout,n,Set(FAXOPT(minrate)=4800)
; Send the fax
exten => faxout,n,NoOp(**** SENDING FAX : ${FAXFILE} ****)
exten => faxout,n,SendFAX(/var/tmp/faxes/${FAXFILE},dfzs)
 
;Calculating Time of Sending
exten => faxout,n,Set(ENDTIME=${SHELL(date +%s)} )
exten => faxout,n,Set(TRANSFERTIME=${MATH(${ENDTIME}-${STARTTIME},int)})
;Actions after sending fax
exten => faxout,n,Set(NORMURL=${FAXOPT(error)})
exten => faxout,n,Set(STATUSMESSAGE=${REPLACE(NORMURL, ,+)})
exten => faxout,n,Set(FAXOPTRATE=${FAXOPT(rate)})
exten => faxout,n,Hangup
 
;Actions if no answer or busy
exten => failed,1,Set(FAXSTATUS=FAILED)
exten => failed,2,Set(STATUSMESSAGE=number+no+answer+or+busy)
exten => failed,3,Set(FAXOPTRATE=none)
 
exten => h,1,NoOP(------------------- FAX to ${EXTEN} with ${FAXSTATUS} -----------------)
exten => h,2,Set(CURLRESULT=${CURL(${RETURNURL}?fax=${RECEIVER}&faxId=${FAX_ID}&status=${FAXSTATUS}&message=${STATUSMESSAGE})})
exten => h,4,Set(LOGFAXOUT=${SHELL(echo "${STRFTIME(${EPOCH},,%d%m%Y-%H:%M:%S)} : ${FAX_ID} : ${RECEIVER} : ${FAXSTATUS} : ${STATUSMESSAGE} : ${TRANSFERTIME}s : ${FAXOPTRATE}" >> /var/log/asterisk/faxout.log)})
exten => h,3,NoOp(${RECEIVER}:${FAX_ID}:${FAXSTATUS}:${STATUSMESSAGE}:${FAXOPTRATE})

Данный контекст пытается дозвониться и отправить факс, при недозвоне он возвращает number+no+answer+or+busy. При удачном дозвоне и попытке отправки возвращает статус и расшифровку статусного сообщения. Эту информацию он возвращает по адресу RETURNURL из php скрипта. Так же он пишет лог файл для дальнейших разборов полетов по каким-то спорным вопросам.

Для работы голосового приветствия необходимо записать файл в формате PCM Encoded, 16 Bits, at 8000Hz и поместить его в /var/lib/asterisk/sounds.

servis_avtomatizirovannoj_otpravki_faksov.txt · Последние изменения: 2013/11/18 16:11 (внешнее изменение)
GNU Free Documentation License 1.3
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0 Яндекс.Метрика