Hatred's Log Place

DON'T PANIC!

Dec 30, 2010 - 3 minute read - programming c++

Astxx: action для команды QueueStatus (+пример)

Логическое продолжение для этой статьи, команда для получения состояния очереди.

Подкатом реализация и пример использования команд QueuePause и QueueStatus, какие эвенты получаются смотрите в документации((тут или тут, вторая ссылка более полная, но на буржуйском, хотя кого это пугает? :wink:))

Реализацяи QueueStatus

/* 
 * Additonal actions for Astxx
 * Copyright (C) 2010  Alexander Drozdov <hatred@inbox.ru>
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/** @file
 *
 * Include this file to use the QueueStatus action. You should include it by hands.
 *
 */

#ifndef ASTXX_MANAGER_ACTION_QUEUE_STATUS_H
#define ASTXX_MANAGER_ACTION_QUEUE_STATUS_H

#include <astxx/manager/basic_action.h>
#include <astxx/manager/message.h>
#include <astxx/manager/error.h>

namespace astxx {
   namespace manager {
      namespace action {
         /** Ask Queue Status
          */
         class queue_status : public basic_action {
            public:
               /** Construct a QueueStatus action.
                * @param queue          - concretize queue [optional]
                * @param member         - select member [optional]
                * @param action_id      - add optional action Id to all responses [optional]
                */
               queue_status(const std::string& member    = "",
                            const std::string& queue     = "", 
                            const std::string& action_id = "") :
                                member(member),
                                queue(queue),
                                action_id(action_id) {}

               /** Format this action as a message::action.
                * @return this message as a message::action
                */
               message::action action() const {
                  message::action action("QueueStatus");

                  if (!queue.empty())
                  {
                    action["Queue"] = queue;
                  }

                  if (!member.empty())
                  {
                    action["Member"] = member;
                  }

                  if (!action_id.empty())
                  {
                    action["ActionID"] = action_id;
                  }

                  return action;
               }

            private:
               std::string queue;
               std::string member;
               std::string action_id;
         };
      }
   }
}

#endif // QUEUESTATUS_H

Пример

Пример основан на event-test.cc, что идёт вместе с astxx.

#include <astxx/manager.h>
#include <vector>
#include <string>
#include <iostream>

#include "queue_status.h"
#include "queue_pause.h"

void print_event(astxx::manager::message::event e) 
{
   //std::cout << e.format();
   std::cout << e["Paused"] << "<br/>n";
}

int main(int argc, char** argv) 
{
   std::vector<std::string> args(argv, argv + argc);

   if (args.size() != 4) 
   {
      std::cerr << "Usage: " << args[0] << " [host] [username] [secret]<br/>n";
      return 1;
   }

   try 
   {
      namespace manager = astxx::manager;
      namespace action = astxx::manager::action;

      manager::connection connection(args[1]);
      std::cout << "Connected to " << connection.name() << " v" << connection.version() << std::endl;

      boost::signals::scoped_connection c1 = connection.register_event("QueueMember", print_event);
      //boost::signals::scoped_connection c2 = connection.register_event("Queue", print_event);

      action::login login(args[2], args[3]);
      login(connection);

      action::queue_pause qpause("SIP/3008", true);
      manager::message::response resp = qpause(connection);
      std::cout << resp.format();

      action::queue_status qstatus("SIP/3008");
      resp = qstatus(connection);
      std::cout << resp.format();

      action::queue_pause qpause2("SIP/3008", false);
      resp = qpause2(connection);
      std::cout << resp.format();

      action::queue_status qstatus2("SIP/3008");
      resp = qstatus2(connection);
      std::cout << resp.format();


      for (;;) 
      {
         connection.wait_event();
         connection.pump_messages();
         connection.process_events();
      }
      return 0;
   }
   catch (const std::exception& e) 
   {
      std::cerr << "Exception: " << e.what() << std::endl;
   }
   return 1;
}

Собственно что тут происходит:

  • создаём подключение
  • регистрируем обработчик для эвента QueueMember (смотрим токи на AMI)
  • логинимся
  • ставим мембера в паузу и спрашиваем его состояние
  • убираем паузу и опять спрашиваем его состояние
  • в цикле обрабатываем приходящие эвенты

