Продолжаем наш рассказ о модификации движка для VoIP оператора связи.
В первой части мы рассказали о начальной структуре базы данных и настройке Asterisk для обслуживания вызовов, с мониторингом состояния вызова. В этой части мы затронем такие вещи как тарификатор, LCR, биллинг и геолокация.
Тарификатор
Ни для кого не является секретом, что у различных операторов связи в зависимости от их географического расположения, довольно сильно отличается стоимость звонков в одни и те же места. Для того чтобы дешево звонить по определенному направлению необходимо подбирать оператора с минимальной ценой в нужном регионе. В зависимости от местности, в которой оператор связи оказывает свои услуги, тарификация вызова может отличаться довольно сильно. Данное отличие состоит в том, как оператор считает потраченное на разговор время. Большинство российских операторов связи тарифицируют звонки поминутно, однако подавляющее большинство VoIP операторов использует другие методы для определения стоимости звонка. Отдельного разговора заслуживают премиум сервисы, но об этом чуть позже.
Вот выдержка из тарифного плана оператора связи:
"Minimal Duration- 1 second"
"Billing increment- 1 second"
"USA -6/6"
"Mexico 60/60"
"Gambia 60/1"
"Tonga All (Prefix 676) - 60/60"
"Vanuatu All (Prefix 678)- 60/60 "
"Samoa (Prefix 685) - 60/60"
"Papua New Guinea (Prefix 675)- 60/60 "
"Nauru All (Prefix 674)- 60/60 "
Как мы видим, минимальное время разговора равно одной секунде, а стоимость разговора вычисляется из количества потраченных секунд (1/1), звонок в Соединённые Штаты Америки тарифицируется с шагом в 6 секунд(6/6), звонок в Мексику тарифицируется с шагом в 60 секунд, т.е. поминутно(60/60). Также может использоваться формула 60/1, что означает посекундную тарификацию звонка, но с полной оплатой первой минуты разговора. Например если минута разговора стоит 0.37USD и вы разговаривали 28 секунд, то стоимость вашего звонка составит 0.37USD, а если вы разговаривали 76 секунд, то стоимость вашего звонка составит (0.37/60)*76USD.
Оператор фиксированной, мобильной или VoIP связи, предоставляя вам поминутную тарификацию в регионы с посекундной оплатой разговора, на данной разнице зарабатывает себе на хлеб. Маржа конечно небольшая, но совместно с повышением тарифа для конечного пользователя, получается как в анекдоте "двадцать старушек — рубль". И совсем немногие операторы позволяют себе продавать посекундную тарификацию конечному пользователю.
Тарифные сетки операторов основаны на префиксной адресации вызова. Префикс обычно представляет собой несколько первых цифр телефона в международном стандарте. Это означает, что у каждого конкретного оператора звонок по определенному направлению может отличаться в разы. Это происходит как из-за способа доставки звонка до вызываемого абонента, так и из-за внедрения в номерную ёмкость локальных операторов связи, так называемых "премиум" или "специальных" сервисов. "Премиум" сервисами обычно называют справочные(где купить, как проехать и т.д.), либо развлекательные сервисы(гороскопы, магазин на диване, секс по телефону и т.д.), доступ к которым предоставляется на платной основе по повышенным тарифам. Если оператор связи не контролирует исходящие звонки из своих систем или несвоевременно обновляет тарифные планы своих партнёров, то известны случаи гигантских долгов из-за случайного разрешения звонков на "премиум" сервисы без контроля личного счёта клиента.
Как это происходит в реальной жизни?
Переделывая "движок" оператора мы столкнулись с тем, что старый "движок" не отслеживал направления звонков и тарифицировал клиента "по факту", с ограничением времени звонка в 3600 секунд. Т.е. клиент мог позвонить на телефон "премиум" сервиса и "завесить" сессию на 1 час. При стоимости звонка в 5 долларов за минуту, оператор попадал на 300 долларов в час. А так как количество одновременных вызовов было не ограничено, то потери могли составлять бОльшие суммы. В связи с тем, что операторы связи только выходящие на рынок пытаются привлечь новых клиентов, они дают "тестовый" доступ новым пользователям на определённую виртуальную сумму. Пользователь совершает звонок в нужное ему место, оценивает качество связи, и если всё хорошо, то начинает пополнять свой "личный" кошелёк у этого оператора связи. Данным типом доступа пользуются фродеры, которые находятся в сговоре с хозяевами "премиум" сервиса. Фродер используя бреши в системе тарификации операторов, совершает несколько звонков на платные сервисы, тем самым выставляя оператора на деньги. При этом стоимость звонка фродера на платный сервис практически равна нулю, а прибыль может достигать огромных сумм. Оператор связи обнаруживает проблему либо на утро, либо после получения оповещения о исчерпании денег на своём счету. Оспорить совершенный звонок, который прошёл через цепочку операторов и достиг "премиум" сервиса, практически невозможно, т.к. оплата за сессию идёт по всей цепочке операторов.
Рассмотрим примеры "премиум" сервисов и как они выглядят в тарифной сетке.
prefix | pricerub | note | tarif_name |
---|---|---|---|
37122 | 1,001 | LATVIA Mobile | VOICETRADEC |
371227 | 0,8439 | LATVIA Other 4, Latvia VAS IPRS | VOICETRADEC |
3712270 | 34,321 | LATVIA Latvia-Mobile, Latvia Premium, Latvia VAS IPRS | VOICETRADEC |
3712272 | 1,001 | LATVIA LATVIA NGN, Latvia mobile Bite, Latvia VAS IPRS | VOICETRADEC |
3712274 | 32,812 | LATVIA LATVIA NGN, Latvia VAS IPRS | VOICETRADEC |
3712277 | 1,0226 | Latvia Mobile — Master, Latvia mobile Master Telecom, LATVIA Radiocoms Mobile, Латвия моб.Master Telecom | VOICETRADEC |
3712278 | 37,181 | Latvia Premium, LATVIA Radiocoms Mobile, Latvia Services ECO Networks, Latvia VAS IPRS, Латвия моб.ECO Solutions | VOICETRADEC |
3712279 | 37,181 | LATVIA Mobile, Latvia Premium, Latvia Services ECO Networks, Latvia VAS IPRS, Латвия моб.ECO Solutions | VOICETRADEC |
Если внимательно посмотреть на таблицу, то мы увидим, что номер 37122705678 попадает под три тарифа 37122,371227,3712270. Если некорректно обработать начало номера или вовремя не обновить тарифный план, то вместо ожидаемого звонка за рубль или 84 копейки, мы получим звонок с ценой больше 30 рублей за минуту. Именно данной лазейкой и пользуются злоумышленники. Поэтому для исключения таких вариантов развития событий, мы разделили все префиксы на 14 категорий.
id | category | description |
---|---|---|
1 | FIXED | Стационарные номера телефонов |
2 | PREMIUM | Премиум сервисы(гороскопы, секс услуги, платная справочная информация и т.д.) |
3 | OffNet | Звонки из роуминга |
4 | OnNet | Звонки внутри сети |
5 | OTHER | Прочие типы звонков |
6 | MOBILE | Мобильные номера телефонов |
7 | PAGER | Сервисы коротких сообщений |
8 | TOLLFREE | Сервисы разговоров, где за вызов платит вызываемый номер |
9 | VOIP | Интернет телефония |
10 | SATELLITE | Спутниковая связь |
11 | NETWORK | Местные операторы связи |
12 | PERSONAL | Персональные "красивые" номера не привязанные к географическому региону |
13 | UNKNOWN | Неизвестные телефонные коды |
14 | UNUSED | Неиспользуемые телефонные коды |
А когда запустили связку в работу, то просто ограничили тестовые звонки на часть спорных категорий. Если пользователь вносил свои деньги на счёт, то заблокированные категории автоматически открывались. Это снизило уровень фрода практически на 99%. Оставшийся процент подвисал в воздухе из-за временного лага в обновлении тарифов партнёров. При обновлении тарифной сетки те префиксы, которые не были определены в таблице, "выпадали" из общего списка и после анализа оператором, привязывались к нужной категории.
LCR(Least Cost Routing) — «маршрутизация по критерию наименьшей стоимости»
В связи с тем, что система которую мы проектировали, подразумевала подключение к большому количеству операторов, возник вопрос выбора маршрутов с наименьшей стоимостью минуты разговора.
Тарифная сетка у нас уже была и в ней находилось около 700.000 записей.
Понятное дело, что поиск по 700.000 записей дело накладное, а с увеличением количества операторов, количество записей бы заметно подросло. Поэтому мы искали множество путей ускорения поиска маршрута в тарифной сетке.
Внимание! номер 79031210011 взят для примера и моим не является. Цены на разговоры в таблицах указаны от апреля 2016 года(последний дамп базы)
Основная проблема поиска заключалась в том, что мы должны найти более длинный номер среди более коротких префиксов. А после этого найти наиболее длинный префикс для каждого оператора из результатов поиска.И для этого есть два пути:
#Первый
select * from rates r where '79031210011' like CONCAT(r.prefix,'%')
#Второй
select * from rates r where INSTR('79031210011',r.prefix) = 1
#Первый чуть быстрее, второй чуть медленнее
select prefix,pricerub,note,tarif_id from rates r where '79031210011' like CONCAT(r.prefix,'%');
/* Затронуто строк: 0 Найденные строки: 15 Предупреждения: 0 Длительность 1 запрос: 0,421 sec. */
select prefix,pricerub,note,tarif_id from rates r where INSTR('79031210011',r.prefix) = 1;
/* Затронуто строк: 0 Найденные строки: 15 Предупреждения: 0 Длительность 1 запрос: 0,453 sec. */
Ответ выглядел следующим образом:
prefix | pricerub | note | tarif_id |
---|---|---|---|
7 | 11,72 | Неопознанные коды | 11 |
79 | 1,495 | РОССИЯ МОБИЛЬНЫЕ | 3 |
79 | 1,15 | Россия (mob) — регион | 11 |
7903 | 1,15 | Россия (mob) — Билайн | 11 |
79031 | 1,15 | Москва (mob) — Билайн | 11 |
7 | 0,715 | RUSSIAN FEDERATION Fixed | 5 |
7903 | 3,9326 | RUSSIAN FEDERATION Mobile | 5 |
7 | 0,742 | RUSSIAN FEDERATION Fixed | 6 |
7903 | 4,2294 | RUSSIAN FEDERATION Mobile | 6 |
7 | 1,6729 | Russia Fixed | 9 |
79 | 7,9731 | Russia Mobile | 9 |
7903 | 5,6999 | Russia Mobile — Beeline | 9 |
7 | 0,8027 | Russia Fixed | 10 |
79 | 1,457 | Russia Mobile | 10 |
7903 | 3,393 | Russia Mobile — Beeline | 10 |
Cкорость поиска в полсекунды(тестовая среда) не то чтобы совсем критична, но выглядит странно. Поэтому для оптимизации поиска мы вынесли поле prefix в отдельную таблицу, сделав его ключевым для таблицы rates
select * from rates_prefix r where '79031210011' like CONCAT(r.prefix,'%');
/* Затронуто строк: 0 Найденные строки: 4 Предупреждения: 0 Длительность 1 запрос: 0,172 sec. */
Как мы видим, скорость поиска выросла примерно в три раза. Что в принципе не так уж и плохо. Далее полученная таблица префиксов "пристыковывается" к таблице тарифов операторов, и из результирующей таблицы убираются лишние "короткие" префиксы. Там же пристыковывается таблица операторов и на выходе мы имеем полноценный список маршрутов с ценами и префиксами, который привязан к оператору связи.
call usp_asteriskfastpathtest('79031210011','test_user',0);
/* Затронуто строк: 0 Найденные строки: 17 Предупреждения: 0 Длительность 1 запрос: 0,140 sec. */
rate_prefix | dial_string | note | rate_pricerub | provider_id |
---|---|---|---|---|
79031 | SIP/westcall/79031210011 | Москва (mob) — Билайн | 1,15 | 7 |
7903 | SIP/sip.voicebuy.com/999279031210011 | RUSSIAN FEDERATION Mobile | 3,9326 | 11 |
7903 | SIP/sbc.voxbeam.com/001110179031210011 | Russia Mobile — Beeline | 5,6999 | 8 |
Ну или например список маршрутов до отеля Crystal Hotel в Америке с номером 13606632262
rate_prefix | dial_string | note | rate_pricerub | provider_id |
---|---|---|---|---|
1360 | SIP/sbc.voxbeam.com/001110313606632262 | United States — OnNet — WA — 360 | 0,3305 | 8 |
1360 | SIP/sip.voicebuy.com/999113606632262 | UNITED STATES OF AMERICA Washington | 0,3474 | 11 |
1360 | SIP/91.190.132.39/010#13606632262 | USA Other | 0,4047 | 13 |
Естественно, при формировании списка дозвона, совместно с сортировкой префиксов в тарифной сетке используется довольно много дополнительных условий. Это и дата начала/конца действия тарифа, поддержка CLI, ручные блокировки и прочие. Финальная таблица перед занесением в базу дополнительно обрабатывается на задаваемое ограничение максимальной стоимости звонка. Нет смысла разрешать звонки за 300 рублей для пользователя у которого на счету всего 100 рублей.
Всё это накладывает свои издержки на производительность. На боевой системе мы получали примерно 50ms на запрос.
Биллинг
Как мы все понимаем, не бывает систем предоставления услуг без подсчёта стоимости предоставленных услуг. Мы долго думали, как наиболее оптимально контролировать состояние кошелька пользователя и нашли на наш взгляд компромиссное решение.
В конце первой части я описал настройку сервера Asterisk в плане добавления сервисных функций и функций контроля состояния канала. Эти же функции позволяют чётко отслеживать состояние вызова для клиента.
Как можно увидеть в нижеследующей таблице
у нас всегда есть информация о текущем тарифе оператора, валюте оператора, тарифе клиента, направлении и прочему. Что в свою очередь превращается в следующую таблицу
И именно dial_guid возвращается приложением make_a_route.py в контекст [make_a_call], а поле step используется для уточнения текущей итерации.
Когда Asterisk начинает подготавливать канал связи для соединения абонентов, он вызывает приложение create_channel_record.py, которое формирует в таблице CDR пустую запись, в которой нет никакой информации кроме времени создания канала, идентификатора пользователя и dial_guid+step. Когда вызываемый пользователь поднимает трубку, вызывается приложение predial.py, которое заполняет поля таблицы ответственные за время поднятия трубки и тарификацию вызова. В случае корректного завершения разговора или возникновения ошибки, вызывается приложение hangup.py, которое "закрывает" CDR запись в базе, заполняя поле со временем окончания разговора. Таким образом получается, что ошибочные звонки, которые по какой-то причине не были совершены, не попадают в биллинг пользователя, но остаются в логах системы. На таблицу с временной CDR информацией установлен триггер, который ожидает изменений строк, где время поднятия трубки и время окончания разговора не равны нулю. Как только данный триггер видит описанное выше условие, он переносит данные из временной CDR таблицы в основную и записывает клиенту на счёт израсходованную сумму.
К слову говоря, есть еще одна таблица в которой хранятся названия каналов обслуживающих текущие вызовы и привязанные к dial_guid. В связи с тем, что мы видим в realtime все текущие разговоры в базе данных, в базу данных был введен триггер срабатывающий раз в 5 секунд и соотносящий текущие осуществляемые разговоры с тарифами на них и остатком средств на счёте клиента.
Как только денежных средств на счёте клиента остаётся менее чем на 1 минуту разговора, триггер помещает в специальную таблицу номер канала, который инициировал вызов. Служебный appication server, находящийся на каждом из Asterisk серверов, мониторит данную таблицу. Как только он видит там строку адресованную в его адрес, вызывается приложение Originate с перенаправлением на контекст с фразой "недостаточно денежных средств" и разговор завершается. После завершения разговора, срабатывают штатные процедуры изменяющие баланс клиента. Данная схема прекрасна тем, что отслеживает все осуществляемые с аккаунта клиента разговоры на всех серверах.
Мониторинг разговоров выглядит примерно так.
Мультивалютный пересчёт
По сути описанная выше технология позволяет строить мультивалютный биллинг в пределах одной системы. К слову о валюте. Так как стоимость звонков через зарубежных операторов считается в долларах или евро, необходимо определить в какой валюте работает клиент. А в связи с тем, что курс валюты меняется каждый день, необходимо обеспечить пересчёт валют.
Это делает простейший скрипт на Python
# -*- coding: utf-8 -*-
import urllib
from sqlconfig import *
import mysql.connector
import json
# Init mysql connection
cnx = mysql.connector.connect(**config)
cursor = cnx.cursor()
cursor.execute('SET AUTOCOMMIT=1;')
cursor.execute('SET collation_connection=\'utf8mb4_unicode_ci\';')
currency_pairs = [ ('EUR','USD'),('EUR','RUB'),('EUR','UAH'),('EUR','KZT'),('RUB','USD'),('RUB','UAH'),('RUB','KZT'),('USD','UAH'),('USD','KZT') ]
for base in currency_pairs:
(fromcur,tocur) = base
root_url = 'http://www.bloomberg.com/markets/api/security/currency/cross-rates/%s,%s'%(fromcur,tocur)
f = urllib.urlopen(root_url)
myjson = json.loads(f.read())
pair = myjson[u'data']
for fromcur in pair:
for topair in pair[fromcur].items():
(tocur,crossrate) = topair
cursor.execute('INSERT INTO currency_cross (getcrosstime,from_currency_id,to_currency_id,crossrate) VALUES (now(),(select id from currency where iso="%s"),(select id from currency where iso="%s"),"%s")'%(fromcur,tocur,crossrate))
print fromcur,tocur,crossrate
cnx.commit()
cursor.close()
cnx.close()
Он формирует таблицу кросскурсов на каждый день
From | To | ExchRate |
---|---|---|
USD | EUR | 0.9423 |
EUR | USD | 1.0612 |
RUB | EUR | 0.01581 |
EUR | RUB | 63.2363 |
UAH | EUR | 0.03409 |
EUR | UAH | 29.3352 |
KZT | EUR | 0.002831 |
EUR | KZT | 353.1992 |
RUB | USD | 0.01678 |
USD | RUB | 59.5889 |
RUB | UAH | 0.4639 |
UAH | RUB | 2.1556 |
RUB | KZT | 5.5854 |
KZT | RUB | 0.179 |
UAH | USD | 0.03618 |
USD | UAH | 27.6434 |
USD | KZT | 332.83 |
KZT | USD | 0.003005 |
Таким образом, в зависимости от основной валюты, в которой производится расчёт, мы можем пересчитывать средства клиента и приводить тарифы к нужной валюте.
Геолокация звонков
Геолокация довольно важная часть различных сервисов, которые общаются с клиентами по всему миру. Всегда приятно на телефоне видеть номер звонящего совпадающего с твоим местоположением. Как это работает ?
Внутренний регулирующий орган в каждой стране дополнительно к международному плану нумерации, а также префиксу конкретной страны, делит свои территории на округа, области, районы, города и населенные пункты, присваивая каждому из них дополнительную цифру в префиксе набора номера.
Крупные города (города миллионники) такие как Москва, Санкт-Петербург и прочие имеют семизначный план нумерации, города регионального значения — шестизначный, города областного значения — пятизначные и т.д.
Внутри номерного плана Российской федерации происходит деление на:
- Федеральный округ
- Город федерального значения
- Город
- Область
- Район
- посёлок, село, поселение и т.д.
Внутри номерного плана Соединённых Штатов Америки происходит деление на:
- Area
- State
- District
- County
- City
Таким образом зная код телефона можно с большой вероятностью узнать местоположение объекта, исключением являются сотовые телефонные номера, которые были смигрированы с одного оператора на другого, а также сервисы предоставляющие услуги геонезависимых номеров.
Для российских номера на сайте россвязи, в свободном доступе, существует несколько таблиц описывающих номерную привязку по регионам и федеральным округам. Принадлежность сотового номера к оператору можно уточнить на сайте цниис.
Для других стран также можно найти информацию на сайте местных регуляторов.
Сбор и уточнение информации об используемых префиксах дело очень затратное по времени. Поэтому полных баз практически нет в свободном доступе. А те которые есть не всегда содержат нужную информацию. Но как и в большинстве ситуаций есть небольшой лайвхак.
Операторы IP телефонии предоставляющие свои тарифы, обычно включают в виде структурированного описания, местоположение которое обслуживает префикс.
Не будем ходить далеко и возьмём первые строки из операторского тарифного плана:
"prefix","comment","price","connect_cost","increment","custom","created_at",
"9375","AFGHANISTAN - CDMA","0.388125","0.0000","60","0","2015-10-11 23:21:51",
"9340","AFGHANISTAN - HERAT","0.388125","0.0000","60","0","2015-10-11 23:21:51",
"9360","AFGHANISTAN - JALALABAD","0.388125","0.0000","60","0","2015-10-11 23:21:51",
"9320","AFGHANISTAN - KABUL","0.388125","0.0000","60","0","2015-10-11 23:21:51",
"9330","AFGHANISTAN - KANDAHAR","0.388125","0.0000","60","0","2015-10-11 23:21:51",
"9350","AFGHANISTAN - MAZAR-E-SHARIF","0.388125","0.0000","60","0","2015-10-11 23:21:51",
"937","AFGHANISTAN - MOBILE","0.388125","0.0000","60","0","2015-10-11 23:21:51",
"9377","AFGHANISTAN - MOBILE - AREEBA","0.32751","0.0000","60","0","2015-10-11 23:21:51",
"9370","AFGHANISTAN - MOBILE - AWCC","0.32751","0.0000","60","0","2015-10-11 23:21:51",
"9378","AFGHANISTAN - MOBILE - OTHER CARRIERS","0.32751","0.0000","60","0","2015-10-11 23:21:51",
"9379","AFGHANISTAN - MOBILE - ROSHAN","0.310365","0.0000","60","0","2015-10-11 23:21:51",
"93","AFGHANISTAN - PROPER","0.388125","0.0000","60","0","2015-10-11 23:21:51",
"35568","ALBANIA - MOBILE - AMC","0.456165","0.0000","60","0","2015-10-11 23:21:51",
"35567","ALBANIA - MOBILE - EAGLE","0.452925","0.0000","60","0","2015-10-11 23:21:51",
"35569","ALBANIA - MOBILE - VODAFONE","0.47007","0.0000","60","0","2015-10-11 23:21:51",
"355","ALBANIA - PROPER","0.08046","0.0000","60","0","2015-10-11 23:21:51",
"3554","ALBANIA - TIRANE","0.08046","0.0000","60","0","2015-10-11 23:21:51",
"35541","ALBANIA - TIRANE","0.08046","0.0000","60","0","2015-10-11 23:21:51",
"35542","ALBANIA - TIRANE","0.03861","0.0000","60","0","2015-10-11 23:21:51",
"35543","ALBANIA - TIRANE","0.08046","0.0000","60","0","2015-10-11 23:21:51",
"35544","ALBANIA - TIRANE","0.08046","0.0000","60","0","2015-10-11 23:21:51",
"35545","ALBANIA - TIRANE","0.08046","0.0000","60","0","2015-10-11 23:21:51",
"35546","ALBANIA - TIRANE","0.08046","0.0000","60","0","2015-10-11 23:21:51",
"3554249","ALBANIA 0 OLO GROUP","0.04401","0.0000","60","0","2015-10-11 23:21:51",
"7997","RUSSIA (MOBILE)","0.07938","0.0000","60","0","2015-10-11 23:21:51",
"78182","RUSSIA - ARKHANGELSK","0.09558","0.0000","60","0","2015-10-11 23:21:51",
"73512","RUSSIA - CHELYABINSK","0.055755","0.0000","60","0","2015-10-11 23:21:51",
"74932","RUSSIA - IVANOVO","0.055755","0.0000","60","0","2015-10-11 23:21:51",
"73412","RUSSIA - IZHEVSK","0.055755","0.0000","60","0","2015-10-11 23:21:51",
"78432","RUSSIA - KAZAN","0.052515","0.0000","60","0","2015-10-11 23:21:51",
"73912","RUSSIA - KRASNOYARSK","0.052515","0.0000","60","0","2015-10-11 23:21:51",
"7813","RUSSIA - LENINGRAD REGION","0.055755","0.0000","60","0","2015-10-11 23:21:51",
"79","RUSSIA - MOBILE","0.07938","0.0000","60","0","2015-10-11 23:21:51",
"7964","RUSSIA - MOBILE - BEELINE","0.13311","0.0000","60","0","2015-10-11 23:21:51",
"7965","RUSSIA - MOBILE - BEELINE","0.13311","0.0000","60","0","2015-10-11 23:21:51",
"792","RUSSIA - MOBILE - MEGAFON","0.07938","0.0000","60","0","2015-10-11 23:21:51",
"791","RUSSIA - MOBILE - OTHER CARRIERS","0.07938","0.0000","60","0","2015-10-11 23:21:51",
1531,US,"United States - OnNet - NE - 531",0.008100,6,6,0.008100,Unchanged,USD,11-Apr-2016,22:00:00,18-Apr-2016,22:00:00
1603,US,"United States - OnNet - NH - 603",0.008100,6,6,0.008100,Unchanged,USD,11-Apr-2016,22:00:00,18-Apr-2016,22:00:00
1201,US,"United States - OnNet - NJ - 201",0.008100,6,6,0.008100,Unchanged,USD,11-Apr-2016,22:00:00,18-Apr-2016,22:00:00
Как можно увидеть из этих данных, существует привязка кода к стране и типу связи.
- PROPER — Основной код страны
- FIXED — фиксированная связь
- MOBILE — мобильный оператор связи. обычно если известно его имя, то оно идёт следом
- CITY — если код относится целиком к городу, то пишется его имя
- OLO — аббревиатура используемая для обозначения локальных операторов(OTHER LOCAL OPERATOR)
- OTHER — прочие виды связи
- IPRS — индивидуальные премиум сервисы
- PREMIUM — премиум услуги
и т.д.
Некоторые операторы включают в описание страну, тип связи, штат и код штата. Что в свою очередь также помогает в навигации. Поэтому можно написать простейший парсер тарифов и довольно быстро свести, через объединение описаний для префиксов, все эти данные в единую таблицу.
Вот наверное в принципе и всё, что можно описать полезного из проекта, который мы делали. От получения первой информации до запуска в тестовую эксплуатацию прошло примерно 3 месяца. Основное время было потрачено на обработку различных данных и отладку механизмов внутри базы данных. Например полный дамп сайта https://sanstv.ru/codes/, с сохранением его работоспособности для других пользователей, занял примерно четверо суток, а обработка данных около двух недель. Тоже самое с российскими префиксами и прочей служебной информацией. По сути проект писался сначала двумя людьми, потом присоединилось еще 2 человека. Основные проблемы проекта заключались в отсутствии описанного ТЗ и как в Пьеса. Технический долг изменением задач на лету. По началу даже показалось, что статья писана с этого проекта. Надеюсь описанные здесь методики и подходы будут полезны Вам в Ваших проектах.
Спасибо за потраченное на прочтение статей время.
© Aborche 2017