.. _ref-first-step:
Первые шаги в написании собственного приложения
===============================================
Вы можете писать свои приложения для управления сетью.
Введиение
---------
Так как RUNOS написан на языке с++, то для эффективности приложения дописываются к существующему коду, то есть после написания вашего приложения вам придется пересобирать RUNOS.
Предполгается, что вы хорошо владете языком C++ и `фреймворком qt `_. Так же полезны базовые знанияе утилиты `cmake `_.
Все файлы, которые вы создаете вам необходимо указывать в подходящем CMakeList.txt, в соответсвии с тем в какой директории находится ваш модуль.
После этого RUNOS будет компилироваться с вашими файлами.
.. _ref-application:
класс Application
------------------
Приложение в RUNOS это класс, который наследован от абстрактного класса Application, который объявлен в файле Application.hh:
.. cpp:class:: Application : public QObject
..
    Вам надо будет перегразуить некоторые виртуальные функции для корректной работы (См. AIP Reference).
    Методы, необходимые для перегрузки :
      * .. cpp:function:: DependencyList Application::DependsOn(const Config& config) const
        Список приложений, от которых зависит ваше приложение.
      * .. cpp:function:: std::string Application::provides() const
        Уникальная строка, которая идентифицирует ваше приложение и может быть использовано остальными для получения доступа к вашему приложению.
      * .. cpp:function:: void Application::init(class Loader*)
        Метод, который инициализирует ваше приложение.
Вам необходимо вставить макрос внутрь вашего класса
(как в `Q_OBJECT `_),
для того, чтобы ваш класс удовлетоврял необходимым требованиям :
.. c:function:: SIMPLE_APPLICATION(your_klass, provides_val)
  your_klass -- Ваш класс.
  provides_val -- имя вашего класса.
  Данный макрос так же добавит в ваш класс статический метод ``get(Loader *)`` который позволит остальным приложениями получать доступ к вашему приложению.
Например::
    #include "Application.hh"
    #include "Loader.hh"
    class YourApp : public Application
    {
    SIMPLE_APPLICATION(YourApp, "your-application-name")
    public:
       void init(Loader*, const Config&) override;
    };
Инициализация
-------------
.. cpp:function:: void Application::init(Loader* ,const Config&)
    Вам необходимо переопредилить данный метод, который вызывается при запуске контроллера, и приложение готово к инициализации, т.е. все зависимости готовы к старту.
Данный метод должен реализовывать все связи вашего приложения с
остальными приложением (Например `connect сигналов `_ или регистрации обработчиков)
Пример::
  #include "Common.hh"
  void YourApp::init(Loader *, const Config& )
  {
       LOG(INFO) << "Hello World";
  }
Старт приложения
----------------
.. cpp:function:: void Application::startUp(Loader *)
    Данный метод вызывается, когда все приложения проиницилизированы.
    В нем вам необходимо выполнить все побочные эффекты вашего приложения, напиример прослушание портов.
Пример::
    #include "Common.hh" // For log
    void YourApp::startUp(Loader *)
    {
      LOG(INFO) << "All services inited";
    }
Регестрация приложения
-----------------------
После того, как вы создали класс для вашего приложения, вам необходимо сообщить ядру контроллера о сущестовании вашего приложения.
Для этого необходимо зарегестрировать ваше приложение с помощью макроса
  .. c:function:: REGISTER_APPLICATION(your_class, list_of_dependeces)
      your_class -- имя вашего класса.
      list_of_depenedeces -- Список, приложений, от которых заваисит ваше приложение. Последним необходимо указать ``""``.
      .. attention::
          Данный макрос нельзя прописывать в заголовочном файле!
.. warning::
    Нельзя зацикиливать зависимости.
Теперь будет создаваться объект вашего приложения,
однако все еще не будут вызываться методы
:cpp:func:`Application::init`
и
:cpp:func:`Application::startUp`, потому что контроллер не считает нужным запускать ваше приложение.
Вам необходимо указать имя своего приложения в ``network-settings.json`` в списке ``services``, чтобы ваше приложение запустилось.
После этого ваше приложение запуститься и может управлять сетью.
Loader
------
.. cpp:class:: Loader
Методы :cpp:func:`Application::init` и :cpp:func:`Application::startUp` принимают как парметр указатель на :cpp:class:`Loader`.
:cpp:class:`Loader` это загрузчик приложений, который и инициализирует ваши приложения.
.. cpp:function:`Application* Loader::app(std::string interface)`
    Данным методом можно получить указатели на стороние приложения.
    interface -- имя стороннего приолжения.
Вы можете получать объекты других приложений с помощью статического метода ``get`` этих приложений, и передав им :cpp:class:`Loader` как аргумент.
Например::
    #include "Controller.hh"
    #include "Loader.hh"
    #include "SwitchConnection.hh"
    #include "Common.hh"
    REGISTER_APPLICATION(YourApp, {"controller", ""})
    ...
    void YourApp::init(Loader *loader, const Config& )
    {
      Controller *ctrl = Controller::get(loader);
      QObject::connect(ctrl, &Controller::switchUp,
          [](SwitchConnectionPtr conn, of13::FeaturesReply fr)
          {
              LOG(INFO) << "This is SWITCH!!!!";
          };)
    }
.. attention::
    Добавляйте приложения, которые вы используется в список зависимостей! Это гарантирует, то что эти приложения будут проиницилизированы.
..
    .. note::
   Чтобы ваше приложение имело хоть какую-нибудь практическую пользу, вам придется взаимодействовать с другими приложениями, чтобы от них узнавать о событиях в сети.
Работа с конфигурационным файлом
--------------------------------
Ваше приложение может считывать настройки из конфигурационного файла.
.. cpp:type: json11:Json::object  Config
    С помощью этого класса, вы можете считываать настройки из файла ``network-settings.json``.
.. cpp:function:: Type config_get(const Config& config,\
                              const std::string& key,\
                              const Type& defval)
    Считать из файла настроек ``network-settings.json`` значение по ключу.
    Если данный ключ не найдет, будет возвращен defval.
    На данный момент поддерживаются следующие типы :
        * ``std::string``
        * ``int``
        * ``double``
        * ``bool``
.. cpp:function:: Config config_cd(const Config& config,\
                                   const std::string& key)
    получить описание объекта json по ключу.
Дополнительные возможности см в `документации по json11 `_.