Dec 29, 2010 - 1 minute read - linux

ArchLinux: geda-gaf в community

Собственно - радость! :)

Там же теперь и разводчик pcb. Двойная радость!

К сожалению, утилита xgsch2pcb (менеджер проектов-интегратор gschem и pcb) до community ещё не добралась, но уже не плохо.

Dec 25, 2010 - 2 minute read - programming c++

Astxx: action для команды QueuePause

Парой слов, что такое Astxx небольшая библиотечка для работы с Asterisk через AMI протокол из C++. Написана с использование STL и Boost.

В одной из прошлых заметок упоминал про дружбу Qt4 и Boost.Signal - для дружбы этой библиотечки и Qt4 это и было нужно :)

Для чего нужна команда, например для организации софтовой DnD кнопки: если интерфейс будет в паузе, из очереди на него не будут переводиться звонки.

Сами классы подкатом.

UPD Переоформил в стиле Astxx

/* 
 * Additonal actions for Astxx
 * Copyright (C) 2010  Alexander Drozdov <hatred@inbox.ru>
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/** @file
 *
 * Include this file to use the QueuePause action. You should include it by hands.
 *
 */

#ifndef QUEUE_PAUSE_H
#define QUEUE_PAUSE_H

#include <astxx/manager/basic_action.h>
#include <astxx/manager/message.h>
#include <astxx/manager/error.h>

#include <vector>
#include <string>

namespace astxx
{
    namespace manager
    {                                                                                                                                                                                                                                        
        namespace action                                                                                                                                                                                                                     
        {                                                                                                                                                                                                                                    
            /** Set Queue Pause state                                                                                                                                                                                                        
            */                                                                                                                                                                                                                               
            class queue_pause : public basic_action                                                                                                                                                                                          
            {                                                                                                                                                                                                                                
            public:                                                                                                                                                                                                                          
                class error : public manager::error                                                                                                                                                                                          
                {                                                                                                                                                                                                                            
                public:                                                                                                                                                                                                                      
                    explicit error(const std::string& desc) throw() : manager::error(desc) { }                                                                                                                                               
                };                                                                                                                                                                                                                           
                                                                                                                                                                                                                                             
            public:                                                                                                                                                                                                                          
                /** Construct a QueuePause action.
                * @param interface      - member
                * @param is_on          - pause state
                * @param queue          - queue for process, if omited - all queues is used
                */
                queue_pause(const std::string &interface, const bool is_on = false, const std::string &queue = "") :
                    _interface(interface),
                    _queue(queue),
                    _is_on(is_on) {}

               /** Format this action as a message::action.
                * @return this message as a message::action
                */
                message::action action() const
                {
                    message::action action("QueuePause");

                    if (!_queue.empty())
                    {
                        action["Queue"] = _queue;
                    }

                    action["Interface"] = _interface;

                    std::string on_off_str = "false";
                    if (_is_on)
                    {
                        on_off_str = "true";
                    }

                    action["Paused"] = on_off_str;

                    return action;
                }

                message::response handle_response(message::response response)
                {
                    basic_action::handle_response(response);
                    if ("Success" != response)
                    {
                        throw queue_pause::error(response["Message"]);
                    }

                    return response;
                }

            private:
                std::string _interface;
                std::string _queue;
                bool        _is_on;
            };

        }
    }
}

#endif // QUEUE_PAUSE_H

Dec 25, 2010 - 1 minute read - programming c++

Qt4: поместить окно на все рабочие столы

Встроенного функционала нет, для X11 можно записпользовать такой код (юзается XLib):


#ifdef Q_WS_X11
#  include <X11/Xlib.h>
#  include <X11/Xatom.h>
#endif

...

toAllDesktops()
{
#ifdef Q_WS_X11
    Atom atom = XInternAtom(x11Info().display(), "_NET_WM_DESKTOP", True);
    if (atom)
    {
        uint32_t data = 0xFFFFFFFF;
        XChangeProperty(x11Info().display(),                // Display
                        winId(),                            // Window
                        atom,                               // Property
                        XA_CARDINAL,                        // Property type
                        32,                                 // Data format: 8, 16 or 32 bit
                        PropModeReplace,                    // Property change mode
                        reinterpret_cast<uint8_t*>(&data),  // Property data
                        1);                                 // Data elements count
    }
#endif
}

