From b7ae18f2d29aea6d18c20d12e7950e978f2c7c24 Mon Sep 17 00:00:00 2001 From: Dmitry Novikov Date: Thu, 18 Apr 2019 17:58:36 +0300 Subject: [PATCH] dic --- docs/dev.md | 123 +++++++++++++++--------------------------------- docs/dhcp.md | 6 +-- docs/map.md | 6 ++- static/js/my.js | 51 -------------------- 4 files changed, 44 insertions(+), 142 deletions(-) diff --git a/docs/dev.md b/docs/dev.md index 45d0ca0..4a7415d 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -8,7 +8,7 @@ ## Добавление поддерживаемого устройства (Свича) -Для того чтоб добавить новый тип устройства с которым потом сможет работать биллинг нужно открыть файл *devapp/dev_types.py* +Для того чтобы добавить новый тип устройства с которым потом сможет работать биллинг, нужно открыть файл *devapp/dev_types.py* и переопределить 2 интерфейса. Первый это *BasePort* для порта свича, а второй *DevBase* для самого свича соответственно. Разберём этот процесс на примере готовой реализации для Eltex. @@ -36,12 +36,13 @@ class EltexPort(BasePort): 1 ) ``` -Тут в инициилизации мы передаём все базовые параметры базовому конструктору, и дополнительный аргумент snmpWorker -для работы по SNMP. *snmpWorker* это объект реализованного интерфейса SNMPBaseWorker, далее я опишу где мы его реализуем. +Тут в иницииализации мы передаём все базовые параметры базовому конструктору, и дополнительный аргумент *snmpWorker* +для работы по SNMP. *snmpWorker* это объект реализованного интерфейса *SNMPBaseWorker*, далее я опишу где мы его реализуем. Для порта надо переопределить 2 метода: *disable* и *enable* понятно для чего, чтоб включать и отключать порт. Шаблон реализации можно даже не менять, просто укажите вместо строки .1.3.6.1.2.1.2.2.1.7 нужный SNMP OID для включения порта. К этой строке будет добавляться номер порта который нужно включить. +Или, все же, переопределите этот метод если вы хотите, например, реализовать включение/выключение по *telnet* или *ssh*. Для отключения так-же по аналогии. Теперь реализация для свича: @@ -85,31 +86,32 @@ class EltexSwitch(DLinkDevice): """ ``` Свойство **@description** Просто отображает человекопонятное название вашего устройства в биллинге. -Заметьте что строка на английском и заключена в процедуру **_** (это ugettext_lazy, см. в импорте вверху файла), +Заметьте, что строка на английском и заключена в процедуру **_** (это ugettext_lazy, см. в импорте вверху файла), это локализация для текущего языка. Про локализацию можно почитать в соответствующем разделе документации *Django* -[django translation](https://docs.djangoproject.com/en/1.11/topics/i18n/translation/). +[django translation](https://docs.djangoproject.com/en/2.1/topics/i18n/translation/). Метод **@get_ports** чаще всего редко изменяется по алгоритму, так что вам, в большенстве случаев, достаточно добавить нужные SNMP OID в соответствующие места процедуры. Но вы вольны реализовать ваш метод получения портов как вам угодно, главное чтоб возвращался список объектов определённого выше класса порта для этого свича. -В данном случае возвращается список объектов *EltexPort*. На самом деле не обязательно список, можете вернуть кортеж -или генератор, что-то итериуемое. +В данном случае возвращается генератор объектов *EltexPort*. На самом деле не обязательно генератор, можете вернуть кортеж +или список, что-то итерируемое. Метод **@get_device_name** получает по SNMP имя устройства, просто укажите в вашей реализации нужный OID. -Метод **@uptime**, понятно что возвращает, укажите нужный OID. Вернётся тип *RuTimedelta*, это переопределённый тип **timedelta**, я его реализовал -для локализации временного промежутка на русский. +Метод **@uptime**, понятно что возвращает, укажите нужный OID. Вернётся тип *RuTimedelta*, это переопределённый тип +**timedelta**, я его реализовал для локализации временного промежутка на русский. Свойство **@has_attachable_to_subscriber** возвращает правду если это устройство можно привязать к абоненту. Например у Dlink стоит True потому что Dlink стоит во многих местах на доступе, и его порты принадлежат абонентам при авторизации. -Свойство **@is_use_device_port** используется в DHCP чтоб понять что мы используем для привязки к абоненту всё устройство или -только порт устройства. Например, если у устройства только 1 порт абонента (PON ONU), и мы привязываем этого абонента ко всему устройству -а не к порту, то нужно указать False, На обычных свичах где мы авторизуем абонента на порту возвращаем True. +Свойство **@is_use_device_port** используется в **DHCP** чтоб понять что мы используем для привязки к абоненту всё +устройство или только порт устройства. Например, если у устройства только 1 порт абонента (PON ONU), и мы привязываем +этого абонента ко всему устройству а не к порту, то нужно указать False, На обычных свичах где мы авторизуем абонента +на порту возвращаем True. -Реализация SNMPBaseWorker по сути не нужна, класс абстрактных методов не имеет. -Потому когда наследуемся от *DevBase* то в базовые классы добавим и SNMPBaseWorker, как это сделано в *DLinkDevice*: +Реализация **SNMPBaseWorker** по сути не нужна, класс абстрактных методов не имеет. +Потому, когда наследуемся от *DevBase* то в базовые классы добавим и SNMPBaseWorker, как это сделано в *DLinkDevice*: ```python class DLinkDevice(DevBase, SNMPBaseWorker): @@ -122,11 +124,8 @@ class DLinkDevice(DevBase, SNMPBaseWorker): Вы, наверное, обратили внимание, что *EltexSwitch* наследован от *DLinkDevice*, это потому что некоторые методы идентичны, и реализация для обоих свичей похожа. ->П.С. Не изучайте как пример реализацию для PON, она, как по мне, костыльна. Это связано с тем что PON сильно отличается от ->принципа работы обычного свича, и чтоб подружить свичи и PON был реализован такой костыль. - ## Реализация своего NAS -Сейчас биллинг работает с Mikrotik в роли устройства для доступа абонентов в интернет. +Сейчас биллинг работает с несколькими Mikrotik в роли устройства для доступа абонентов в интернет. Как можно реализовать такой-же для вашего роутера, например на GNU/Linux. Создадим файл *gw_app/nas_managers/mod_linux.py* и реализуем потомка для интерфейса *BaseTransmitter*. @@ -209,23 +208,22 @@ class LinuxTransmitter(BaseTransmitter): ``` Для того чтоб биллинг знал о вашем классе надо указать его в *gw_app/nas_managers/\_\_init\_\_.py*. -Замените ->from .mod_mikrotik import MikrotikTransmitter - -На это ->from .mod_mikrotik import LinuxTransmitter - -И укажите ваш класс -> Transmitter = MikrotikTransmitter +Добавьте в кортеж *NAS_TYPES* ещё один кортеж из двух элементов, в котором первый будет код реализации в БД, +максимум 4 символа. А второй будет классом вашей реализации. Получится примерно такое содержимое: - ```python -from .mod_mikrotik import LinuxTransmitter -from .core import NasFailedResult, NasNetworkError -from .structs import TariffStruct, AbonStruct - -Transmitter = LinuxTransmitter +from gw_app.nas_managers.mod_mikrotik import MikrotikTransmitter +from gw_app.nas_managers.mod_linux import LinuxTransmitter +from gw_app.nas_managers.core import NasNetworkError, NasFailedResult +from gw_app.nas_managers.structs import SubnetQueue + +# Указываем какие реализации шлюзов у нас есть, это будет использоваться в +# web интерфейсе +NAS_TYPES = ( + ('mktk', MikrotikTransmitter), + ('linx', NasNetworkError), +) ``` Для примера, как вы наверное уже догадались, можно посмотреть реализацию для Mikrotik в файле *gw_app/nas_managers/mod_mikrotik.py* @@ -237,11 +235,7 @@ NasNetworkError, как понятно из названия, вызываетс Кстати, не все методы обязательно реализовывать, некоторые из них зарезервированы на будущие цели, в комментариях к их прототипам в интерфейсе *BaseTransmitter* это сказано. Поэтому просто переопределите эти зарезервированные методы как -пустые, например метод *add_tariff_range* нигде в биллинге пока не вызывается. так что можно определить его пустым. -```python -def add_tariff_range(self, tariff_list): - pass -``` +пустые, я имею ввиду *pass* в реализации. ## Отправляем оповещения @@ -264,57 +258,14 @@ send_notify(msg_text='Text message',account=employee_profile, tag='apptag') с помощью тега *msgapp*, и вы не спутаете ваши сообщения с сообщениями из модуля, например, задач который использует тэг *taskap*. -#### Получение оповещения -```python -from chatbot.models import MessageQueue - -msg = MessageQueue.objects.pop(user=employee_profile, tag='apptag') -``` - -Метод **pop** плучает первое сообщение и удаляет его. - - -#### Отображаем оповещение в браузере - -Чтоб отобразить **WebNotification** добавте в файле скриптов *static/js/my.js* строку вида: - -```javascript -$(document).notifys({news_url: '/url/to/your_view', check_interval: 60}); -``` -Тут *news_url* это путь к вашему представления которое возвращает новые оповещения, а *check_interval* - это интервал обращения к вашему представлению. - - -Представление для Web оповещений выглядит примерно так: -```python -@login_required -@only_admins -def check_news(request): - msg = MessageQueue.objects.pop(user=request.user, tag='apptag') - if msg is not None: - r = { - 'exist': True, - 'content': msg, - 'title': 'Message title' - } - else: - r = {'exist': False} - return HttpResponse(dumps(r)) -``` - -Убедитесь что вашему представлению не будет доступа от абонентов, об этом позаботится декоратор *only_admins* из *djing.lib*. - -После получения сообщения надо вернуть словарь с параметрами: - -*exist* - Логическое значение, обозначает есть или нет информации в ответе. Если *exist* == True тогда возвращае ещё *content* и *title*. - -*content* - Соответственно содержимое оповещения. - -*title* - Заголовок оповещения. - - ### Свой сервис для API Сервисы общаются с биллингом через http запросы и могут быть самыми разными, но все они должны уметь одинаково -расчитывать хеш сумму для проведения транзакци, иначе web сервер биллинга просто вернёт 403. +расчитывать хеш сумму для проведения транзакци, иначе web сервер биллинга просто вернёт 403. Код расчёта хеш +суммы находится в *djing/lib/__init__.py* в функции *check_sign* и *calc_hash*, они рядом, там увидите. И +используются они декоратором *hash_auth_view* в *djing/lib/decorators.py* и примесью(Mixin) *HashAuthView* в +файле *djing/global_base_views.py*. + +Смысл в том, чтобы ### Дополнительная инфа в устройствах diff --git a/docs/dhcp.md b/docs/dhcp.md index b9ca933..cec8dc3 100644 --- a/docs/dhcp.md +++ b/docs/dhcp.md @@ -1,7 +1,7 @@ ## ISC-DHCP Сервер, взаимодействие с биллингом. -Вобщих чертах взаимодействие происходит с помощью скрипта **dhcp_lever.py** -в корне проекта. Запущенный DHCP сервер, при возникновении событий запускает -этот сценарий , а тот говорит биллингу подробнее что произошло. +В общих чертах взаимодействие происходит с помощью скрипта **dhcp_lever.py**,который хранится в корне проекта, +или [dhcp_lever](https://github.com/nerosketch/dhcp_lever), который написан на C++.. Запущенный DHCP сервер, +при возникновении событий запускает этот сценарий , а тот говорит биллингу о случившемся. При событии *expiry* или *release* биллингу нужно освободить ip, а при *commit* нужно назначить динамическую аренду ip для учётной записи абонента в биллинге. diff --git a/docs/map.md b/docs/map.md index 1ef80dc..be0cf01 100644 --- a/docs/map.md +++ b/docs/map.md @@ -1,7 +1,9 @@ ### Маркеры -Карта была раелизована на основе Яндекс Карт, на момент создание модуля я не знал о том, что в правилах Яндекса -указано что карты нельзя использовать в закрытых сайтах, потому карта +Карта была раелизована на основе Яндекс Карт, на момент создания модуля я не знал о том, что в правилах Яндекса +указано что карты нельзя использовать в закрытых сайтах, потому модуль не будет работать долго. В планах +реализация модуля с использованием не географической карты, а логической древовидной структуры сети. Далее описание +существующего модуля на основе яндекс карт, на случай усли у вас есть коммерческий доступ я яндекс картам. На карте есть 5 видов маркеров, хранятся файлы этих маркеров в папке *djing/static/img/gmarkers*. Каждый из них отличается цветом и иконкой в центре. Так зелёный маркер с значком HDD в diff --git a/static/js/my.js b/static/js/my.js index e41306b..c9e36a0 100644 --- a/static/js/my.js +++ b/static/js/my.js @@ -170,57 +170,6 @@ $(document).ajaxError(function (ev, jqXHR, ajaxSettings, thrownError) { })(jQuery); -(function($){ - $.fn.notifys = function(opt){ - var settings = $.extend({ - news_url: null, - check_interval: 60 - }, opt); - - var notifShow = function(title, content){ - if(!settings.news_url) return; - var perm = Notification.permission.toLowerCase(); - if(perm === "granted"){ - curnotify = new Notification(title, { - tag: 'djing-notify', - body: content, - icon: '/static/img/noticon.png'} - ); - }else if(perm === "default"){ - Notification.requestPermission(on_ask_perm); - } - }; - - var on_ask_perm = function(r){ - console.log("Thanks for letting notify you"); - }; - - var check_news = function(){ - var perm = Notification.permission.toLowerCase(); - if("granted" === perm && settings.news_url){ - $.getJSON(settings.news_url, function(r){ - if(r.auth){ - if(r.exist){ - notifShow(r.title, r.content); - } - }else{ - window.location.href = '/'; - } - }); - } - }; - - if(settings.news_url){ - // once per minute check news - var tiid = setInterval(check_news, settings.check_interval*1000); - - //Notification.requestPermission(on_ask_perm); - } - } -})(jQuery); - - - $(document).ready(function () { // Live html5 image preview