{language}
  • Примеры
  • ЧАВО
  • Документация
  • Задачи/ошибки
  • Команда
  • Участие
  • Публикации
  • Введение

    Документация активно дорабатывается! Подумайте о том, чтобы внести свой вклад.

    PHPDaemon — это асинхронный демонизируемый фреймворк. С его помощью легко писать очень быстрые сетевые приложения, веб-сервисы и многое другое. Из коробки идут сервера FastCGI, HTTP, CGI, FlashPolicy, Telnet, WebSocket; клиенты MySQL, Redis, MongoDB, PostgreSQL, Memcached, IRC, XMPP и другие. Работать с сетью действительно просто. Программист средней руки может написать, к примеру, полноценного IRC-бота за час.

    Пользование документацией Введение

    Как видите, вся документация представлена на одной странице, поэтому вы можете пользоваться обычным поиском по странице (горячая клавиша Ctrl + F или Cmd + F)

    Установка

    Требования Установка

    Рекомендуется также установить:

    Исходный код Установка

    Вы можете клонировать PHPDaemon репозиторий
    git clone https://github.com/kakserpom/phpdaemon.git

    Или скачать текущую версию в виде архива
    wget https://github.com/kakserpom/phpdaemon/archive/master.zip

    Установите необходимые модули
    pecl install event eio inotify

    Composer Установка

    Добавьте раздел в ваш composer.json

    "require" : {
        "kakserpom/phpdaemon" : "dev-master"
    }

    Подробная информации о пакете на packagist.org.

    CentOS/RedHat Установка

    Для начала необходимо установить все сопуствующие утилиты.
    sudo yum install -y git gcc openssl-devel libevent

    Чтобы установить PHP 5.5 необходимо добавить Remi и Epel репозитории, потому что стандартный содержит старую версию.

    Для RHEL/CentOS 6.4-6.0 32 Bit.

    sudo rpm -Uvh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm 
    sudo rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-6.rpm

    Для RHEL/CentOS 6.4-6.0 64 Bit.

    sudo rpm -Uvh http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
    sudo rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-6.rpm
    #Устанавливаем PHP.  
    sudo yum --enablerepo=remi,remi-test install -y php-cli php-devel php-pear php-process
    
    #Далее устанавливаем pecl модули.  
    sudo -i
    pecl install event eio
    
    #Для корректной работы модуля event и eio необходим модуль sockets.
    #В системах RedHat/CentOS файлы конфигурации подгружаются в алфавитном порядке, поэтому назовем их z-event.ini и z-eio.ini соответственно.  
    echo "extension=event.so" > /etc/php.d/z-event.ini
    echo "extension=eio.so" > /etc/php.d/z-eio.ini
    
    exit #выходим из sudo

    Установите date.timezone в /etc/php.ini.

    #Подготовим директорию для установки PHPDaemon.  
    sudo mkdir /opt/phpdaemon
    sudo chown [your user]:[your group] /opt/phpdaemon
    cd /opt/phpdaemon
    
    #Устанавливаем PHPDaemon.  
    cd /opt/phpdaemon
    git clone https://github.com/kakserpom/phpdaemon.git ./
    
    #Копируем конфигурационный файл из примера.  
    cp /opt/phpdaemon/conf/phpd.conf.example /opt/phpdaemon/conf/phpd.conf
    
    #Сделаем ссылку на phpd
    ln -s /opt/phpdaemon/bin/phpd /usr/bin/phpd

    Запускаем PHPDaemon
    sudo phpd start --verbose-tty=1

    Опция --verbose-tty=1 указывет демону выводить журнал в терминал.

    Если вы видите что-то похожее на это:

    [PHPD] Loaded config file: '/opt/phpdaemon/conf/phpd.conf'
    [PHPD] Loaded config file: 'conf/conf.d/ExampleJabberBot.conf'
    [PHPD] Loaded config file: 'conf/conf.d/FastCGI.conf'
    [PHPD] Loaded config file: 'conf/conf.d/FlashpolicyServer.conf'
    [PHPD] Loaded config file: 'conf/conf.d/HTTPServer.conf'
    [PHPD] Loaded config file: 'conf/conf.d/IdentServer.conf'
    [PHPD] Loaded config file: 'conf/conf.d/SSL-sample.conf'
    [PHPD] Loaded config file: 'conf/conf.d/WebSocketServer.conf'

    Поздравляем! PHPDaemon запущен!

    #Для начала необходимо установить все сопутствующие утилиты.  
    sudo apt-get install gcc make libcurl4-openssl-dev libevent-dev git libevent
    
    #Устанавливаем PHP 5.5.  
    sudo apt-get install php5-cli php5-dev php-pear
    
    #Далее устанавливаем pecl модули.  
    sudo -i
    pecl install event eio
    echo "extension=event.so" > /etc/php5/mods-available/event.ini
    echo "extension=eio.so" > /etc/php5/mods-available/eio.ini
    
    #Создаем ссылки
    ln -s /etc/php5/mods-available/event.ini /etc/php5/cli/conf.d/event.ini
    ln -s /etc/php5/mods-available/eio.ini /etc/php5/cli/conf.d/eio.ini
    
    #Подготовим директорию для установки PHPDaemon.  
    mkdir /opt/phpdaemon
    chown [your user]:[your group] /opt/phpdaemon
    
    exit #выходим из sudo
    
    #Устанавливаем PHPDaemon.  
    cd /opt/phpdaemon
    git clone https://github.com/kakserpom/phpdaemon.git ./
    
    #Создаем конфигурационный файл из примера.  
    cp /opt/phpdaemon/conf/phpd.conf.example /opt/phpdaemon/conf/phpd.conf
    
    #Добавляем права на исполнение
    chmod ug+x /opt/phpdaemon/bin/*
    
    #Сделаем ссылку на phpd для удобного управления демоном  
    alias phpd='/opt/phpdaemon/bin/phpd'
    
    #Локальный алиас для sudo  
    alias sudo='sudo '

    Пробуем запустить демон.
    sudo phpd start --verbose-tty=1

    Опция --verbose-tty=1 указывает демону выводить журнал в терминал.

    Если вы видите что-то похожее на это:

    [PHPD] Loaded config file: '/opt/phpdaemon/conf/phpd.conf'
    [PHPD] Loaded config file: 'conf/conf.d/ExampleJabberBot.conf'
    [PHPD] Loaded config file: 'conf/conf.d/FastCGI.conf'
    [PHPD] Loaded config file: 'conf/conf.d/FlashpolicyServer.conf'
    [PHPD] Loaded config file: 'conf/conf.d/HTTPServer.conf'
    [PHPD] Loaded config file: 'conf/conf.d/IdentServer.conf'
    [PHPD] Loaded config file: 'conf/conf.d/SSL-sample.conf'
    [PHPD] Loaded config file: 'conf/conf.d/WebSocketServer.conf'

    Поздравляем! PHPDaemon запущен!

    Добавим алиасы чтобы они были доступны после перезагрузки

    echo "alias phpd='/opt/phpdaemon/bin/phpd'" >> ~/.bashrc
    echo "alias sudo='sudo '" >> ~/.bashrc

    Вы можете установить PHPDaemon с помощью layman overlay.

    Добавьте ссылку в секцию overlays в файле layman.cfg:
    https://github.com/lexa-uw/layman-phpdaemon/blob/master/layman.xml

    В итоге будет выглядеть примерно так:

    overlays  : http://www.gentoo.org/proj/en/overlays/repositories.xml
                https://github.com/lexa-uw/layman-phpdaemon/blob/master/layman.xml

    Выполняем команды

    sudo layman -L
    sudo layman -a phpdaemon
    sudo emerge www-servers/phpdaemon

    К примеру, нижеследующие команды устанавливают phpdaemon версии 0.4.1, 1.0_beta2 и еженедельный релиз.

    $ sudo emerge "=www-servers/phpdaemon-0.4.1" "=www-servers/phpdaemon-1.0_beta2" "www-servers/phpdaemon"
    Это пакеты, которые будут объединены по порядку:
    
    Расчёт зависимостей... готово!
    [ebuild   R   ~] www-servers/phpdaemon-0.4.1:0.4::phpdaemon  USE="libevent -examples -runkit" 0 kB
    [ebuild   R   ~] www-servers/phpdaemon-1.0_beta2:1.0::phpdaemon  USE="eio event -runkit" 0 kB
    [ebuild   R   ~] www-servers/phpdaemon-20130907:weekly::phpdaemon  USE="eio event -runkit" 0 kB
    ...

    После установки вы можете использовать "eselect phpdaemon set" для создания символической ссылки на /usr/bin/phpd

    $ sudo eselect phpdaemon list
    Available phpdaemon targets:
      [1]   phpd0.4
      [2]   phpd1.0
      [3]   phpdweekly
    $ sudo eselect phpdaemon set 3
    $ sudo eselect phpdaemon show
    Current phpdaemon:
      weekly

    Добавить phpdaemon в автозагрузку:

    $ rc-update add phpd default
     * service phpd added to runlevel default

    Добавить отдельные init.d скрипты для разных версий:

    $ ln -s /etc/init.d/phpd /etc/init.d/phpd-0.4
    $ ln -s /etc/init.d/phpd /etc/init.d/phpd-1.0
    $ ln -s /etc/init.d/phpd /etc/init.d/phpd-weekly

    Добавить phpd-1.0 в автозагрузку:

    $ rc-update add phpd-1.0 default
     * service phpd added to runlevel default

    Быстрый старт

    PHPDaemon представляет из себя один мастер-процесс с несколькими рабочими процессами.

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

    Механизма взаимодействия между ребочими процессами не предусмотрено, поэтому для синхронизации приложений в разных процессах вы можете использовать стороннее ПО, например Redis.

    Исполняющий файл находится в дирктории ./bin/phpd. Вы можете создать свой исполняющий файл, как показано в примере ./bin/sampleapp. Перед запуском демон проверяет переменную $configFile, используя её для загрузки конфигурации.

    Псевдотипы Быстрый старт

    Псевдотип url @TODO

    Управление

    $ phpd start Запуск демона
    $ phpd stop Остановка демона
    SYSCTL: SIGTERM, SIGQUIT
    $ phpd hardstop Принудительная остановка демона
    SYSCTL: SIGINT, SIGKILL
    $ phpd update Обновление конфигурации
    SYSCTL: SIGHUP
    $ phpd reload Плавный перезапуск всех рабочих процессов
    SYSCTL: SIGUSR2
    $ phpd reopenlog Переоткрытие журналов
    SYSCTL: SIGUSR1
    $ phpd restart Плавный перезапуск демона
    $ phpd hardrestart Принудительный перезапуск демона
    $ phpd status Вывод статуса демона
    $ phpd fullstatus Вывод подробной информации работы демона
    $ phpd configtest Вывод глобальных опций. В скобках будет указано значение по-умочанию.
    $ phpd log [-n K] Вывод журнала в реальном времени с помощью команды tail -f. C параметром -n K выводится K последних строк. Или используйте -n +K для вывода строк, начиная с K.
    $ phpd runworker Запуск рабочего процесса без мастер-процесса. Используется для отладки.

    Конфигурация

    Типы данных Конфигурация

    Большинство опций phpdaemon описывается своими типами данных, позволяющие указывать значения расширенным форматом.

    Предназначен для записи объема информации. Можно записать в виде целого числа или целого числа с постфиксом.

    Формат записи: integer [bBkKmMgG]?

    Постфикс Множитель Пример Значение
    b, B 1 1b 1
    k 1000 1k 1000
    K 1024 1K 1024
    m 1000 * 1000 1m 1000000
    M 1024 * 1024 1M 1048576
    g 1000 * 1000 * 1000 1g 1000000000
    G 1024 * 1024 * 1024 1G 1073741824

    Предназначен для записи количества секунд. Число может быть с плавающей точкой с использованием только символа точки ..

    Формат записи: float [smhd]? или (float [smhd])+

    Постфикс Множитель Пример Значение
    s 1 1s 1
    m 60 1m 60
    h 60 * 60 2h 12s 7212
    d 60 * 60 * 24 1d 15m 32s 87332

    Предназначен для записи чисел.

    Формат записи: integer [kKmMgG]?

    Постфикс Множитель Пример Значение
    k, K 1000 1k 1000
    m, M 1000 * 1000 1M 1000000
    g, G 1000 * 1000 * 1000 1g 1000000000

    Глобальные опции Конфигурация

    Два способа установки опций:

    1. Конфигурационный файл ./conf/phpd.conf;
    2. Параметры командной строки, например --max-workers=1.

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

    Конфигурационный файл Глобальные опции Конфигурация

    Формат записи опции название-опции [значение];

    Название опции не чувствительно к регистру и использованию знака дефиса -. Следующие варианты написания равнозначны:

    Значение может отсутствовать, что приравнивется к bool(true), либо может быть записано следующими способами:

    Для записи массива используется разделитель пробел   или запятая ,. В одном значении можно использовать оба разделителя одновременно.

    Пример опции Вывод var_dump
    var-name; bool(true)
    var-name null; NULL
    var-name true; bool(true)
    var-name false; bool(false)
    var-name 0; int(0)
    var-name 1; int(1)
    var-name 3.14; float(3.14)
    var-name "3.14"; string(4) "3.14"
    var-name "пример. длинной строки,второй пример"; string(67) "пример. длинной строки,второй пример"
    var-name пример. длинной строки,второй пример; array(5) {
        [0]=>
        string(13) "пример."
        [1]=>
        string(14) "длинной"
        [2]=>
        string(12) "строки"
        [3]=>
        string(12) "второй"
        [4]=>
        string(12) "пример"
    }
    var-name 1, 'a' null 3.14 'пару слов'; array(5) {
        [0]=>
        int(1)
        [1]=>
        string(1) "a"
        [2]=>
        NULL
        [3]=>
        float(3.14)
        [4]=>
        string(17) "пару слов"
    }

    Ниже будут перечислены глобальные опции демона в формате:
    название-опции (тип-данных = значение-по-умолчанию);

    Плавный перезапуск рабочих процессов Глобальные опции Конфигурация

    Связанные с мастер-процессом Глобальные опции Конфигурация

    Рабочие процессы Глобальные опции Конфигурация

    Журналирование и отладка Глобальные опции Конфигурация

    Подсистема ввода-вывода POSIX Глобальные опции Конфигурация

    Приложения Конфигурация

    Разработка

    Маршрутизация Разработка

    Получая запросы демон первым делом должен определить какому приложению он должен передать обработку. Для этого служит обработчик запросов AppResolver.

    Вы можете определить свой обработчик или использовать пример ./conf/AppResolver.php. Название файла должно совпадать с названием класса обработчика. Правила описываются в методе getRequestRoute. Он принимает два аргумента:

    Результатом работы метода может быть:

    Не забудьте указать в конфигурационном файле путь до вашего AppResolver.

    В настройках сервера, принимающего запросы, с помощью опции responder можно указать имя приложения по-умолчанию, которому будет передан запрос, если getRequestRoute вернул null.

    Приложение Разработка

    Приложением в демоне является класс, наследуемый от \PHPDaemon\Core\AppInstance. Название файла должно совпадать с названием приложения.

    Разместите свое приложение в каталоге со стандартными приложениями демона ./PHPDaemon/Applications.
    Укажите namespace PHPDaemon\Applications;.

    Вы можете разместить свое приложение в любом каталоге. Для этого слудет указать путь до каталога в опции add-include-path и namespace относительно этого каталога.

    Для обработки входящих запросов надо объявить метод beginRequest, который должен возвращать объект запроса. Про него будет сказано чуть ниже.

    Пример простейшего приложения ./PHPDaemon/Applications/MyApp.php:

    namespace PHPDaemon\Applications;
    
    class MyApp extends \PHPDaemon\Core\AppInstance {
        public function beginRequest($req, $upstream) {
            return new MyAppRequest($this, $upstream, $req);
        }
    }

    При запросе от клиента соединение получает один случайный рабочий процесс. Запрос передается на обработку приложению.

    По-умолчанию приложение инициализируется во всех рабочих процессах. Опция limit-instances ограничивает количество автоматически запускаемых копий приложения во всех рабочих процессах.

    Основные методы приложения:

    Если не объявлять метод beginRequest приложение при инициализации попытается найти и вернуть объект класса c постфиксом Request. Т.е. для приложения MyApp приложение попытается найти MyAppRequest.

    Обработка запросов Разработка

    Каждый клиентский запрос сопровождается созданием объекта запроса в методе beginRequest в приложении. Объект запроса будет уничтожен сразу после отправки результата клиенту.

    В Websocket объект запроса будет уничтожен при закрытии соединения.

    Класс объекта запроса должен наследоваться от \PHPDaemon\HTTPRequest\Generic. Основной рабочий код, обрабатывающий код, необходимо размещать в методе run. К свойствам запроса можно обращаться по $this->attrs или через глобальные переменные $_GET, $_POST, $_COOKIE, $_REQUEST, $_SESSION, $_FILES, $_SERVER.

    Основные методы объекта запроса:

    Серверы и клиенты Разработка

    Отладка Разработка

    Примеры Разработка

    Примеры работы компонентами демона лежат в каталоге ./PHPDaemon/Examples. В конфигурационном файле путь до примера можно указать так:

    Examples\Example {}

    Не забудьте настроить необходимые серверы и клиенты.

    В данный момент мы проверяем и переносим все примеры в каталоги компонентов. Примеры для клиента HTTP вы можете посмотреть в ./PHPDaemon/Clients/HTTP/Examples.

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

    Серверы

    Серверы предназначены для приема запросов и передачи их приложениям.

    Каждый сервер представляет собой класс наследуемый от Сеть\Сервер, который в свой очередь наследуется от Сеть\Пул. Сервер можно инициировать прямо в пользовательском приложении, например:

    /* ... */
    $this->pool = \PHPDaemon\Servers\FlashPolicy::getInstance([
        'listen' => 'tcp://0.0.0.0:843'
    ]);
    $this->pool->onReady();
    /* ... */

    Но не забывайте, что в таком случае следует отправлять ему onReady(), onShutdown() и onConfigUpdated() события.

    В большинстве случаев сервер запускается одноименнным приложением Pool.

    # контекст для ssl соединения (опционально)
    TransportContext:myContext {
        tls;
        certFile "/path/to/cert.pem";
        pkFile "/path/to/privkey.pem";
        passphrase "";
        verifyPeer true;
        allowSelfSigned true;
    }
    
    # слушаем 80 и 443 порт
    Pool:HTTPServer {
        listen "tcp://0.0.0.0:80", "tcp://0.0.0.0:443##myContext";
        port 80;
        privileged;
        maxconcurrency 1;
    }

    Опции серверов Серверы

    В данном разделе перечислены опции, используемые всеми серверами.

    Сервер использует пространство имен HTTPRequest.

    Это транспортное приложение предоставляет HTTP сервер для phpDaemon. Входящие Websocket соединения будут переданы приложению WebsocketServer.

    HTTP пробует определить приложение через AppResolver, не забудьте сконфигурировать его.

    Опции HTTP Серверы

    FastCGI Серверы

    Сервер использует пространство имен HTTPRequest.

    Это транспортное приложение представляет FastCGI сервер для phpDaemon.

    После конфигурирования phpDaemon вам также следует задействовать веб-сервер, который поддерживает FastCGI. Если вы еще не сделали выбор в пользу одного из них, мы советуем NGINX.

    Веб-сервер может передавать FastCGI-серверу параметр APPNAME, который содержит название приложения которое должно обработать данный запрос. Если параметр не передан, FastCGI-сервер попробует определить это через AppResolver.

    Пример конфигурации NGINX:

    location /Example/ {
        fastcgi_pass unix:/tmp/phpdaemon.fcgi.sock;
        fastcgi_param APPNAME Example;
        include fastcgi_params;
    }

    Опции FastCGI Серверы

    DebugConsole Серверы

    Это транспортное приложение предоставляет интерактивную отладочную консоль для phpDaemon.

    # telnet 127.0.0.1 8818
    Trying 127.0.0.1...
    Connected to 127.0.0.1.
    Escape character is '^]'.
    Welcome! DebugConsole for phpDaemon.
    
    login secret
    OK.
    eval echo 123;
    123

    Опции DebugConsole Серверы

    FlashPolicy Серверы

    Это простое приложение предоставляет Flashpolicy сервер для phpDaemon.

    Это приложение необходимо включить в случае если вы хотите присоединяться к серверу посредством Flash.

    Опции FlashPolicy Серверы

    Servers\Ident Серверы

    Servers\IRCBouncer Серверы

    Требует рефакторинга

    Servers\Socks Серверы

    WebSocket Серверы

    Сервер использует пространство имен HTTPRequest.

    Это транспортное приложение представляет WebSocket сервер для phpDaemon.

    Ваше приложение должно получать ссылку на экземпляр WebSocketServer и вызывать addRoute() для добавления своих путей. Callback-функция пути должна возвращать новый экземпляр вашего класса, который наследуется от WebSocketRoute и определяет метод onFrame. Внутри метода onFrame мы можете обращаться к $this->client->sendFrame() для отправки пакетов клиенту.

    Опции WebSocket Серверы

    Клиенты

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

    Основы Клиенты

    Опции клиентов Основы Клиенты

    Asterisk Клиенты

    namespace PHPDaemon\Clients\Asterisk;

    Раздел устарел!

    Asterisk - это АТС с открытым исходным кодом. AMI - программный интерфейс (API) Asterisk для управления системой, который позволяет разработчикам отправлять команды на сервер, считывать результаты их выполнения, а так же получать уведомления о происходящих событиях в реальном времени. Клиент Asterisk обеспечивает высокоуровневый интерфейс к AMI, позволяющий разработчикам контролировать сервер Asterisk из приложений.

    В основе документирования клиента лежит материал книги Asterisk: будущее телефонии.

    Использование Asterisk Клиенты

    @TODO это из вики, проверить

    Перед тем как посылать команды и получать события с сервера, нужно получить сессию(сессии) соединения(соединений) в вашем приложении. В вашем приложении вы получаете объект AsteriskDriver посредством:

    $this->pbxDriver = Daemon::$appResolver->getInstanceByAppName('AsteriskDriver');
    Соединение Использование Asterisk Клиенты

    Далее получаете объект AsteriskDriverSession посредством:

    $session = $this->pbxDriver->getConnection();
    // или
    foreach($this->pbxConnections as $addr => $conn) {
        $session = $this->pbxDriver->getConnection($addr);
        // что-нибудь делаем...
    }

    Добавляете (композиция) в него текущий контекст соединения посредством:

    $session->context = $this;

    При соединении:

    $session->onConnected(function(SocketSession $session, $status) {
        // ваш код, в зависимости от соединения
    });

    При разрыве:

    $session->onFinish(function(SocketSession $session) {
        // возможно запустить интервал реконнекта...
    });

    Предположим у вас несколько серверов Asterisk с которых вы хотите получать события(events) и на которые вы хотите отправлять команды(actions). Так же вы хотите отслеживать падение соединения(connection failed), и осуществлять реконнект. Смотрите пример реконнекта ниже.

    Немного о формате ввода-вывода Использование Asterisk Клиенты

    Хотя протокол AMI является строковым, драйвер при вводе-выводе работает с ассоциативными массивами. При получении ответа на действие или события все заголовки и их значения приводятся к нижнему регистру, если значение не содержит информацию, для которой важен регистр - например имя пира.

    Отправка команд и получение ответа Использование Asterisk Клиенты

    Для отправки команды и получения ответа вы можете воспользоваться либо методом-помощником, который снабжен подробным комментарием из документации Asterisk, либо универсальным методом Connection::action.

    В любом случае для каждой команды вы определяете функцию обратного вызова, в которую будет передан объект сессии соединения и ассоциативный массив пар заголовок-значение ответа.

    Клиент корректно обрабатывает, что порядок следования пакетов ответа не определен, корректно собирает составные пакеты ответа.

    $session->getSipPeers(function(SocketSession $session, array $packet) {
        // $session->addr содержит адрес соединения
        // $session->context содержит контекст вызова (если был установлен)
        // $packet - это массив пар заголовок-значение ответа
        // что-нибудь делаем
    })
    // или
    $session->getConfig('chan_dahdi.conf', array($this, 'doSomething'));
    public function doSomething(SocketSession $session, array $packet) {
    
    }
    // или
    $session->action('Ping', function(SocketSession $session, array $packet) {
        if($packet['response'] == 'success' && $packet['ping'] == 'pong') {
            // успешно сыграли в пинг-понг
        }    
    });
    // или
    // $channel содержит канал из события
    $session->redirect(array(
        'Channel' => $channel,
        'Context' => 'internal',
        'Exten' => '116',
        'Priority' => 1
    ), function(SocketSession $session, array $packet) {
      // узнаем успешно или нет из ответа сервера содержащегося в ассоциативном массиве $packet
    });
    Получение событий сервера Использование Asterisk Клиенты

    Функция обратного вызова при наступлении события в данном соединении определяется один раз и передается методу onEvent().

    $session->onEvent(array($this, 'onPbxEvent'));

    Когда запущено несколько воркеров, чтобы не получилось, что события канала(характеризуются наличием уникального идентификатора(uniqueid) канала) кратны количеству воркеров(workers) можно воспользоваться таблицей блокировки. Вот пример, когда в качестве таблицы блокировки используется MongoDB коллекция(collection), которая позволяет ставить уникальный индекс на документ:

    $session->onEvent(array($this, 'onPbxEvent'));
    // db.events.ensureIndex({"event": 1, "addr": 1}, {unique: true});
    public function onPbxEvent(SocketSession $session, array $event) {
        if(method_exists('Foo_PbxEventDispatcher', "{$event['event']}Handler")) {
            $handler = "{$event['event']}Handler";
            if(isset($event['uniqueid']) || isset($event['uniqueid1'])) {
                $appInstance = $this;
                $this->db->events->insert(
                    array(
                            'ts' => microtime(true),
                            'event' => $event,
                            'addr' => $session->addr
                    ),
                    function($result) use ($appInstance, $session, $event) {
                        if($result['err'] === null) {
                            $handler = "{$event['event']}Handler";
                            Foo_PbxEventDispatcher::$handler($appInstance, $session, $event);
                        }
                    }
                );
            }
            else {
                Foo_PbxEventDispatcher::$handler($this, $session, $event);
            }
        }
    }

    Пример реконнекта Asterisk Клиенты

    class Foo extends AppInstance {
        // ...
        public function onInit() {
            // pbxConnections - array of connections
            foreach($this->pbxConnections as $addr => $conn) {
                $pbx_driver_session = $this->pbxDriver->getConnection($addr);
                if($pbx_driver_session instanceof SocketSession) {
                    $pbx_driver_session->context = $this;
                    //$pbx_driver_session->onError(array($this, 'onPbxError'));
                    $pbx_driver_session->onConnected(array($this, 'onPbxConnected'));
                    $pbx_driver_session->onEvent(array($this, 'onPbxEvent'));
                    $pbx_driver_session->onFinish(array($this, 'onPbxFinish'));
                }
                else {
                    $this->runPbxReconnectInterval($pbx_driver_session);
                }
            }
        }
        // ...
        public function onPbxConnected(SocketSession $session, $status) {
            if($status) {
                if($session->context instanceof PbxReconnector) {
                    $session->context->finish();
                }
                // do something...
            }
            else {
                $this->runPbxReconnectInterval($session);
            }
        }
        // ...
        public function onPbxFinish(SocketSession $session) {
            $this->runPbxReconnectInterval($session);
        }
        // ...
        public function runPbxReconnectInterval(SocketSession $session) {
                    if(Daemon::$process->terminated) {
                return;
            }
            foreach ($this->queue as &$r) {
                if($r instanceof PbxReconnector) {
                    if ($r->attrs->addr == $session->addr) {
                        return;
                    }
                }
            }
            $interval = $this->pushRequest(new PbxReconnector($this, $this));
            $interval->attrs->addr = $session->addr;
        }
        // ...
    }
    // ...
    class PbxReconnector extends Request {
            public $interval = 0.3;
    
        public function run() {
            $pbx_driver_session = $this->appInstance->pbxDriver->getConnection($this->attrs->addr);
            if($pbx_driver_session) {
                if($this->appInstance->config->{'pbxreconnectorlogging'}->value) {
                    Daemon::log('Reconnecting to ' . $this->attrs->addr);
                }
                $pbx_driver_session->context = $this;
                $pbx_driver_session->onConnected(array($this->appInstance, 'onPbxConnected'));
                $pbx_driver_session->onFinish(array($this->appInstance, 'onPbxFinish'));
            }
            $this->sleep($this->interval);
        }
    }

    Класс Pool Asterisk Клиенты

    namespace PHPDaemon\Clients\Asterisk;
    class Pool extends \PHPDaemon\Network\Client;
    Опции по-умолчанию Класс Pool Asterisk Клиенты
    Методы Класс Pool Asterisk Клиенты

    Класс Connection Asterisk Клиенты

    namespace PHPDaemon\Clients\Asterisk;
    class Connection extends \PHPDaemon\Network\ClientConnection;

    Clients\DNS Клиенты

    Clients\Gibson Клиенты

    namespace PHPDaemon\Clients\HTTP;

    Предназначен для выполнения GET и POST запросов на удаленные хосты.

    Клиент использует пространство имен HTTPRequest.

    Примеры HTTP Клиенты

    Получение файла google.com/robots.txt GET запросом:

    $httpclient = \PHPDaemon\Clients\HTTP\Pool::getInstance();
    
    $httpclient->get('http://www.google.com/robots.txt',
        function ($conn, $success) {
            // обработка данных ответа
        }
    );

    Рабочий пример клиента представлен в Clients/HTTP/Examples/Simple.php

    Класс Pool HTTP Клиенты

    namespace PHPDaemon\Clients\HTTP;
    class Pool extends \PHPDaemon\Network\Client;
    Опции по-умолчанию Класс Pool HTTP Клиенты
    Методы Класс Pool HTTP Клиенты

    Класс Connection HTTP Клиенты

    namespace PHPDaemon\Clients\HTTP;
    class Connection extends \PHPDaemon\Network\ClientConnection;
    Свойства Класс Connection HTTP Клиенты

    Clients\ICMP Клиенты

    Clients\IRC Клиенты

    Требует рефакторинга

    Clients\Memcache Клиенты

    Clients\Mongo Клиенты

    MySQL Клиенты

    namespace PHPDaemon\Clients\MySQL;

    Клиент для СУБД MySQL

    Использование MySQL Клиенты

    @TODO

    В вашем приложении вам следует получать объект MySQLClient посредством Daemon::$appResolver->getInstanceByAppName('MySQLClient') и использовать как описано ниже.

    Подготовка объекта соединения Использование MySQL Клиенты
    /*
      @method getConnection
      @description Establishes connection.
      @param string Optional. Address.
      @return integer Connection's ID.
    */

    Вам следует получить объект MySQLClientSession посредством метода $MySQLClient->getConnection(), затем вы можете положить ваш текущий запрос/сессию/что-нибудь еще в текущий контекст соединения (в свойство context).

    Затем используйте:

    $this->sql->onConnected(
        function($sql, $success) {
            if (!$success) {
                return;
            }
            // your connection-dependent code
        }
    );

    Примеры MySQL Клиенты

    $sql->query('SHOW VARIABLES', 
       function($sql, $success) {
          $sql->context->queryResult = $sql->resultRows; // save the result
          $sql->context->wakeup(); // wake up the request immediately
       }
    );

    Когда callback-функция вызвана, $sql->context содержит ваш объект, который вы туда положили перед этим. $sql->resultRows хранит результат в виде массива ассоциативных массивов. $sql->resultFields содержит поля ответа в виде массива ассоциативных массивов.

    Класс Pool MySQL Клиенты

    namespace PHPDaemon\Clients\MySQL;
    class Pool extends \PHPDaemon\Network\Client;
    Опции по-умолчанию Класс Pool MySQL Клиенты
    Методы Класс Pool MySQL Клиенты

    Класс Connection MySQL Клиенты

    namespace PHPDaemon\Clients\MySQL;
    class Connection extends \PHPDaemon\Network\ClientConnection;
    Свойства Класс Connection MySQL Клиенты

    Clients\PostgreSQL Клиенты

    Clients\Redis Клиенты

    namespace PHPDaemon\Clients\Redis;

    Асинхронный клиент для NoSQL хранилища Redis

    Clients\Valve Клиенты

    Clients\WebSocket Клиенты

    Clients\XMPP Клиенты

    Библиотеки

    namespace PHPDaemon\Cache;

    Механизм локального LRU-кеша ключ-значение.

    Используется для кеширования замыканий созданных через create_function. Также используется в Clients\DNS

    Класс CappedStorage Cache Библиотеки

    namespace PHPDaemon\Cache;
    abstact class CappedStorage;

    Базовый абстрактный класс.

    Класс Item Cache Библиотеки

    namespace PHPDaemon\Cache;
    class Item;
    Свойства Класс Item Cache Библиотеки

    Класс CappedStorageHits Cache Библиотеки

    namespace PHPDaemon\Cache;
    class CappedStorageHits extends CappedStorage;

    Реализация CappedStorage с сортировкой по количеству обращений

    ComplexJob Библиотеки

    namespace PHPDaemon\Core;
    class ComplexJob extends \ArrayAccess;

    Объект класса ComplexJob позволяет повесить функцию обратного вызова на завершение всех объявленных в нем процедур. Это удобно, когда нужно выполнить ряд независимых цепочек действий.

    Примеры ComplexJob Библиотеки

    $j = new ComplexJob(function($j) { // Когда всё выполнилось
       D($j['foo']); // this
       D($j['foobar']); // is
       D($j['bar']); // sparta
    });
    
    /* Добавляем задачу */
    $j('foo', function($name, $j) { 
       $j[$name] = 'this'; // Вызываем setResult()
    
       /* Еще задачу */
       $j('foobar', function($name, $j) { 
          $j[$name] = 'is';
       });
    });
    
    /* И еще одну */
    $j('bar', function($name, $j) {
       $j[$name] = 'sparta';
    });
    
    $j(); // Запускаем

    Константы ComplexJob Библиотеки

    Свойства ComplexJob Библиотеки

    Методы ComplexJob Библиотеки

    ShellCommand Библиотеки

    namespace PHPDaemon\Core;
    class ShellCommand extends \PHPDaemon\Network\IOStream;

    Класс является наследником IOStream, так что в нём доступны такие методы как read[ln], write[ln], и так далее.

    Примеры ShellCommand Библиотеки

    Простое выполнение, аналог функции shell_exec
    ShellCommand::exec('echo "foo"', function($commandInstance, $output) {
       D($output); // foo
    });
    С дополнительными параметрами и переменными окружения
    $command = 'git log';
    $cb = function($commandInstance, $output) {
         D($output); // foo
    };
    $arguments = ['-1', '--pretty' => 'oneline'];
    $env = [];
    ShellCommand::exec($command, $cb, $arguments, $env);

    Аргументы будут экранированы с помощью escapeshellarg

    Пакетная обработка вывода

    @TODO

    Свойства ShellCommand Библиотеки

    Методы ShellCommand Библиотеки

    namespace PHPDaemon\Core;
    class Timer;

    С помощью этого класса можно создавать отложенные во времени события (таймеры)

    Примеры Timer Библиотеки

    $i = 0;
    setTimeout(function($timer) use (&$i) {
     D("Пять секунд прошло!");
    
     if (++$i < 3) {
        // запуск таймера ещё на 5 секунд
        $timer->timeout();
     } else {
        D('Конец');
        $timer->free();
     }
    }, 5e6);

    Глобальные функции Timer Библиотеки

    Свойства Timer Библиотеки

    Методы Timer Библиотеки

    TransportContext Библиотеки

    namespace PHPDaemon\Core;
    class TransportContext extends AppInstance;

    @TODO

    namespace PHPDaemon\FS;

    Класс FileSystem FS Библиотеки

    namespace PHPDaemon\FS;
    class FileSystem;
    Свойства Класс FileSystem FS Библиотеки

    Класс File FS Библиотеки

    namespace PHPDaemon\FS;
    class File;
    Свойства Класс File FS Библиотеки
    Методы Класс File FS Библиотеки

    Класс FileWatcher FS Библиотеки

    namespace PHPDaemon\FS;
    class FileWatcher;
    Свойства Класс FileWatcher FS Библиотеки

    namespace PHPDaemon\PubSub;

    Класс PubSub PubSub Библиотеки

    namespace PHPDaemon\PubSub;
    class PubSub;

    Класс PubSubEvent PubSub Библиотеки

    namespace PHPDaemon\PubSub;
    class PubSubEvent extends \SplObjectStorage;

    namespace PHPDaemon\SockJS;

    Класс Application SockJS Библиотеки

    namespace PHPDaemon\SockJS;
    class Application extends \PHPDaemon\Core\AppInstance;

    С помощью этого класса можно создавать SockJS сервера. SockJS - это простой протокол и клиент/сервер набор библиотек, на базе которых строиться реал-тайм веб приложения, где браузер автоматически выбирает транспортный протокол, базируясь на возможностях конкретного клиента (обеспечивается совместимость начиная с IE6+). При этом, с точки зрения API, разработчик получает практически полную совместимость с WebSocket API.

    Детальнее:

    Работа с любыми другими протоколами, кроме WebSocket, требует наличия Redis-сервера (при старте приложение попытается создать дефолтное соединение с localhost:6379, для отдельных настроек в конфигурации приложения можно задать свой пул соединений).

    Приложения

    MongoNode Приложения

    namespace PHPDaemon\Examples;
    class MongoNode;

    Это приложение предоставляет узел репликации MongoDB. Это дает возможность устанавливать произвольные хуки на добавление/изменение/удаление объектов.

    Требования MongoNode Приложения

    Требуется установленный модуль pecl/mongo и включенный phpdaemon/MongoCllient.

    Использование MongoNode Приложения

    Когда MongoNode включено, оно незамедлительно получает новые изменения в базе.

    По-умолчанию:

    Если объект обладает свойством “_key” сериализованное его значение отправляется в ключ Memcache под тем названием, которое задано в значении _key. Когда объект удаляется из MongoDB, он удаляется и из Memcache.

    Если объект имеет свойство “_ev”, его значение отправляется в RTEP-событие под тем названием, которое задано в значении _ev.

    TelnetHoneypot Приложения

    namespace PHPDaemon\Examples;
    class TelnetHoneypot;

    Это приложение предоставляет простой telnet сервер для phpDaemon.

    Использование TelnetHoneypot Приложения

    [[email protected] phpdaemon.wiki]# telnet 127.0.0.1 23
    Trying 127.0.0.1...
    Connected to 127.0.0.1.
    Escape character is '^]'.
    ping
    pong

    ServerStatus Приложения

    namespace PHPDaemon\Applications;
    class ServerStatus;

    Это приложение обеспечивает получение информации о состоянии phpDaemon по протоколу HTTP, аналогично консольной команде phpd fullstatus.

    Использование ServerStatus Приложения

    Необходимо добавить в conf/phpd.conf:

    ServerStatus {
        enable    1;
    }
    HTTP {
        enable 1;
        privileged;
    }

    Также в conf/AppResolver.php в методе getRequestRoute() добавить условие для запуска метода beginRequest() в приложении ServerStatus. Например, чтобы получить информацию о phpDaemon по адресу http:///ServerStatus/:

    /**
     * Routes incoming request to related application. Method is for overloading.   
     * @param object Request.
     * @param object AppInstance of Upstream.
     * @return string Application's name.
     */
    public function getRequestRoute($req, $upstream) {
        if (preg_match('~^/(ServerStatus|Example)/~', $req->attrs->server['DOCUMENT_URI'], $m)) {
            return $m[1];
        }
    }

    Пример ответа:

    Uptime: 1 day. 11 hour. 33 min. 51 sec.
    State of workers:
            Total: 4
            Idle: 4
            Busy: 0
            Shutdown: 20
            Pre-init: 0
            Wait-init: 0
            Init: 0

    Примечание ServerStatus Приложения

    Если вы используете опцию --logworkersetstatus, то соответствие такое:

    Утилиты

    Binary Утилиты

    namespace PHPDaemon\Utils;
    class Binary;

    Данный класс предоставляет набор статических методов для работы с бинарными данными.

    Методы Binary Утилиты

    Crypt Утилиты

    namespace PHPDaemon\Utils;
    class Crypt;

    Данный класс содержит методы, относящиеся к криптографии.

    Методы Crypt Утилиты

    DateTime Утилиты

    namespace PHPDaemon\Utils;
    class DateTime extends \DateTime;

    В конструтор можно передавать метку времени Unix.

    Методы DateTime Утилиты

    Encoding Утилиты

    namespace PHPDaemon\Utils;
    class Encoding;

    Сторонняя библиотека — forceutf8

    Методы Encoding Утилиты

    namespace PHPDaemon\Utils;
    class IRC;

    Класс используемый в IRC-клиенте и IRC-баунсере

    Методы IRC Утилиты

    namespace PHPDaemon\Utils;
    class MIME;

    Методы MIME Утилиты

    ShmEntity Утилиты

    namespace PHPDaemon\Utils;
    class ShmEntity;

    Эластичное хранилище кучи в разделяемой памяти

    Используется для хранения массива состояний рабочих процессов

    Методы ShmEntity Утилиты

    Terminal Утилиты

    namespace PHPDaemon\Utils;
    class Terminal;


    Данный класс нуждается в доработке: не хватает полноценной поддержки ncurses. Если хотите помочь, нажмите на кота!

    Методы Terminal Утилиты

    Структуры

    ObjectStorage Структуры

    namespace PHPDaemon\Structures;
    class ObjectStorage extends \SplObjectStorage;

    Данный класс предоставляет хранилище объектов с несколькими дополнительными методами

    Можно создавать классы-наследники

    Методы ObjectStorage Структуры

    PriorityQueueCallbacks Структуры

    namespace PHPDaemon\Structures;
    class PriorityQueueCallbacks extends \SplPriorityQueue;

    Используется в Network/Client для хранения вызовов, пока все доступные соединения заняты

    StackCallbacks Структуры

    namespace PHPDaemon\Structures;
    class StackCallbacks extends \SplStack;

    Данный класс предоставляет стек функций обратного вызова с несколькими дополнительными методами

    Используется в Network/Client для хранения стека функций обратного вызова запросов

    Методы StackCallbacks Структуры

    Примеси

    Примеси (англ. traits).

    Данный раздел описывает доступные для разработчиков встроенные примеси.

    ClassWatchdog Примеси

    namespace PHPDaemon\Traits;
    trait ClassWatchdog;

    Данная примесь уже использована во всех базовых классах и при наследовании от них не нужно использовать её повторно.

    Эта примесь нужна, чтобы предотвратить появление ошибки уровня E_ERROR (Fatal error) при обращении к несуществующему методу. E_ERROR же прерывает работу всего рабочего процесса, что недопустимо в реалиях phpDaemon. Настоятельно рекомендуется к использованию во всех используемых классах.

    Определены следующие магические методы:

    StaticObjectWatchdog Примеси

    namespace PHPDaemon\Traits;
    trait StaticObjectWatchdog;

    Данная примесь уже использована во всех базовых классах и при наследовании от них не нужно использовать её повторно.

    PHP-машина умеет хранить набор свойств объекта двумя способами: в виде фиксированного массива и в виде ассоциативной таблицы (англ. hash table) с использованием B-дерева. Изначально, при создании любого объекта, свойства хранятся в виде массива с быстрым доступом. При первой попытке установить значение свойства не объявленного директивой visibility $name, набор свойств конвертируется в ассоциативную таблицу. То же самое происходит при удалении (unset) любого свойства). Данная операция сама по себе не самая быстрая, особенно при большом количестве свойств), но и доступ к свойствам после неё замедляется. Разумеется, есть объекты с намеренно динамическим набором свойств, которые сродни ассоциативным массивам и с ними всё в порядке. Но часто бывает так, что программист забывает добавить объявление свойства или даже опечатывается в его названии. Порой это ведёт к сильному ухудшению производительности, которое трудно расследовать.

    Прежде чем говорить, что PHP медленный, неплохо бы научиться его готовить.

    Данная примесь определяет следующие магические методы:

    StrictStaticObjectWatchdog Примеси

    namespace PHPDaemon\Traits;
    trait StrictStaticObjectWatchdog;

    Поведение аналогично StaticObjectWatchdog, но эта примесь бросает исключение, вместо записи в журнал.

    Определяет следующие магические методы:

    DeferredEventHandlers Примеси

    namespace PHPDaemon\Traits;
    trait DeferredEventHandlers;

    Данная примесь реализует механизм отложенных событий в объекте.

    class MyClass {
        use \PHPDaemon\Traits\DeferredEventHandlers;
        protected function onSomethingEvent($foo, $bar) {
            return function($ev) {
                list ($foo, $bar = $ev->args;
                $ev->setResult("Foo is $foo, bar is $bar");
            };
        }
    }
    $o = new MyClass;
    $o->onSomething(function($ev) {
        D($ev->result);
        // Foo is fooo, bar is barr
    }, 'foo', 'barr');
    
    $o->onSomething(function($ev) {
        D($ev->result);
        // Foo is fooo, bar is barr
    });

    При этом когда результат уже установлен, производящее его замыкание не будет вызвано повторно. Не нужно беспокоиться о повторном вызове еще до того как результат установлен, ожидающие замыкания будут вызваны правильно.

    EventHandlers Примеси

    namespace PHPDaemon\Traits;
    trait EventHandlers;

    Данная примесь реализует простой механизм PUB/SUB для объекта.

    class MyClass {
        use \PHPDaemon\Traits\EventHandlers;
    }
    $o = new MyClass;
    
    $o->on('smth', function($o, $foo, $bar) {
        D("Foo is $foo, bar is $bar");
    });
    
    $o->trigger('smth', 'foo', 'barr');
    

    Не забывайте о том, что при удалении такого объекта необходимо вызвать метод cleanupEventHandlers(), чтобы избежать утечек памяти.

    Sessions Примеси

    namespace PHPDaemon\Traits;
    trait Sessions;

    Эта примесь реализует механизм сессий, именно реализует, а не является оберткой над session_* функциями.

    Почему мы не можем использовать нативный механизм сессий PHP?

    Как и нативная реализация, поведение сессий основывается на php.ini.

    Текущая реализация поддерживает хранение сессий в файлах, session.serialize_handler = php|php_binary, lock r+! файлов - аналогичный нативному - для предотвращения race condition.

    Вы можете безопасно использовать PhpDaemon c существующими сессиями, сериализация совместима с нативной (См. session_encode, session_decode).

    Пример использования:

    $this->onSessionStart(function ($event) {
        if (!$event->getResult()) {
            //Session open failed
        }
        //Session open succeed
    });

    Данная примесь используется в HTTPRequest и Servers\WebSocket\Route

    DNode Примеси

    trait \PHPDaemon\WebSocket\Traits\DNode

    Данная примесь применима в классах-наследниках Servers\WebSocket\Route

    Примесь реализует серверную часть протокола DNode, который служит для Удалённого вызова процедур (RPC).

    Для подключение примеси нужно внести use \PHPDaemon\WebSocket\Traits\DNode в определение своего класса-наследника Servers\WebSocket\Route.

    Затем необходимо определить методы, доступные клиенту. Фактически это делает метод defineLocalMethods, который должен вызываться в onHandshake.

    Давайте, для примера, создадим метод dummy с аргументами $foo, $bar и $callback:

    protected function dummyMethod($foo, $bar, $callback) {
        if (!static::ensureCallback($callback)) {
            /* $callback не содержит функцию обратного вызова */
            return;
        }
        $callback(md5($foo ^ $bar));
    }

    При обращении dummy('Hello', 'World', function(result) {...}) ответом будет вызов этой функции с аргументом bd7815679056a50c3f545b159ce5e385 — результатом выполнения md5('Hello' ^ 'World')

    В качестве аргументов можно передавать передавать собственные функции обратного вызова, но учтите, что они удаляются из памяти после вызова, если возвратное значение не является true. Таким образом, следует понимать ожидается ли повторный вызов, и в этом случае возвращать true. Это делается во избежание утечек памяти.

    Для вызова удаленного метода по имени, используйте callRemote.

    Как вы могли заметить, пример dummyMethod использует вызов static::ensureCallback($callback). Всегда нужно проверять переданный аргумент с помощью ensureCallback перед его исполнением. В противном случае, это обернётся серьёзной брешью безопасности.

    Методы DNode Примеси

    Сеть

    Пул Сеть

    namespace PHPDaemon\Network;
    abstract class Pool extends ObjectStorage;

    Хранит в себе активные объекты Соединение и ОткрытыйСокет.

    Пул (клиент или сервер) можно инстанцировать из пользовательского приложении, например:

    $this->httpclient = \PHPDaemon\Clients\HTTP\Pool::getInstance();

    или

    /* ... */
    $this->pool = \PHPDaemon\Servers\FlashPolicy\Pool::getInstance([
        'listen' => 'tcp://0.0.0.0:843'
    ]);
    $this->pool->onReady();
    /* ... */

    Но не забывайте отправлять ему onReady(), onShutdown() и onConfigUpdated() события.

    В большинстве случаев сервер запускается одноименнным приложением Pool.

    # контекст для ssl соединения (опционально)
    TransportContext:myContext {
        tls;
        certFile "/path/to/cert.pem";
        pkFile "/path/to/privkey.pem";
        passphrase "";
        verifyPeer true;
        allowSelfSigned true;
    }
    
    # слушаем 80 и 443 порт
    Pool:HTTPServer {
        listen "tcp://0.0.0.0:80", "tcp://0.0.0.0:443##myContext";
        port 80;
        privileged;
        maxconcurrency 1;
    }

    Свойства Пул Сеть

    Методы Пул Сеть

    Client Сеть

    namespace PHPDaemon\Network;
    abstract class Client extends Pool;

    @TODO

    Методы Client Сеть

    ClientConnection Сеть

    namespace PHPDaemon\Network;
    class ClientConnection extends Connection;

    @TODO

    Методы ClientConnection Сеть

    Connection Сеть

    namespace PHPDaemon\Network;
    abstract class Connection extends IOStream;

    @TODO

    Методы Connection Сеть

    IOStream Сеть

    namespace PHPDaemon\Network;
    abstract class IOStream;

    @TODO

    Свойства IOStream Сеть

    Методы IOStream Сеть

    Server Сеть

    namespace PHPDaemon\Network;
    abstract class Server extends Pool;

    @TODO

    Свойства Server Сеть

    Методы Server Сеть

    HTTPRequest

    Generic HTTPRequest

    namespace PHPDaemon\HTTPRequest;
    abstract class Generic extends \PHPDaemon\Request\Generic;

    @TODO

    Свойства Generic HTTPRequest

    Методы Generic HTTPRequest

    Input HTTPRequest

    namespace PHPDaemon\HTTPRequest;
    class Input extends \EventBuffer;

    @TODO

    Свойства Input HTTPRequest

    Методы Input HTTPRequest

    ЧаВО

    Как сделать событие, которое вызывается через заданный временной интервал?

    См. Библиотеки/Timer

    Публикации

    Внести свою лепту

    Если хотите помочь, то даже если располагаете ограниченным временем, не стесняйтесь! Проекту пригодится любая помощь.

    Эта документация Внести свою лепту

    Мы очень хотим свести количество недокументированного кода к минимуму, но нам не хватает рук. Даже написав абзац текста, потратив десять минут, вы уже сделаете большое дело.

    Внесение изменений Эта документация Внести свою лепту

    Старайтесь вносить изменения в на том языке, которым владеете лучше всего. Если набрались смелости добавить новый язык, возьмите за основу наиболее близкий из присутствующих.

    Чтобы внести изменения в эту документацию, необходимо:

    1. Сделать Fork репозитория kakserpom/daemon.io
    2. Внести изменения в Markdown (.md) файлы в папке ./docs/<язык>/
    3. Скомпилировать index.html, выполнив команду ./docs/build
    4. Посмотреть как выглядят внесенные изменения в браузере
    5. Послать Pull Request

    Хотите видеть изменения в браузере, не запуская каждый раз команду? Запустите watch -n1 ./docs/build — она будет выполняться раз в секунду

    Формат документации Эта документация Внести свою лепту

    Мы используем Markdown (о синтаксисе по-русски) с некоторыми дополнениями.

    Для удобства работы документация разбита на множество мелких файлов. Подключение файла осуществляется строкой иморта: <!-- import filepath.md -->. Путь к подключаемому файлу указывается относительно текущего.

    Константы используются для языковых настроек и короткой записи часто используемых шаблонов. Записываются в виде <!-- pvar Название ..Значение.. -->

    Обязательные языковые константы lang, title, menu-* должны быть переведены для каждой языковой версии документации.

    Константы могут быть использованы как шаблоны. Применение шаблона: {Название Значение1 Значение2...}. Значения будут подставлены в шаблон вместо %s.

    Пример шаблона:
    <!-- pvar tpl-outlink <a target="_blank" href="%s">%s<i class="fa fa-external-link"></i></a> -->

    Пример использования: {tpl-outlink http://ru.wikipedia.org/wiki/Markdown Markdown}

    Заголовки могут быть описаны следующими способами:

    якорь - идентификатор заголовка для навигации, который указывается в адресе. Разрешенные символы [a-zA-Z0-9_-]. Должен быть уникальным среди якорей на своём уровне, чтобы избежать коллизий адресов.

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

    Примеры:

    При добавлении нового заголовка учтите, что якорь должен быть строго на английском языке и быть простым и информативным. При переводе якори не изменяются

    Можно указать CSS-класс элемента листа:

     -.n Элемент без символа списка
     -.n.ti Элемент без символа списка и с отступом от предыдущего

    На данный момент используются CSS-классы:

    Выделение курсивом и жирным работает только через *, _ отключен для совместимости с программным кодом.

    Выделение кода апострофами `...` дополнено возможностью применять модификаторы и CSS-классы.
    Модификаторы — это опции, включающие дополнительную обработку текста.

    Модификаторы и классы пишутся после открывающего апострофа и должны быть закрыты дополнительным перед началом текста. Перед указанием модификаторов ставится символ : (двоеточие). Каждый модификатор указывается одним латинским символом. Классы указываются с помощью ведущей точки.

    При указании одновременно и модификаторов, и классов, сначала должны быть записаны модификаторы.

    Список модификаторов:

    Из классов на данный момент может применять только .clear, но лучше указывайте модификатор :c.

    Примеры использования:

    Многострочный код добавлен возможностью подсветки синтаксиса и указанием CSS-классов. Код, содержащий конфигурацию, обозначается синтаксисом ruby.

    Из классов на данный момент может применять только .inline для оформления методов.

    Примеры:

    ```php.inline
    void public post ( url $url, array $data, array $params )
    void public post ( url $url, array $data, callable $resultcb )
    ```

    ```ruby
    Pool:HTTPServer {

    listen "tcp://0.0.0.0:80", "tcp://0.0.0.0:443##myContext";  
    port 80;  
    privileged;  
    maxconcurrency 1;  

    }
    ```

    Аналогично, чтобы восполнить пробелы в PHPDoc-комментариях в коде, сделайте Fork основного репозитория, внесите изменения и пошлите Pull Request.

    Учтите, что все PHPDoc-комментарии пишутся строго на английском языке

    Программный код Внести свою лепту

    Улучшения программного кода всегда приветствуется. Если у вас есть модуль для публикации, и вы считаете, что он заслуживает включения в основной репозиторий, пришлите Pull Request. Аналогично поступайте с улучшениями существующего кода.

    Авторы документации

    Перевод на русский Авторы документации

    Корректура русской версии Авторы документации

    ...

    Программирование Авторы документации

    Fork me on GitHub