тут предполагается, что эта функцейка будет медотом класса окна, иначе нужно будет передавать Display и Window. Специальное значение 0xFFFFFFFF как раз и говорит - разместить на всех рабочих столах, иначе воспринимается как номер стола, куда нужно поместить окно. В случае Windows этот функционал бесмесленен, поэтому портабельность не сильно пострадает, при использовании директив препроцессора.

Подробности:

Dec 13, 2010 - 1 minute read - programming c++

Boost.Signals и Qt4

Использую библиотечку astxx, которая использует Boost.Signals, использую в программе на Qt, сразу словил ошибку компиляции:

g++ -c -m64 -pipe -g -Wall -W -D_REENTRANT -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt/mkspecs/linux-g++-64 -I../queue-test -I/usr/include/QtCore -I/usr/include -I. -I../queue-test -I. -o main.o ../queue-test/main.cpp
In file included from /usr/include/boost/signals/connection.hpp:13:0,
                 from /usr/include/boost/signals/signal_template.hpp:18,
                 from /usr/include/boost/signals/signal0.hpp:24,
                 from /usr/include/boost/signal.hpp:19,
                 from /usr/include/astxx/manager/connection.h:40,
                 from /usr/include/astxx/manager.h:32,
                 from ../queue-test/main.cpp:8:
/usr/include/boost/signals/detail/signals_common.hpp:26:13: error: expected identifier before ‘protected’
/usr/include/boost/signals/detail/signals_common.hpp:26:13: error: expected unqualified-id before ‘protected’
../queue-test/main.cpp:75:1: error: expected ‘}’ at end of input
make: *** [main.o] Error 1

Описания способов решения нашел тут:

http://www.boost.org/doc/libs/1_45_0/doc/html/signals/s04.html

Пока же, временно, определил макрос:

#define BOOST_SIGNALS_NAMESPACE boost_signals

Upd:

В .pro файле добавил:

CONFIG += no_keywords

После чего такие конструкции перестанут компилироваться:

signals:
private slots:
public slots:

Заменить на:

Q_SIGNALS:
private Q_SLOTS:
public Q_SLOTS:

Dec 8, 2010 - 2 minute read -

Немного разного про Git

Несколько вопросов про Git внутри компании, такие как:

  • миграция с mercurial (hg)
  • организация совместного доступа, управление правами
  • прикручивание к redmine
  • организация анонимного ReadOnly доступа к отдельным репозиториям

Миграция с Mercurial

Тут не буду вдаваться в особые подробности, воспользовался этой статьёй: http://hedonismbot.wordpress.com/2008/10/16/hg-fast-export-convert-mercurial-repositories-to-git-repositories/, отработало, историю правок сохранила. Единственно, на ArchLinux пришлось пробежаться и заменить вызовы python на python2.

Организация совместного доступа

Вот тут интереснее, можно это делать на основе пользователей и групп в системе, но мне захотелось что бы был один аккаунт и там уже разруливалось кому что и где можно.

Нашел статью: http://scie.nti.st/2007/11/14/hosting-git-repositories-the-easy-and-secure-way. Где собственно описывается решение на основе gitosis. Можно на просторах рунета найти перевод этой статьи на русский.

Из всего, что хотелось бы добавить: пользователей нужно в конфиге указывать как USER@HOST, иначе получите великий отлуп. Я на этом обжёгся. Решение мне не очень нравится, поэтому попробую раскурить как обойтись просто указанием USER.

Ну и как справка, сгенерировать ключик: ssh-keygen -f .ssh/$USER@$HOSTNAME

pub-часть отдать админу, что бы залил (кстати, так же через git) и прописал права. Private часть прописать для хоста с git, как - man ssh_config

Прикручивание к redmine

По умолчанию (у нас сервер с Debian) http сервер запущен с указанием группы www-data, тогда как репозитории git доступны на чтение/запись пользователю git и на чтение группе git. Вариант - добавить пользователя www-data в группу git, но не очень гибко. Я сделал следующим образом.

В корень домашней директории (/home/git) поместил следующий скрипт:

#!/bin/bash

cd /home/git
source .web-access.conf
cd repositories

# 1. pass
chown $git_user:$git_group *

