воскресенье, июля 06, 2014

Next Gen PBX

Возвращаюсь к теме создания софта для ip-телефонии. Тема для меня не перестала быть интересной даже спустя год после смены деятельности с администрирования на программирование.
Уже больше года вынашиваю идею создания платформы для ip-телефонии с реализацией виртуализации на уровне самой платформы. Т.е., например, есть оператор связи мелкой или средней руки, который получил лицензию на телематические услуги и взял у ФАС пул городских номеров. И вот хочется этому оператору со своих клиентов стричь деньги не только за предоставление городского номера и телефонных линий, а, например, за услугу виртуальной АТС. Это чтобы клиент вообще не заморачивался с оборудованием, а только купил/взял в аренду телефонные аппараты.
И вот тут выходит на сцену платформа для предоставления услуг виртуальных АТС. Таких решений на рынке пока немного и все они, как правило, платные и очень(просто космически) дорогие или топорно сделанные(или и то и другое). Я хочу создать опенсорсную систему на базе IP PBX FreeSWITCH. Выбор данной pbx(а не того же астериска) обусловлен некоторыми факторами, главными из которых являются более серьёзный подход к разработке системы(этой мой взгляд со стороны), использование в качестве SIP-модуля библиотеки sofia, возможность(вроде как неиллюзорная) использовать платы расширения digium|sangoma|openvox, ну и вообще, за 8 лет астериск уже как-то поприелся, хочется чего-то свежего.
В настоящий момент пилю систему для аудио-конференций, планирую в будущем включить данную систему в состав телефонной платформы. Сейчас же просто, как проба пера, чтобы сформировать окончательный образ будущей системы и понабивать себе руку в написании кода асинхронного приложения.

среда, июля 02, 2014

Perl. Добавляем инкапсуляцию методам класса

Перл - замечательный язык с очень простой и понятной ООП-парадигмой. Из коробки мы имеем полиморфизм и наследование, но, к сожалению, не можем похвастаться инкапсуляцией.
Инкапсуляция, для тех кто не знаком с терминами, это сокрытие методов класса от посторонних лиц. Другими словами, мы в классе создаём различные методы, часть из которых доступна для вызова другими модулями/скриптами. Другая часть не должна быть вызвана нигде, кроме как в самом классе(private-метод) или в классе, который наследуется от данного класса(protected-метод).
В перле, как и в питоне, нельзя штатными средствами перекрыть доступ к методам класса. Применяется негласное соглашение, по которому методы(или функции), имена которых начинаются с нижнего подчёркивания, считаются приватными.

С этим в принципе можно мириться и ваять код на pure-перл, не прибегая к ООП-фреймворкам типа Moose, что я в принципе всегда и делал - меня слегка пугает перспектива тянуть в своё приложение 100500 модулей ради одного функционала.
К счастью, благодаря статье в журнале pragmaticperl я узнал о модуле Attribute::Protected. Данный модуль написал Tatsuhiko Miyagawa, очень известный разработчик в мире Perl.
Модуль достаточно легковесный и имеет в зависимостях только Attribute::Handlers, который давно является модулем ядра perl.
Рассмотрим на примере, как можно с помощью указанного модуля добавить в наш класс инкапсуляцию.
Для наглядности создадим 2 модуля и один скрипт, который будет вызывать оба модуля. Один модуль будет наследоваться от другого.

MyModuleParent.pm :
package MyModuleParent;

use strict;
use warnings;
use Attribute::Protected;

sub new {
    my $class = shift;

    return bless {}, $class;
}

sub _private_method : Private {
    print "This is private method in package " . __PACKAGE__ . "\n";
}

sub _protected_method : Protected {
    print "This is protected method in package " . __PACKAGE__ . "\n";
}

sub public_method {
    print "This is public method in package " . __PACKAGE__ . "\n";
}

1;

MyModule.pm :
package MyModule;

use strict;
use warnings;

use parent 'MyModuleParent';

sub mymethod {
    print "This is simple method in package " . __PACKAGE__ . "\n";
}

sub call_protect_method {
    my $self = shift;
    $self->_protected_method;
}

sub call_private_method {
    my $self = shift;
    $self->_private_method;
}

1;

script.pl :
#!/usr/bin/perl

use strict;
use warnings;

use MyModule;
use MyModuleParent;

my $parent_object = MyModuleParent->new;
my $object = MyModule->new;

$object->public_method;         # OK
$object->mymethod;              # OK
$object->call_protect_method;   # OK
$object->call_private_method;   # NOT OK

$parent_object->public_method;       # OK
$parent_object->_protected_method;   # NOT OK
$parent_object->_private_method;     # NOT OK
Объект "$object" может вызвать публичный метод класса "MyModuleParent", т.к. от него наследуется класс "MyModule". Также, данный объект вызывает методы "call_protect_method" и "call_private_method", вызывающие в свою очередь protect и private методы класса "MyModuleParent" соответственно. Вызов метода "call_private_method" завершится с ошибкой _private_method() is a private method of MyModuleParent!, вызов метода "call_protect_method" завершится успешно. Прямой вызов из скрипта private и protected методов класса "MyModuleParent"(через объект $parent_object) завершится с ошибкой.

Таким образом, мы получаем малой кровью(а оверхед там действительно ничтожный, проверенно в дебаггере) надёжную инкапсуляцию методов, очень похожую на сишную и явовску, да к тому же сделанную почти полностью на базовых средствах языка. Модулю Attribute::Protected уже 13 лет, удивитильно, что его так мало используют.