VoIP телефонія. Asterisk. Нестандартний підхід до всього. Частина 2

Продовжуємо нашу розповідь про модифікації движка для 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.37 USD і ви розмовляли 28 секунд, то вартість дзвінка становитиме 0.37 USD, а якщо ви розмовляли 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
Швидкість пошуку в півсекунди(тестова середа) не те щоб зовсім критична, але виглядає дивно. Тому для оптимізації пошуку ми винесли поле 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
  • Центр
Таким чином знаючи код телефону можна з великою ймовірністю дізнатися місце розташування об'єкта, винятком є стільникові телефонні номери, які були смигрированы з одного оператора на інший, а також сервіси надають послуги геонезависимых номерів.
Для російських номери на сайті россвязи, у вільному доступі, існує кілька таблиць описують номерну прив'язку за регіонами та федеральним округах. Приналежність стільникового номера до оператора можна уточнити на сайті цниис.
Для інших країн також можна знайти інформацію на сайті місцевих регуляторів.
Збір та уточнення інформації про використовувані префіксах справа дуже затратна по часу. Тому повних баз практично немає у вільному доступі. А ті що є не завжди містять потрібну інформацію. Але як і в більшості ситуацій є невеликий лайвхак.
Оператори 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
Aborche
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.