# 2. pass
for repo in $repos
do
  chown $git_user:$web_group $repo
done

В /etc/sudoers добавил следующую строчку: git ALL=NOPASSWD: /home/git/allow-web-access.sh

В хук /home/git/repositories/gitosis-admin.git/hooks/post-update добавил следующую строчку: sudo -u root /home/git/allow-web-access.sh

Сделал симлинк: ln -s /home/git/repositories/gitosis-admin.git/gitosis-export/web-access.conf /home/git/.web-access.conf

Создал в рабочей копии конфигурации гитозиса файл:

repos="repo1.git repo2.git"

git_user="git"
git_group="git"
web_group="www-data"

в repos указываются репозитории к которым разрешён доступ web-серверу. После чего, как обычно: git commit -a git push

Все нужные действия выполнятся автоматом.

В самом redmine указываем полные пути к репозиториям, типа: /home/git/repositories/repo1.git

Анонимный ReadOnly доступ к некоторым репозиториям

В статье про гитозис про это есть, там правда использована опция --export-all, убираем её. Внутри директории репы, к которой нужен анонимный доступ, делаем файл git-daemon-export-ok: touch git-daemon-export-ok

На будущее - автоматизировать эту операцию через конфигурацию гитозиса.

Dec 2, 2010 - 2 minute read - programming

Java Enums

Для тех случаев когда enum нету, к примеру, при использовании BeanShell:

http://alumnus.caltech.edu/~leif/OO/Enum.html

Подкатом небольшое дополнение и пример.

Небольшая ремарка, для BeanShell придется разносить класс и сами создания констант, к примеру так:

// Не обязательно
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

/**
 Хранит описание одной записи в дополнительных действиях, а так же собирает их в перечисление
 дабы можно было использовать интерфейс коллекций для перебора при формировании списка
*/
class AdditionalActionId
{
    private static Collection all_ids = new ArrayList();

    private int    value;
    private String description;

    /**
     Конструктор, принимает ID дополнительного действия и описание (что будет в меню отображаться)
    */
    AdditionalActionId(int value, String description)
    {
        this.value       = value;
        this.description = description;

        all_ids.add(this);
    }

    /**
     Возвращает Id действия
    */
    public int toInt()
    {
        return this.value;
    }

    /**
     Возвращает описание действия
    */
    public String toString()
    {
        return this.description;
    }

    /**********************************************************************************************/
    /* Statics methods (class wide methods) ------------------------------------------------------*/
    /**********************************************************************************************/

    /**
     Получаем итератор для перебора всех ранее созданных действий
    */
    public static Iterator getIterator()
    {
        return all_ids.iterator();
    }

    /**
     Получаем количество дополнительных действий
    */
    public static int getSize()
    {
        return all_ids.size();
    }
}

/**
 Класс-обертка, для реализации некоторого подобия Enum (который не работает в BeanShell)
*/
class AdditionalActionIds
{
    private static int action = 1;

    // Перечисляем наши действия
    //public static final AdditionalActionId TARIFF_ADD_COMMON1 = new AdditionalActionId(action++, "TEST");
    //public static final AdditionalActionId TARIFF_ADD_COMMON2 = new AdditionalActionId(action++, "TEST");
    //public static final AdditionalActionId TARIFF_ADD_COMMON3 = new AdditionalActionId(action++, "TEST");
    //public static final AdditionalActionId TARIFF_ADD_COMMON4 = new AdditionalActionId(action++, "TEST");

    // Must be LAST
    public static final AdditionalActionId ABON_RECALC_ALL    = new AdditionalActionId(1000000, "Дополнительное действие");
}

// Пример перебора всех значений
/*Iterator it = AdditionalActionId.getIterator();
while (it.hasNext())
{
    action = (AdditionalActionId)it.next();
    print("ID: " + action.toInt() + ", desc: " + action.toString());
}
*/

// Пример обращения к конкретному элементу
/*AdditionalActionId action = AdditionalActionIds.TARIFF_ADD_COMMON3;
print("ID: " + action.toInt() + ", desc: " + action.toString());*/

Иначе имеем проблемы. Не знаю, бага или фича, но факт.

Nov 19, 2010 - 1 minute read - projects programming

Crowns 0.6.0

