Не смотря на то, что сейчас усиленно форсится, что перл как язык нынче безнадёжно устарел и ему пора на свалку истории, это совсем не так. Как и раньше, он легко ив непринуждённой манере умеет работать с текстом. Собственно, для того он и писался.

Итак, у меня появилась задача по написанию плагина-уведомлялки на перле, ибо мне интересно получать на десктопе уведомления и том, что там происходит в IRC. Сказано - сделано.

Написал я всё это процедурно и бесхитростно: приходит уведомление, мы стрипаем форматирование, добываем название канала, кто сказал и скармливаем это всё утилите notify-send. И тут же нарываемся на то, что утилита отрабатывает не моментально, а замирает на секунду-две. Всё бы ничего, но внутри себя HexChat построен по принципу 1-й циклической очереди, в которой регистрируются все происходящие эвенты, начиная с отрисовки интерфейса, событий в меню, обработки ввода пользователя и заканчивая сетевыми событиями и событиями, передаваемыми плагинам. Если какое-то событие начинает тормозить, тормозит вся программа. То есть наш HexChat начинает призадумываться, а это уже некомфортно.

Как это обойти, чтобы душевное волнение улеглось и не было столь острым?

Надо сказать программе, что наш плагин будет выполняться долго и нужно просто каждые n секунд заглядывать и проверять как у нас дела, а когда мы доработаем до конца - прибрать за нами и всё.

Делается это просто: мы спавним тред, в котором в шаредной переменной мы по окончании исполнения действия ставим или снимаем флаг. В основном треде мы просто ставим хук на таймер, и говорим проверять раз в некоторое время, как только мы нарываемся в проверке на изменение состояния флага(шаредной переменной), мы джойним тред, снимаем хук и сваливаем из скрипта. Не очень изящно, зато очень эффективно.

Для наглядности: в основной функции:

$active = 1;
my $t = threads->create(\&notify, $topic, $text);

while (! defined($t)) {
    select(undef, undef, undef, 0.25);
    $t = threads->create(\&notify, $topic, $text);
}

$t->detach;

if ($active == 1) {
    hook_timer( 100, \&timeraction);
}

return EAT_NONE;

а сам тред:

sub notify(@) {
    my($topic, $text) = @_;
    `notify-send -u normal -t 12000 -a hexchat "$topic" -i hexchat "$text"`;
    $active = 0;
}

ну и timeraction:

sub timeraction {
    if ($active == 0) {
        return REMOVE;
    } else {
        return KEEP;
    }
}

Реализовав такие "параллельные" уведомления я наткнулся на интересный баг. Есть такой notification демон, под названием dunst, если в него приезжают сразу, параллельно несколько notification-ов, он перестаёт принимать новые уведомления, просто висит и всё. Зато xfce4-notifyd и notification-daemon работают хорошо, но первый уведомлениями облепливает весь экран, а второй просто прячет бОльшую часть уведомлений по счётчик в трее, что какбэ тоже не айс...

Вот так и живём :(

Next Post