{"id":281154,"date":"2016-11-18T10:05:04","date_gmt":"2016-11-18T07:05:04","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=281154"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=281154","title":{"rendered":"\u041b\u0435\u043f\u0438\u043c \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441"},"content":{"rendered":"<p>\u041f\u043e\u0434\u043a\u0438\u043d\u0443\u043b\u0438 \u0437\u0430\u0434\u0430\u0447\u0443 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0442 RabbitMQ, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442, \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u0430\u043b\u044c\u0448\u0435 \u043f\u043e \u044d\u0442\u0430\u043f\u0443 \u0432 RabbitMQ. \u041f\u043e\u0441\u043b\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0437\u0430\u0434\u0430\u043d\u0438\u044f, \u044f \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043b \u043d\u0430 \u0442\u043e \u0447\u0442\u043e \u043f\u043e\u0443\u0447\u0438\u043b\u043e\u0441\u044c. \u041e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c, \u0447\u0442\u043e \u044d\u0442\u043e\u0442 \u043d\u0430\u0431\u043e\u0440 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0431\u044b\u0441\u0442\u0440\u043e\u0433\u043e \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f <a href=\"https:\/\/habrahabr.ru\/company\/oleg-bunin\/blog\/310418\">pipeline \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b<\/a><\/p>\n<p>  <\/p>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b: <\/p>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/CopernicaMarketingSoftware\/REACT-CPP\">REACT-CPP<\/a>;<\/li>\n<li><a href=\"https:\/\/github.com\/CopernicaMarketingSoftware\/AMQP-CPP\">AMQP-CPP<\/a>;<\/li>\n<li><a href=\"https:\/\/github.com\/miloyip\/rapidjson\">RapidJSON<\/a>;<\/li>\n<li><a href=\"https:\/\/github.com\/google\/leveldb\">LevelDB<\/a>;<\/li>\n<li><a href=\"https:\/\/github.com\/easylogging\/easyloggingpp\">Easylogging++<\/a>.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0431\u0443\u0434\u0443 \u0434\u0435\u043b\u0430\u0442\u044c \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441 \u0434\u043b\u044f \u0432\u044b\u0434\u0430\u0447\u0438 \u0440\u0435\u0439\u0442\u0438\u043d\u0433\u0430 \u0438\u0433\u0440\u043e\u043a\u043e\u0432. \u041e\u0442 \u044f\u0434\u0440\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0432 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441 \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<ul>\n<li><em>player_registered(id,name)<\/em>;<\/li>\n<li><em>player_renamed(id,name)<\/em>;<\/li>\n<li><em>player_won(id, points)<\/em>.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0421\u0435\u0440\u0432\u0438\u0441 \u0440\u0430\u0437 \u0432 \u043c\u0438\u043d\u0443\u0442\u0443 \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u0442\u0441\u044b\u043b\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u044b\u043c \u0440\u0435\u0439\u0442\u0438\u043d\u0433\u0430.\u0420\u0435\u0439\u0442\u0438\u043d\u0433 \u0441\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043f\u043e \u043d\u0430\u0431\u0440\u0430\u043d\u043d\u044b\u043c \u043e\u0447\u043a\u0430\u043c \u0437\u0430 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u043d\u0443\u044e \u043d\u0435\u0434\u0435\u043b\u044e.<\/p>\n<p><a name=\"habracut\"><\/a>  <\/p>\n<h2 id=\"react-cpp\"><strong>REACT-CPP<\/strong><\/h2>\n<p>  <\/p>\n<p><strong>REACT-CPP<\/strong> \u2014 \u044d\u0442\u043e \u043e\u0431\u0435\u0440\u0442\u043a\u0430 \u043d\u0430\u0434 <a href=\"http:\/\/software.schmorp.de\/pkg\/libev.html\">libev<\/a> \u043d\u0430 C++11. \u042d\u0442\u0430 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u043d\u0443\u0436\u043d\u0430 \u0434\u043b\u044f \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u0446\u0438\u043a\u043b\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0439(event loop).<br \/>  \u0422.\u043a. \u043a\u0440\u043e\u043c\u0435 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0441\u043e\u043a\u0435\u0442\u043e\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u044e\u0442\u0441\u044f \u0442\u0430\u0439\u043c\u0435\u0440\u044b \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0438 unix \u0441\u0438\u0433\u043d\u0430\u043b\u043e\u0432.<\/p>\n<p>  <\/p>\n<pre><code class=\"cpp\">class Application { public:      Application();     ~Application();      using IntervalWatcherPtr = std::shared_ptr&lt;React::IntervalWatcher&gt;;      void run();     void shutdown();     \/\/...  private:      bool onMinute();     \/\/...      private:      React::MainLoop m_loop;     IntervalWatcherPtr m_minuteTimer;     \/\/... };<\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"cpp\">void Application::run() {     m_minuteTimer = m_loop.onInterval(5.0, 60.0, std::bind(&amp;Application::onMinute, this));      m_loop.onSignal(SIGTERM, [this]() -&gt; bool     {         shutdown();         return false;     });      m_loop.onSignal(SIGUSR1, [this]()-&gt;bool{         cleanRating();         return true;     });      \/\/...     m_loop.run(); }  bool Application::onMinute() {     calculateRating();     sendRating();     return true; }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0422\u0443\u0442 \u0441\u043e\u0437\u0434\u0430\u044e \u0442\u0430\u0439\u043c\u0435\u0440 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u0442\u0430\u0440\u0442\u0443\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 5 \u0441\u0435\u043a\u0443\u043d\u0434 \u0438 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u043a\u0430\u0436\u0434\u044b\u0435 60 \u0441\u0435\u043a\u0443\u043d\u0434.<br \/>  \u041b\u044e\u0431\u043e\u0439 \u043f\u0440\u0438\u043b\u0438\u0447\u043d\u044b\u0439 \u0434\u0435\u043c\u043e\u043d\/\u0441\u0435\u0440\u0432\u0438\u0441 \u0434\u043e\u043b\u0436\u0435\u043d \u0438\u043c\u0435\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a <strong>SIGTERM<\/strong>, \u0447\u0442\u043e \u0431\u044b \u0438\u0437 \u0432\u043d\u0435 \u043f\u043e\u043f\u0440\u043e\u0441\u0438\u0442\u044c \u0435\u0433\u043e \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u0441\u044f.<br \/>  \u0427\u0442\u043e \u043a\u0430\u0441\u0430\u0435\u0442\u0441\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 <strong>SIGUSR1<\/strong> \u0442\u0443\u0442 \u043c\u043e\u0436\u043d\u043e \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0442\u044c \u043d\u0430\u0447\u0430\u043b\u043e\/\u043a\u043e\u043d\u0435\u0446 \u043d\u0435\u0434\u0435\u043b\u0438 \u0447\u0435\u0440\u0435\u0437 <a href=\"http:\/\/www.boost.org\/doc\/libs\/1_61_0\/doc\/html\/date_time.html\">Boost.Date_Time<\/a>, \u043d\u043e \u043c\u043d\u0435 \u0442\u0443\u043f\u043e \u043b\u0435\u043d\u044c, \u043a\u043e\u0433\u0434\u0430 \u0432 GNU\/Linux \u0435\u0441\u0442\u044c cron+pkill.<\/p>\n<p>  <\/p>\n<h2 id=\"amqp-cpp\"><strong>AMQP-CPP<\/strong><\/h2>\n<p>  <\/p>\n<p>\u0421 \u0442\u0435\u0445 \u043f\u043e\u0440 \u043a\u0430\u043a \u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043b <a href=\"https:\/\/habrahabr.ru\/post\/253317\/\">RabbitMQ tutorials \u043d\u0430 C++<\/a> AMQP-CPP \u043e\u0431\u0437\u0430\u0432\u0435\u043b\u0430\u0441\u044c \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u043d\u0430 libev \u0438 libuv.<\/p>\n<p>  <\/p>\n<p>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<pre><code class=\"cpp\">void Application::createChannel(AMQP::TcpConnection &amp;connection) {     m_channel = std::make_unique&lt;AMQP::TcpChannel&gt;(&amp;connection);      m_channel-&gt;declareQueue(m_cfg.source().name, AMQP::durable)         .onSuccess([&amp;](const std::string &amp;name, uint32_t messagecount, uint32_t consumercount)                    {                        LOG(INFO) &lt;&lt; &quot;Declared queue &quot;                                  &lt;&lt; name                                  &lt;&lt; &quot;, message count: &quot;                                  &lt;&lt; messagecount;                         m_channel-&gt;consume(m_cfg.source().name)                            .onReceived([&amp;](const AMQP::Message &amp;message,                                            uint64_t deliveryTag,                                            bool redelivered)                                        {                                            onMessage(message, deliveryTag, redelivered);                                        })                            .onError([](const char *message)                                     {                                         LOG(ERROR) &lt;&lt; &quot;Error consume:&quot; &lt;&lt; message;                                         APP-&gt;shutdown();                                     });                    })         .onError([&amp;](const char *message)                  {                      LOG(ERROR) &lt;&lt; &quot;Error declare queue:&quot; &lt;&lt; message;                      shutdown();                  }); }  void Application::onMessage(const AMQP::Message &amp;message,                             uint64_t deliveryTag,                             bool redelivered) {     parseMessage(message);     m_channel-&gt;ack(deliveryTag); }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u044f \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<pre><code class=\"cpp\">AMQP::Envelope env(s.GetString());  m_channel-&gt;publish(&quot;&quot;, m_cfg.destination().name, env);<\/code><\/pre>\n<p>  <\/p>\n<h2 id=\"leveldb\"><strong>LevelDB<\/strong><\/h2>\n<p>  <\/p>\n<p>\u041c\u043e\u0436\u0435\u0442 \u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 \u0434\u0430\u043d\u043d\u044b\u0445. \u0412\u0437\u044f\u043b LelevDB, \u044f \u043e \u043d\u0435\u043c \u043f\u0438\u0441\u0430\u043b \u0432 <a href=\"https:\/\/habrahabr.ru\/post\/256207\/\">\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 LevelDB<\/a>. \u0421\u0434\u0435\u043b\u0430\u043b \u043b\u0438\u0448\u044c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0443\u044e RAII \u043e\u0431\u0435\u0440\u0442\u043a\u0443:<\/p>\n<p>  <\/p>\n<div class=\"spoiler\"><b class=\"spoiler_title\">\u041a\u043e\u0434 \u043e\u0431\u0435\u0440\u0442\u043a\u0438<\/b><\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"cpp\">class DataBase { public:      DataBase();      bool open(const std::string &amp;path2base, bool compression = true);      bool put(const std::string &amp;key, const ByteArray &amp;value, bool sync = false);     ByteArray get(const std::string &amp;key);      Snapshot snapshot();      Iterator iterator();  private:      std::shared_ptr&lt;leveldb::DB&gt; m_backend; };  class Snapshot { public:      Snapshot();      ~Snapshot();      ByteArray get(const std::string &amp;key);      Iterator iterator();  private:      Snapshot(const std::weak_ptr&lt;leveldb::DB&gt; &amp;backend, const leveldb::Snapshot *snapshot);  private:      friend class DataBase;      std::weak_ptr&lt;leveldb::DB&gt; m_backend;     const leveldb::Snapshot *m_shapshot; };  class Iterator { public:      Iterator(std::unique_ptr&lt;leveldb::Iterator&gt; rawIterator);     Iterator(Iterator &amp;&amp;iter);      \/*!      * Create empty iterator      *\/     Iterator() = default;      ~Iterator();      bool isValid() const noexcept;      void next();      void prev();      std::string key();     ByteArray value();      \/*!      * Seek to first      *\/     void toFirst();      \/*!      * Seek to last      *\/     void toLast();      Iterator(const Iterator &amp;) = delete;     Iterator &amp;operator=(const Iterator &amp;) = delete;  private:      std::unique_ptr&lt;leveldb::Iterator&gt; m_iterator; };<\/code><\/pre>\n<\/div>\n<\/div>\n<p>  <\/p>\n<p>LevelDB \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f\/\u0432\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f.<\/p>\n<p>  <\/p>\n<pre><code class=\"cpp\">void Application::loadFromLocalStorage() {     auto snapshot = m_localStorage-&gt;snapshot();     auto iter = snapshot.iterator();     iter.toFirst();     while (iter.isValid()) {         auto player = new Player(iter.value());         m_id2player[player-&gt;id] = player;         m_players.push_back(player);         iter.next();     } }  void Application::updatePlayerInBD(const Player *player) {     if (!m_localStorage-&gt;put(std::to_string(player-&gt;id), player-&gt;serialize())) {         LOG(ERROR) &lt;&lt; &quot;[&quot; &lt;&lt; player-&gt;id &lt;&lt; &quot;, &quot;                    &lt;&lt; player-&gt;name                    &lt;&lt; &quot;] is not updated in the database&quot;;     } }<\/code><\/pre>\n<p>  <\/p>\n<h2 id=\"logika-servisa\"><strong>\u041b\u043e\u0433\u0438\u043a\u0430 \u0441\u0435\u0440\u0432\u0438\u0441\u0430<\/strong><\/h2>\n<p>  <\/p>\n<p>\u0414\u0430\u043d\u043d\u044b\u0435 \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0442 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 JSON. <\/p>\n<p>  <\/p>\n<p>\u0420\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u0442 json \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f <strong>RapidJSON<\/strong>, \u0438\u0449\u0443 \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u0438\u0439 \u043c\u0435\u0442\u043e\u0434, \u0432\u044b\u0437\u044b\u0432\u0430\u044e \u043d\u0443\u0436\u043d\u044b\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a:<\/p>\n<p>  <\/p>\n<pre><code class=\"cpp\">void Application::parseMessage(const AMQP::Message &amp;message) {     \/*      * \u0421\u0445\u0435\u043c\u043a\u0430 \u0438\u043c\u0435\u0435\u0442 \u0432\u0438\u0434      * {      *   &quot;method&quot;:&quot;player_registered&quot;,      *   &quot;params&quot;:{      *   ...      *   }      * }      *\/     rapidjson::Document doc;     doc.Parse(message.body(), message.bodySize());      const std::string method = doc[&quot;method&quot;].GetString();     auto iter = m_handlers.find(method);     if (iter != m_handlers.end()) {         iter-&gt;second(*this, doc[&quot;params&quot;]);     }     else {         LOG(WARNING) &lt;&lt; &quot;Unknown method:&quot; &lt;&lt; method;     } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0421\u0430\u043c\u0438 \u043c\u0435\u0442\u043e\u0434\u044b \u043f\u0440\u043e\u0441\u0442\u044b\u0435:<\/p>\n<p>  <\/p>\n<pre><code class=\"cpp\">void Application::onPlayerRegistered(const JValue &amp;params) {     auto obj = params.GetObject();     const uint64_t playerId = obj[&quot;id&quot;].GetUint64();     if (!isRegistred(playerId)) {         auto player = new Player;         player-&gt;id = playerId;         player-&gt;name = obj[&quot;name&quot;].GetString();         m_players.push_back(player);         m_id2player[playerId] = player;         updatePlayerInBD(player);     } }  void Application::onPlayerRenamed(const JValue &amp;params) {     auto obj = params.GetObject();     const uint64_t playerId = obj[&quot;id&quot;].GetUint64();     if (isRegistred(playerId)) {         auto player = m_id2player[playerId];         player-&gt;name = obj[&quot;name&quot;].GetString();         updatePlayerInBD(player);     }     else {         LOG(WARNING) &lt;&lt; &quot;Renaming an unknown user[&quot; &lt;&lt; playerId &lt;&lt; &quot;]&quot;;     } }  void Application::onPlayerWon(const JValue &amp;params) {     auto obj = params.GetObject();     const uint64_t playerId = obj[&quot;id&quot;].GetUint64();     if (isRegistred(playerId)) {         auto player = m_id2player[playerId];         player-&gt;points += obj[&quot;points&quot;].GetInt64();         updatePlayerInBD(player);     }     else {         LOG(WARNING) &lt;&lt; &quot;Unknown player[&quot; &lt;&lt; playerId &lt;&lt; &quot;]&quot;;     } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0420\u0430\u0437 \u0432 \u043c\u0438\u043d\u0443\u0442\u0443 \u0441\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u0438\u0433\u0440\u043e\u043a\u043e\u0432 \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c \u0440\u0435\u0439\u0442\u0438\u043d\u0433:<\/p>\n<p>  <\/p>\n<pre><code class=\"cpp\">bool Application::onMinute() {     calculateRating();     sendRating();     return true; }  void Application::calculateRating() {     std::sort(m_players.begin(), m_players.end(), [](const Player *a, const Player *b)     {         return a-&gt;points &gt; b-&gt;points;     }); }  void Application::sendRating() {     using namespace rapidjson;      StringBuffer s;     Writer&lt;StringBuffer&gt; writer(s);     writer.StartArray();      const size_t count = std::min(m_players.size(), size_t(10));     for (size_t i = 0;          i &lt; count;          ++i) {         writer.StartObject();          writer.Key(&quot;id&quot;);         writer.Uint64(m_players[i]-&gt;id);          writer.Key(&quot;name&quot;);         writer.String(m_players[i]-&gt;name.c_str());          writer.Key(&quot;points&quot;);         writer.Int64(m_players[i]-&gt;points);          writer.EndObject();     }      writer.EndArray();     AMQP::Envelope env(s.GetString());      m_channel-&gt;publish(&quot;&quot;, m_cfg.destination().name, env); }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412\u0435\u0441\u044c \u043a\u043e\u0434 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043d\u0430 <a href=\"https:\/\/github.com\/RPG-18\/SimpleMicroservice\">GitHub&#8217;e<\/a>. \u0418\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a \u043f\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u043c \u0438 \u0441\u043e\u0431\u0438\u0440\u0430\u044e\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0430 GNU\/Linux \u0441 gcc.<\/p>\n<p>  <\/p>\n<p>\u041f\u043e\u0434\u0432\u0435\u0434\u0435\u043c \u0438\u0442\u043e\u0433\u0438, \u0447\u0442\u043e \u0438\u043c\u0435\u0435\u043c:<\/p>\n<p>  <\/p>\n<ul>\n<li>event loop \u0441 \u0442\u0430\u0439\u043c\u0435\u0440\u0430\u043c\u0438, \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c\u0438 \u0441\u0438\u0433\u043d\u0430\u043b\u043e\u0432 \u0438 \u0432\u0441\u0435\u043c\u0438 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u043f\u043b\u044e\u0448\u043a\u0430\u043c\u0438 libev;<\/li>\n<li>\u0440\u0430\u0431\u043e\u0442\u0430 \u0441 RabbitMQ;<\/li>\n<li>\u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u043e\u0435 key-value \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435;<\/li>\n<li>\u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 json.<\/li>\n<\/ul>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habrahabr.ru\/post\/315268\/\"> https:\/\/habrahabr.ru\/post\/315268\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u041f\u043e\u0434\u043a\u0438\u043d\u0443\u043b\u0438 \u0437\u0430\u0434\u0430\u0447\u0443 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0442 RabbitMQ, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442, \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u0430\u043b\u044c\u0448\u0435 \u043f\u043e \u044d\u0442\u0430\u043f\u0443 \u0432 RabbitMQ. \u041f\u043e\u0441\u043b\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0437\u0430\u0434\u0430\u043d\u0438\u044f, \u044f \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u043b \u043d\u0430 \u0442\u043e \u0447\u0442\u043e \u043f\u043e\u0443\u0447\u0438\u043b\u043e\u0441\u044c. \u041e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c, \u0447\u0442\u043e \u044d\u0442\u043e\u0442 \u043d\u0430\u0431\u043e\u0440 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0431\u044b\u0441\u0442\u0440\u043e\u0433\u043e \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f <a href=\"https:\/\/habrahabr.ru\/company\/oleg-bunin\/blog\/310418\">pipeline \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u044b<\/a><\/p>\n<p>  <\/p>\n<p>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b: <\/p>\n<p>  <\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/CopernicaMarketingSoftware\/REACT-CPP\">REACT-CPP<\/a>;<\/li>\n<li><a href=\"https:\/\/github.com\/CopernicaMarketingSoftware\/AMQP-CPP\">AMQP-CPP<\/a>;<\/li>\n<li><a href=\"https:\/\/github.com\/miloyip\/rapidjson\">RapidJSON<\/a>;<\/li>\n<li><a href=\"https:\/\/github.com\/google\/leveldb\">LevelDB<\/a>;<\/li>\n<li><a href=\"https:\/\/github.com\/easylogging\/easyloggingpp\">Easylogging++<\/a>.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0431\u0443\u0434\u0443 \u0434\u0435\u043b\u0430\u0442\u044c \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441 \u0434\u043b\u044f \u0432\u044b\u0434\u0430\u0447\u0438 \u0440\u0435\u0439\u0442\u0438\u043d\u0433\u0430 \u0438\u0433\u0440\u043e\u043a\u043e\u0432. \u041e\u0442 \u044f\u0434\u0440\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0432 \u043c\u0438\u043a\u0440\u043e\u0441\u0435\u0440\u0432\u0438\u0441 \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f:<\/p>\n<p>  <\/p>\n<ul>\n<li><em>player_registered(id,name)<\/em>;<\/li>\n<li><em>player_renamed(id,name)<\/em>;<\/li>\n<li><em>player_won(id, points)<\/em>.<\/li>\n<\/ul>\n<p>  <\/p>\n<p>\u0421\u0435\u0440\u0432\u0438\u0441 \u0440\u0430\u0437 \u0432 \u043c\u0438\u043d\u0443\u0442\u0443 \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u0442\u0441\u044b\u043b\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u044b\u043c \u0440\u0435\u0439\u0442\u0438\u043d\u0433\u0430.\u0420\u0435\u0439\u0442\u0438\u043d\u0433 \u0441\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043f\u043e \u043d\u0430\u0431\u0440\u0430\u043d\u043d\u044b\u043c \u043e\u0447\u043a\u0430\u043c \u0437\u0430 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u043d\u0443\u044e \u043d\u0435\u0434\u0435\u043b\u044e.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-281154","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/281154","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=281154"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/281154\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=281154"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=281154"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=281154"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}