Выпустил версию 0.6.0 программы Crowns.

Из основных изменений:

  • Добавлена возможность задавать ограничение на отображение деревьев по возрасту (кстати это поле, как я понял, в основном используется не для возраста, а для задания года “рождения” дерева)
  • Исправлен диалог редактирования данных: в нем невозможно было задать возраст дерева

Nov 13, 2010 - 1 minute read - linux programming

MountTray

Написал небольшую программу для подключения, отключения сменных дисков в Linux, использует udisks для монтирования (в планах сделать бакенд и для простых mount/unmount через sudo, класс для использования которого уже написан, для полных минималистов), udev для детекта новых дисков и изъятия существующих (опять таки, готов и бакед для использования inotify, можно будет альтернативно прикрутить его, кстати, а на други unix системах как с inotify?) и в минимальном плане DBus для возможности получать сообщения: а вдруг кто-то там снаружи примонтировал/отмонтировал диск.

Пожелания - мне на мыло

~~Проект разместил на Gitorius: http://gitorious.org/h4tr3d-utils/pages/MountTray~~

Новый адрес: https://github.com/h4tr3d/mount-tray, проект не разрабатывается уже несколько лет.

Nov 11, 2010 - 2 minute read - туризм

Планировали одно, а получилось как получилось...

В составе трех человек:

  • Быстрый (Серёга)
  • Медленный (Я)
  • Новичёк (Настя) планировали на длинный ноябрьских праздниках сгонять траверс Фалаза-Пидан, и даже собрались и даже выехали…

…Но сходили, категорически не так как ожидали Но не это главное, а главное осюсения (коих, в отличии от почти диванного похода на Облачную, про который даже написать то нечего в голову не лезет, значительно больше)

В общем, маршрут не прошли, причина проста: “Русские на войне своих не бросают…” А если проще: Настя конкретно натерла (до крови) ноги уже к тому моменту как дошли до ушуисткой базы (да, решили идти по Смольному). Поэтому сделали привал, стали держать военный совет: одну домой её не отправим и одному продолжать маршрут тоже не есть гуд. Поэтому пошли на компромисс: в первый день пробатонились чуть дальше по ручью - разбили лагерь, дышали воздухом, гоняли чаи. На следующий день Я и Серёга сгоняли в радиалку на Фалазу…

Тут тоже весело получилось: планировали топать по тропе (ну вроде как она там есть), хотя я в тех районах уже на Фалазу забирался, но поднимался по осыпям. В общем… девиз радиалки стал: “тропа!? какая тропа! идём по приборам!”

Прибора было три: распечатка карты, компас и “что-то мне подсказывает”. Последним пользовался чаще :laughing:

Тропу даже искать, в общем, не стали: планировалось выйти на седловинку и там подниматься - проверить состояние и что там вообще за условия, но обходя заросли актинидии пополам с малиновым вар… в смысле с элеутерококком, опять выбрались на осыпь, ну уже и решили по ней и забираться. Так и доползли, встречая, изредка, творения рук человеческих в виде туров (http://picasaweb.google.com/skoulik/yZvOXG#5536649695455909314).

Немного почалившись на вершине, вдыхая воздух, решаем таки на обратном пути свалиться в седловинку и дальше по ручью. Ну что, сказано, сделано - на седловинку попали как снайперы (склон с осыпями и голый лес помогают ориентироваться), про тропы уже не думали (ибо нефиг), проходим немного и начинаем спускаться к ручью… От тут начинается красоты: толстенные поваленные деревья обросшие мхом, валуны в таком же состоянии, актинидия, которая, цепляясь за ноги, как бы намекает на слова из песенки (хоть там и морская тематика): “…оставайся мальчик с нами, будешь нашим королём…”, ну и конечно - элеутерококк :simple_smile: Скоро и сам ручей появился валуны стали более красивыми, а мы, как горные козлы, устроили горно-лесной паркур - скакали по камням (без рюкзаков, чего бы это не поскакать-то)

В лагере нас ждал обедс, покушали, собрались и обратно на электричку. Иголки от элеутерококка доставал до вчерашнего дня

И нужно будет опять выбрать время, маршрут таки сходить.

Малость фото (в художественном оформлении, ну уж какова фантазия художника):