<commit_before>#include <miniMAT/ast/WhosStmt.hpp>

#include <miniMAT/util/PrintResult.hpp>

#include <iostream>
#include <iomanip>

namespace miniMAT {
    namespace ast {
        std::string WhosStmt::GetClassName() const {
            return "WhosStmt";
        }

        void WhosStmt::VisitDisplay(const std::string& prefix) const {
            using namespace miniMAT::visit::display;

            Show(prefix, *this);
        }

        Matrix WhosStmt::VisitEvaluate(std::shared_ptr<std::map<std::string, Matrix>> vars) {
            if (vars->size() != 0) {
                using namespace std;

                // Get max variable name length
                auto maxwidth = max_element(vars->begin(), vars->end(), [](pair<string, Matrix> p1, pair<string, Matrix> p2) {
                    return p1.first.size() < p2.first.size();}
                )->first.size();

                // Get "longest" row and col dimensions
                auto rowcompare = [](pair<string, Matrix> p1, pair<string, Matrix> p2) {
                    int firstlength  = log10(p1.second.rows()) + 1;
                    int secondlength = log10(p2.second.rows()) + 1;
                    return firstlength < secondlength;
                };
                auto colcompare = [](pair<string, Matrix> p1, pair<string, Matrix> p2) {
                    int firstlength  = log10(p1.second.cols()) + 1;
                    int secondlength = log10(p2.second.cols()) + 1;
                    return firstlength < secondlength;
                };
                int maxrows = log10(max_element(vars->begin(), vars->end(), rowcompare)->second.rows()) + 1;
                int maxcols = log10(max_element(vars->begin(), vars->end(), colcompare)->second.cols()) + 1;

                int space = 2;

                cout << setw(maxwidth + space) << right << "Name" << setw(maxrows+1+maxcols + space) << right << "  Size " << endl;
                cout << setw(maxwidth + space) << right << "====" << setw(maxrows+1+maxcols + space) << right << "  ==== " << endl;
                for (auto var : *vars) {
                    auto varname = var.first;
                    auto rowstr  = to_string(var.second.rows());
                    auto colstr  = to_string(var.second.cols());

                    cout << setw(maxwidth + space) << right << varname << setw(maxrows + space) << right << rowstr << "x" << setw(maxcols + space) << left << colstr << endl;
                }
            }

            return Matrix::Zero(0,0);
        }

        void WhosStmt::VisitCheck(std::shared_ptr<std::map<std::string, Matrix>> vars,
                                  std::shared_ptr<reporter::ErrorReporter> reporter) const {

        }
    }
}<commit_msg>Add 'Bytes' field to 'whos' statement<commit_after>#include <miniMAT/ast/WhosStmt.hpp>

#include <miniMAT/util/PrintResult.hpp>

#include <iostream>
#include <iomanip>

#include <cstring>

namespace miniMAT {
    namespace ast {
        std::string WhosStmt::GetClassName() const {
            return "WhosStmt";
        }

        void WhosStmt::VisitDisplay(const std::string& prefix) const {
            using namespace miniMAT::visit::display;

            Show(prefix, *this);
        }

        Matrix WhosStmt::VisitEvaluate(std::shared_ptr<std::map<std::string, Matrix>> vars) {
            if (vars->size() != 0) {
                using namespace std;

                // Get max variable name length
                auto maxwidth = max_element(vars->begin(), vars->end(), [](pair<string, Matrix> p1, pair<string, Matrix> p2) {
                    return p1.first.size() < p2.first.size();}
                )->first.size();

                // Get number of digits in "largest" row and col dimensions
                auto rowcompare = [](pair<string, Matrix> p1, pair<string, Matrix> p2) {
                    int firstlength  = log10(p1.second.rows()) + 1;
                    int secondlength = log10(p2.second.rows()) + 1;
                    return firstlength < secondlength;
                };
                auto colcompare = [](pair<string, Matrix> p1, pair<string, Matrix> p2) {
                    int firstlength  = log10(p1.second.cols()) + 1;
                    int secondlength = log10(p2.second.cols()) + 1;
                    return firstlength < secondlength;
                };
                int maxrows = log10(max_element(vars->begin(), vars->end(), rowcompare)->second.rows()) + 1;
                int maxcols = log10(max_element(vars->begin(), vars->end(), colcompare)->second.cols()) + 1;

                // Get number of digits in largest size (in bytes)
                int doublesize  = sizeof(double);
                auto sumcompare = [](pair<string, Matrix> p1, pair<string, Matrix> p2) {
                    return p1.second.sum() < p2.second.sum();
                };
                int maxbytes = log10(max_element(vars->begin(), vars->end(), sumcompare)->second.sum() * doublesize) + 1;

                int space = 6;

                int totalbytes = 0;
                int totalsize  = 0;

                int namewidth = maxwidth + space;
                int sizewidth = maxrows+1+maxcols + space;
                int bytewidth = maxbytes + space;

                cout << setw(namewidth) << right << "Name" << setw(sizewidth) << right << "Size" << setw(bytewidth) << right << "Bytes" << endl;
                cout << setw(namewidth) << right << "====" << setw(sizewidth) << right << "====" << setw(bytewidth) << right << "=====" << endl;
                for (auto var : *vars) {
                    auto varname = var.first;

                    auto rowstr  = to_string(var.second.rows());
                    auto colstr  = to_string(var.second.cols());

                    auto bytes   = static_cast<int>(var.second.size() * doublesize);
                    auto bytestr = to_string(bytes);

                    totalbytes += bytes;
                    totalsize  += 1;

                    cout << setw(namewidth) << right << varname << setw(maxrows+space) << right << rowstr << "x" << setw(maxcols+space) << left << colstr << setw(maxbytes) << right << bytestr << endl;
                }
                cout << endl << "Grand total is " << totalsize << " elements using " << totalbytes << " bytes" << endl;
            }

            return Matrix::Zero(0,0);
        }

        void WhosStmt::VisitCheck(std::shared_ptr<std::map<std::string, Matrix>> vars,
                                  std::shared_ptr<reporter::ErrorReporter> reporter) const {

        }
    }
}<|endoftext|>


<commit_before>#include "kvazaarfilter.h"

#include "statisticsinterface.h"

#include <kvazaar.h>

#include <QSettings>
#include <QtDebug>
#include <QTime>
#include <QSize>

enum RETURN_STATUS {C_SUCCESS = 0, C_FAILURE = -1};

KvazaarFilter::KvazaarFilter(QString id, StatisticsInterface *stats):
  Filter(id, "Kvazaar", stats, YUVVIDEO, HEVCVIDEO),
  api_(NULL),
  config_(NULL),
  enc_(NULL),
  pts_(0),
  input_pic_(NULL),
  framerate_num_(30),
  framerate_denom_(1)
{
  maxBufferSize_ = 3;
}

void KvazaarFilter::updateSettings()
{
  qDebug() << "Updating kvazaar settings";
  close();
  if(init())
  {
    qDebug() << name_ << "Kvazaar resolution change successful";
  }
  else
  {
    qDebug() << "Failed to change resolution";
  }

  Filter::updateSettings();
}

bool KvazaarFilter::init()
{
  qDebug() << name_ << "iniating";

  // input picture should not exist at this point
  Q_ASSERT(!input_pic_ && !api_);

  api_ = kvz_api_get(8);
  if(!api_)
  {
    qCritical() << name_ << "failed to retrieve Kvazaar API";
    return false;
  }
  config_ = api_->config_alloc();
  enc_ = NULL;

  if(!config_)
  {
    qCritical() << name_ << "failed to allocate Kvazaar config";
    return false;
  }
  QSettings settings("kvazzup.ini", QSettings::IniFormat);

  api_->config_init(config_);
  api_->config_parse(config_, "preset", settings.value("video/Preset").toString().toUtf8());

  config_->width = settings.value("video/ResolutionWidth").toInt();
  config_->height = settings.value("video/ResolutionHeight").toInt();
  config_->threads = settings.value("video/kvzThreads").toInt();
  config_->qp = settings.value("video/QP").toInt();
  config_->wpp = settings.value("video/WPP").toInt();
  config_->vps_period = settings.value("video/VPS").toInt();
  config_->intra_period = settings.value("video/Intra").toInt();
  config_->framerate_num = settings.value("video/Framerate").toInt();
  config_->framerate_denom = framerate_denom_;

  if(settings.value("video/Slices").toInt() == 1)
  {
    if(config_->wpp == 0)
    {
      api_->config_parse(config_, "tiles", "2x2");
      config_->slices = KVZ_SLICES_TILES;
    }
    else
    {
      config_->slices = KVZ_SLICES_WPP;
    }
  }

  // TODO Maybe send parameter sets only when needed
  //config_->target_bitrate = target_bitrate;

  enc_ = api_->encoder_open(config_);

  if(!enc_)
  {
    qCritical() << name_ << "failed to open Kvazaar encoder";
    return false;
  }

  input_pic_ = api_->picture_alloc(config_->width, config_->height);

  if(!input_pic_)
  {
    qCritical() << name_ << "could not allocate input picture";
    return false;
  }

  qDebug() << name_ << "iniation success";
  return true;
}

void KvazaarFilter::close()
{
  if(api_)
  {
    api_->encoder_close(enc_);
    api_->config_destroy(config_);
    enc_ = NULL;
    config_ = NULL;

    api_->picture_free(input_pic_);
    input_pic_ = NULL;
    api_ = NULL;
  }
  qDebug() << name_ << "Kvazaar closed";

  pts_ = 0;
}

void KvazaarFilter::process()
{
  Q_ASSERT(enc_);
  Q_ASSERT(config_);

  std::unique_ptr<Data> input = getInput();
  while(input)
  {
    kvz_picture *recon_pic = NULL;
    kvz_frame_info frame_info;
    kvz_data_chunk *data_out = NULL;
    uint32_t len_out = 0;

    if(config_->width != input->width
       || config_->height != input->height
       || config_->framerate_num != input->framerate)
    {
      // This should not happen.
      qDebug() << name_ << "WARNING: Input resolution differs:"
               << config_->width << "x" << config_->height << "input:"
               << input->width << "x" << input->height;

      qDebug() << name_ << "Framerates:" << config_->framerate_num << "input:" << input->framerate;

      QSettings settings("kvazzup.ini", QSettings::IniFormat);
      settings.setValue("video/ResolutionWidth", input->width);
      settings.setValue("video/ResolutionHeight", input->height);
      settings.setValue("video/Framerate", input->framerate);
      updateSettings();
    }

    if(!input_pic_)
    {
      qCritical() << name_ << "input picture was not allocated correctly";
      break;
    }

    // copy input to kvazaar picture
    memcpy(input_pic_->y,
           input->data.get(),
           input->width*input->height);
    memcpy(input_pic_->u,
           &(input->data.get()[input->width*input->height]),
           input->width*input->height/4);
    memcpy(input_pic_->v,
           &(input->data.get()[input->width*input->height + input->width*input->height/4]),
           input->width*input->height/4);

    input_pic_->pts = pts_;
    ++pts_;

    api_->encoder_encode(enc_, input_pic_,
                         &data_out, &len_out,
                         &recon_pic, NULL,
                         &frame_info );

    if(data_out != NULL)
    {
      uint32_t delay = QDateTime::currentMSecsSinceEpoch() -
          (input->presentationTime.tv_sec * 1000 + input->presentationTime.tv_usec/1000);
      stats_->sendDelay("video", delay);
      stats_->addEncodedPacket("video", len_out);

      std::unique_ptr<uchar[]> hevc_frame(new uchar[len_out]);
      uint8_t* writer = hevc_frame.get();
      uint32_t dataWritten = 0;

      for (kvz_data_chunk *chunk = data_out; chunk != NULL; chunk = chunk->next)
      {
        if(chunk->first_chunk_in_slice && dataWritten != 0 && config_->slices != KVZ_SLICES_NONE)
        {
          // send previous packet if this is not the first

          // TODO: put delayes into deque, and set timestamp accordingly to get more accurate latency.
          std::unique_ptr<Data> slice(shallowDataCopy(input.get()));

          sendEncodedFrame(std::move(slice), std::move(hevc_frame), dataWritten);

          hevc_frame = std::unique_ptr<uchar[]>(new uchar[len_out - dataWritten]);
          writer = hevc_frame.get();
          dataWritten = 0;
        }

        memcpy(writer, chunk->data, chunk->len);
        writer += chunk->len;
        dataWritten += chunk->len;
      }
      api_->chunk_free(data_out);
      api_->picture_free(recon_pic);

      // send last packet reusing input structure
      sendEncodedFrame(std::move(input), std::move(hevc_frame), dataWritten);
    }
    input = getInput();
  }
}

void KvazaarFilter::sendEncodedFrame(std::unique_ptr<Data> input, std::unique_ptr<uchar[]> hevc_frame,
                                     uint32_t dataWritten)
{
  input->type = HEVCVIDEO;
  input->data_size = dataWritten;
  input->data = std::move(hevc_frame);
  sendOutput(std::move(input));
}
<commit_msg>[Dependencies] Kvazaarfilter is now compatible with the newest kvazaar and no longer requires a special version where the first chunk of slice is indicated. Its a little bit unclear why such solution was adapted in the first place.<commit_after>#include "kvazaarfilter.h"

#include "statisticsinterface.h"

#include <kvazaar.h>

#include <QSettings>
#include <QtDebug>
#include <QTime>
#include <QSize>

enum RETURN_STATUS {C_SUCCESS = 0, C_FAILURE = -1};

KvazaarFilter::KvazaarFilter(QString id, StatisticsInterface *stats):
  Filter(id, "Kvazaar", stats, YUVVIDEO, HEVCVIDEO),
  api_(NULL),
  config_(NULL),
  enc_(NULL),
  pts_(0),
  input_pic_(NULL),
  framerate_num_(30),
  framerate_denom_(1)
{
  maxBufferSize_ = 3;
}

void KvazaarFilter::updateSettings()
{
  qDebug() << "Updating kvazaar settings";
  close();
  if(init())
  {
    qDebug() << name_ << "Kvazaar resolution change successful";
  }
  else
  {
    qDebug() << "Failed to change resolution";
  }

  Filter::updateSettings();
}

bool KvazaarFilter::init()
{
  qDebug() << name_ << "iniating";

  // input picture should not exist at this point
  Q_ASSERT(!input_pic_ && !api_);

  api_ = kvz_api_get(8);
  if(!api_)
  {
    qCritical() << name_ << "failed to retrieve Kvazaar API";
    return false;
  }
  config_ = api_->config_alloc();
  enc_ = NULL;

  if(!config_)
  {
    qCritical() << name_ << "failed to allocate Kvazaar config";
    return false;
  }
  QSettings settings("kvazzup.ini", QSettings::IniFormat);

  api_->config_init(config_);
  api_->config_parse(config_, "preset", settings.value("video/Preset").toString().toUtf8());

  config_->width = settings.value("video/ResolutionWidth").toInt();
  config_->height = settings.value("video/ResolutionHeight").toInt();
  config_->threads = settings.value("video/kvzThreads").toInt();
  config_->qp = settings.value("video/QP").toInt();
  config_->wpp = settings.value("video/WPP").toInt();
  config_->vps_period = settings.value("video/VPS").toInt();
  config_->intra_period = settings.value("video/Intra").toInt();
  config_->framerate_num = settings.value("video/Framerate").toInt();
  config_->framerate_denom = framerate_denom_;

  if(settings.value("video/Slices").toInt() == 1)
  {
    if(config_->wpp == 0)
    {
      api_->config_parse(config_, "tiles", "2x2");
      config_->slices = KVZ_SLICES_TILES;
    }
    else
    {
      config_->slices = KVZ_SLICES_WPP;
    }
  }

  // TODO Maybe send parameter sets only when needed
  //config_->target_bitrate = target_bitrate;

  enc_ = api_->encoder_open(config_);

  if(!enc_)
  {
    qCritical() << name_ << "failed to open Kvazaar encoder";
    return false;
  }

  input_pic_ = api_->picture_alloc(config_->width, config_->height);

  if(!input_pic_)
  {
    qCritical() << name_ << "could not allocate input picture";
    return false;
  }

  qDebug() << name_ << "iniation success";
  return true;
}

void KvazaarFilter::close()
{
  if(api_)
  {
    api_->encoder_close(enc_);
    api_->config_destroy(config_);
    enc_ = NULL;
    config_ = NULL;

    api_->picture_free(input_pic_);
    input_pic_ = NULL;
    api_ = NULL;
  }
  qDebug() << name_ << "Kvazaar closed";

  pts_ = 0;
}

void KvazaarFilter::process()
{
  Q_ASSERT(enc_);
  Q_ASSERT(config_);

  std::unique_ptr<Data> input = getInput();
  while(input)
  {
    kvz_picture *recon_pic = NULL;
    kvz_frame_info frame_info;
    kvz_data_chunk *data_out = NULL;
    uint32_t len_out = 0;

    if(config_->width != input->width
       || config_->height != input->height
       || config_->framerate_num != input->framerate)
    {
      // This should not happen.
      qDebug() << name_ << "WARNING: Input resolution differs:"
               << config_->width << "x" << config_->height << "input:"
               << input->width << "x" << input->height;

      qDebug() << name_ << "Framerates:" << config_->framerate_num << "input:" << input->framerate;

      QSettings settings("kvazzup.ini", QSettings::IniFormat);
      settings.setValue("video/ResolutionWidth", input->width);
      settings.setValue("video/ResolutionHeight", input->height);
      settings.setValue("video/Framerate", input->framerate);
      updateSettings();
    }

    if(!input_pic_)
    {
      qCritical() << name_ << "input picture was not allocated correctly";
      break;
    }

    // copy input to kvazaar picture
    memcpy(input_pic_->y,
           input->data.get(),
           input->width*input->height);
    memcpy(input_pic_->u,
           &(input->data.get()[input->width*input->height]),
           input->width*input->height/4);
    memcpy(input_pic_->v,
           &(input->data.get()[input->width*input->height + input->width*input->height/4]),
           input->width*input->height/4);

    input_pic_->pts = pts_;
    ++pts_;

    api_->encoder_encode(enc_, input_pic_,
                         &data_out, &len_out,
                         &recon_pic, NULL,
                         &frame_info );

    // TODO: decrease latency by polling at least once more.

    if(data_out != NULL)
    {
      uint32_t delay = QDateTime::currentMSecsSinceEpoch() -
          (input->presentationTime.tv_sec * 1000 + input->presentationTime.tv_usec/1000);
      stats_->sendDelay("video", delay);
      stats_->addEncodedPacket("video", len_out);

      std::unique_ptr<uchar[]> hevc_frame(new uchar[len_out]);
      uint8_t* writer = hevc_frame.get();
      uint32_t dataWritten = 0;

      for (kvz_data_chunk *chunk = data_out; chunk != NULL; chunk = chunk->next)
      {
        if(chunk->data[0] == 0 && chunk->data[1] == 0  &&( chunk->data[2] == 1 || (chunk->data[2] == 0 && chunk->data[3] == 1 ))
           && dataWritten != 0 && config_->slices != KVZ_SLICES_NONE)
        {
          // send previous packet if this is not the first

          // TODO: put delayes into deque, and set timestamp accordingly to get more accurate latency.
          std::unique_ptr<Data> slice(shallowDataCopy(input.get()));

          sendEncodedFrame(std::move(slice), std::move(hevc_frame), dataWritten);

          hevc_frame = std::unique_ptr<uchar[]>(new uchar[len_out - dataWritten]);
          writer = hevc_frame.get();
          dataWritten = 0;
        }

        memcpy(writer, chunk->data, chunk->len);
        writer += chunk->len;
        dataWritten += chunk->len;
      }
      api_->chunk_free(data_out);
      api_->picture_free(recon_pic);

      // send last packet reusing input structure
      sendEncodedFrame(std::move(input), std::move(hevc_frame), dataWritten);
    }
    input = getInput();
  }
}

void KvazaarFilter::sendEncodedFrame(std::unique_ptr<Data> input, std::unique_ptr<uchar[]> hevc_frame,
                                     uint32_t dataWritten)
{
  input->type = HEVCVIDEO;
  input->data_size = dataWritten;
  input->data = std::move(hevc_frame);
  sendOutput(std::move(input));
}
<|endoftext|>


<commit_before>#include "gtest/gtest.h"

#include <pistache/net.h>

#include <stdexcept>
#include <iostream>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

using namespace Pistache;

TEST(net_test, port_creation)
{
    Port port1(3000);
    ASSERT_FALSE(port1.isReserved());
    uint16_t value1 = port1;
    ASSERT_EQ(value1, 3000);
    ASSERT_EQ(port1.toString(), "3000");

    Port port2(80);
    ASSERT_TRUE(port2.isReserved());
    uint16_t value2 = port2;
    ASSERT_EQ(value2, 80);
    ASSERT_EQ(port2.toString(), "80");
}

TEST(net_test, address_creation)
{
    Address address1("127.0.0.1:8080");
    ASSERT_EQ(address1.host(), "127.0.0.1");
    ASSERT_EQ(address1.port(), 8080);

    std::string addr = "127.0.0.1";
    Address address2(addr, Port(8080));
    ASSERT_EQ(address2.host(), "127.0.0.1");
    ASSERT_EQ(address2.port(), 8080);

    Address address3(Ipv4(127, 0, 0, 1), Port(8080));
    ASSERT_EQ(address3.host(), "127.0.0.1");
    ASSERT_EQ(address3.port(), 8080);

    Address address4(Ipv4::any(), Port(8080));
    ASSERT_EQ(address4.host(), "0.0.0.0");
    ASSERT_EQ(address4.port(), 8080);

    Address address5("*:8080");
    ASSERT_EQ(address5.host(), "0.0.0.0");
    ASSERT_EQ(address5.port(), 8080);

    Address address6("[::1]:8080");
    ASSERT_EQ(address6.host(), "::1");
    ASSERT_EQ(address6.port(), 8080);

    std::string addr2 = "[::1]";
    Address address7(addr2, Port(8080));
    ASSERT_EQ(address7.host(), "::1");
    ASSERT_EQ(address7.port(), 8080);

    Address address8(Ipv6(0, 0, 0, 0, 0, 0, 0, 1), Port(8080));
    ASSERT_EQ(address8.host(), "::1");
    ASSERT_EQ(address8.port(), 8080);

    Address address9(Ipv6::any(), Port(8080));
    ASSERT_EQ(address9.host(), "::");
    ASSERT_EQ(address9.port(), 8080);

    Address address10("[::]:8080");
    ASSERT_EQ(address10.host(), "::");
    ASSERT_EQ(address10.port(), 8080);

    Address address11("[2001:0DB8:AABB:CCDD:EEFF:0011:2233:4455]:8080");
    ASSERT_EQ(address11.host(), "2001:0DB8:AABB:CCDD:EEFF:0011:2233:4455");
    ASSERT_EQ(address11.port(), 8080);

    Address address12(Ipv4::loopback(), Port(8080));
    ASSERT_EQ(address12.host(), "127.0.0.1");
    ASSERT_EQ(address12.port(), 8080);

    Address address13(Ipv6::loopback(), Port(8080));
    ASSERT_EQ(address13.host(), "::1");
    ASSERT_EQ(address13.port(), 8080);

    Address address14("127.0.0.1");
    ASSERT_EQ(address14.host(), "127.0.0.1");
    ASSERT_EQ(address14.port(), 80);

    Address address15("www.example.com");
    ASSERT_EQ(address15.host(), "93.184.216.34");
    ASSERT_EQ(address15.port(), 80);
}

TEST(net_test, invalid_address)
{
    ASSERT_THROW(Address("127.0.0.1:9999999"), std::invalid_argument);
    ASSERT_THROW(Address("127.0.0.1:"), std::invalid_argument);
    ASSERT_THROW(Address("127.0.0.1:-10"), std::invalid_argument);

    ASSERT_THROW(Address("[GGGG:GGGG:GGGG:GGGG:GGGG:GGGG:GGGG:GGGG]:8080");, std::invalid_argument);
    ASSERT_THROW(Address("[::GGGG]:8080");, std::invalid_argument);
    ASSERT_THROW(Address("256.256.256.256:8080");, std::invalid_argument);
    ASSERT_THROW(Address("1.0.0.256:8080");, std::invalid_argument);
}

TEST(net_test, address_parser)
{
    AddressParser ap1("127.0.0.1:80");
    ASSERT_EQ(ap1.rawHost(), "127.0.0.1");
    ASSERT_EQ(ap1.rawPort(), "80");
    ASSERT_EQ(ap1.family(), AF_INET);
    ASSERT_EQ(ap1.hasColon(), true);

    AddressParser ap2("example.com");
    ASSERT_EQ(ap2.rawHost(), "example.com");
    ASSERT_EQ(ap2.rawPort(), "");
    ASSERT_EQ(ap2.family(), AF_INET);
    ASSERT_EQ(ap2.hasColon(), false);

    AddressParser ap3("[2001:0DB8:AABB:CCDD:EEFF:0011:2233:4455]:8080");
    ASSERT_EQ(ap3.rawHost(), "[2001:0DB8:AABB:CCDD:EEFF:0011:2233:4455]");
    ASSERT_EQ(ap3.rawPort(), "8080");
    ASSERT_EQ(ap3.family(), AF_INET6);

    ASSERT_THROW(AddressParser("127.0.0.1:");, std::invalid_argument);
    ASSERT_THROW(AddressParser("[::]:");, std::invalid_argument);
}
<commit_msg>Fixes to tests and additional tests<commit_after>#include "gtest/gtest.h"

#include <pistache/net.h>

#include <stdexcept>
#include <iostream>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

using namespace Pistache;

TEST(net_test, port_creation)
{
    Port port1(3000);
    ASSERT_FALSE(port1.isReserved());
    uint16_t value1 = port1;
    ASSERT_EQ(value1, 3000);
    ASSERT_EQ(port1.toString(), "3000");

    Port port2(80);
    ASSERT_TRUE(port2.isReserved());
    uint16_t value2 = port2;
    ASSERT_EQ(value2, 80);
    ASSERT_EQ(port2.toString(), "80");
}

TEST(net_test, address_creation)
{
    Address address1("127.0.0.1:8080");
    ASSERT_EQ(address1.host(), "127.0.0.1");
    ASSERT_EQ(address1.family(), AF_INET);
    ASSERT_EQ(address1.port(), 8080);

    std::string addr = "127.0.0.1";
    Address address2(addr, Port(8080));
    ASSERT_EQ(address2.host(), "127.0.0.1");
    ASSERT_EQ(address2.family(), AF_INET);
    ASSERT_EQ(address2.port(), 8080);

    Address address3(Ipv4(127, 0, 0, 1), Port(8080));
    ASSERT_EQ(address3.host(), "127.0.0.1");
    ASSERT_EQ(address3.family(), AF_INET);
    ASSERT_EQ(address3.port(), 8080);

    Address address4(Ipv4::any(), Port(8080));
    ASSERT_EQ(address4.host(), "0.0.0.0");
    ASSERT_EQ(address4.family(), AF_INET);
    ASSERT_EQ(address4.port(), 8080);

    Address address5("*:8080");
    ASSERT_EQ(address5.host(), "0.0.0.0");
    ASSERT_EQ(address5.family(), AF_INET);
    ASSERT_EQ(address5.port(), 8080);

    Address address6("[::1]:8080");
    ASSERT_EQ(address6.host(), "::1");
    ASSERT_EQ(address6.family(), AF_INET6);
    ASSERT_EQ(address6.port(), 8080);

    std::string addr2 = "[::1]";
    Address address7(addr2, Port(8080));
    ASSERT_EQ(address7.host(), "::1");
    ASSERT_EQ(address7.family(), AF_INET6);
    ASSERT_EQ(address7.port(), 8080);

    Address address8(Ipv6(0, 0, 0, 0, 0, 0, 0, 1), Port(8080));
    ASSERT_EQ(address8.host(), "::1");
    ASSERT_EQ(address8.family(), AF_INET6);
    ASSERT_EQ(address8.port(), 8080);

    Address address9(Ipv6::any(true), Port(8080));
    ASSERT_EQ(address9.host(), "::");
    ASSERT_EQ(address9.family(), AF_INET6);
    ASSERT_EQ(address9.port(), 8080);

    Address address10("[::]:8080");
    ASSERT_EQ(address10.host(), "::");
    ASSERT_EQ(address10.family(), AF_INET6);
    ASSERT_EQ(address10.port(), 8080);

    Address address11("[2001:0DB8:AABB:CCDD:EEFF:0011:2233:4455]:8080");
    ASSERT_EQ(address11.host(), "2001:0DB8:AABB:CCDD:EEFF:0011:2233:4455");
    ASSERT_EQ(address11.family(), AF_INET6);
    ASSERT_EQ(address11.port(), 8080);

    Address address12(Ipv4::loopback(), Port(8080));
    ASSERT_EQ(address12.host(), "127.0.0.1");
    ASSERT_EQ(address12.family(), AF_INET);
    ASSERT_EQ(address12.port(), 8080);

    Address address13(Ipv6::loopback(true), Port(8080));
    ASSERT_EQ(address13.host(), "::1");
    ASSERT_EQ(address13.family(), AF_INET6);
    ASSERT_EQ(address13.port(), 8080);

    Address address14("127.0.0.1");
    ASSERT_EQ(address14.host(), "127.0.0.1");
    ASSERT_EQ(address14.family(), AF_INET);
    ASSERT_EQ(address14.port(), 80);

    Address address15("www.example.com");
    ASSERT_EQ(address15.host(), "93.184.216.34");
    ASSERT_EQ(address15.family(), AF_INET);
    ASSERT_EQ(address15.port(), 80);

    Address address16(IP(127, 0, 0, 1), Port(8080));
    ASSERT_EQ(address16.host(), "127.0.0.1");
    ASSERT_EQ(address16.family(), AF_INET);
    ASSERT_EQ(address16.port(), 8080);

    Address address17(IP::any(), Port(8080));
    ASSERT_EQ(address17.host(), "0.0.0.0");
    ASSERT_EQ(address17.family(), AF_INET);
    ASSERT_EQ(address17.port(), 8080);

    Address address18(IP(2, 0, 0, 0, 0, 0, 0, 1), Port(8080));
    ASSERT_EQ(address18.host(), "2::1");
    ASSERT_EQ(address18.family(), AF_INET6);
    ASSERT_EQ(address18.port(), 8080);

    Address address19(IP::any(true), Port(8080));
    ASSERT_EQ(address19.host(), "::");
    ASSERT_EQ(address19.family(), AF_INET6);
    ASSERT_EQ(address19.port(), 8080);

    Address address20(IP::loopback(true), Port(8080));
    ASSERT_EQ(address20.host(), "::1");
    ASSERT_EQ(address20.family(), AF_INET6);
    ASSERT_EQ(address20.port(), 8080);

    Address address21(IP::loopback(true), Port(8080));
    ASSERT_EQ(address21.host(), "127.0.0.1");
    ASSERT_EQ(address21.family(), AF_INET);
    ASSERT_EQ(address21.port(), 8080);

}

TEST(net_test, invalid_address)
{
    ASSERT_THROW(Address("127.0.0.1:9999999"), std::invalid_argument);
    ASSERT_THROW(Address("127.0.0.1:"), std::invalid_argument);
    ASSERT_THROW(Address("127.0.0.1:-10"), std::invalid_argument);

    ASSERT_THROW(Address("[GGGG:GGGG:GGGG:GGGG:GGGG:GGGG:GGGG:GGGG]:8080");, std::invalid_argument);
    ASSERT_THROW(Address("[::GGGG]:8080");, std::invalid_argument);
    ASSERT_THROW(Address("256.256.256.256:8080");, std::invalid_argument);
    ASSERT_THROW(Address("1.0.0.256:8080");, std::invalid_argument);
}

TEST(net_test, address_parser)
{
    AddressParser ap1("127.0.0.1:80");
    ASSERT_EQ(ap1.rawHost(), "127.0.0.1");
    ASSERT_EQ(ap1.rawPort(), "80");
    ASSERT_EQ(ap1.family(), AF_INET);
    ASSERT_EQ(ap1.hasColon(), true);

    AddressParser ap2("example.com");
    ASSERT_EQ(ap2.rawHost(), "example.com");
    ASSERT_EQ(ap2.rawPort(), "");
    ASSERT_EQ(ap2.family(), AF_INET);
    ASSERT_EQ(ap2.hasColon(), false);

    AddressParser ap3("[2001:0DB8:AABB:CCDD:EEFF:0011:2233:4455]:8080");
    ASSERT_EQ(ap3.rawHost(), "[2001:0DB8:AABB:CCDD:EEFF:0011:2233:4455]");
    ASSERT_EQ(ap3.rawPort(), "8080");
    ASSERT_EQ(ap3.family(), AF_INET6);

    ASSERT_THROW(AddressParser("127.0.0.1:");, std::invalid_argument);
    ASSERT_THROW(AddressParser("[::]:");, std::invalid_argument);
}
<|endoftext|>


<commit_before>/**
 * Appcelerator Kroll - licensed under the Apache Public License 2
 * see LICENSE in the root folder for details on the license.
 * Copyright (c) 2008 Appcelerator, Inc. All Rights Reserved.
 */
#include <iostream>
#include <vector>
#include <cstring>
#include <dlfcn.h>
#include <string>
#import <Cocoa/Cocoa.h>
#include "host.h"

namespace kroll
{
	OSXHost::OSXHost(int _argc, const char **_argv) : Host(_argc,_argv)
	{
	}

	OSXHost::~OSXHost()
	{
	}

	const char* OSXHost::GetPlatform()
	{
		return "osx";
	}

	const char* OSXHost::GetModuleSuffix()
	{
		return "module.dylib";
	}

	bool OSXHost::Start()
	{
		Host::Start();
		NSApplication *app = [NSApplication sharedApplication];
		[app finishLaunching];
		return true;
	}

	bool OSXHost::RunLoop()
	{
		NSApplication *app = [NSApplication sharedApplication];
		// we pull out an event from the queue, blocking a little bit before returning
		try
		{
			@try
			{
				NSEvent *event = [app nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate dateWithTimeIntervalSinceNow:10] inMode:NSDefaultRunLoopMode dequeue:YES];
				if (event)
				{
					[app sendEvent:event];
				}
			}
			@catch(NSException *e)
			{
				std::cerr << "Caught NSException in main loop: " << [[e reason] UTF8String] << std::endl;
			}
		}
		catch (std::exception &e)
		{
			std::cerr << "Caught exception in main loop: " << e.what() << std::endl;
		}
		catch (...)
		{
			std::cerr << "Caught unhandled exception in main loop: " << std::endl;
		}
		return true;
	}

	Module* OSXHost::CreateModule(std::string& path)
	{
		void* lib_handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_GLOBAL);
		if (!lib_handle)
		{
			std::cerr << "Error load module: " << path << ", error: " << dlerror() << std::endl;
			return 0;
		}

		// get the module factory
		ModuleCreator* create = (ModuleCreator*)dlsym(lib_handle, "CreateModule");
		if (!create)
		{
			std::cerr << "Error load create entry from module: " << path << std::endl;
			return 0;
		}

		std::string dir = FileUtils::GetDirectory(path);
		return create(this,dir.c_str());
	}
}

@interface KrollMainThreadCaller : NSObject
{
	kroll::BoundMethod *method;
	SharedPtr<kroll::Value> *result;
	const ValueList* args;
	SharedPtr<kroll::Value> *exception;
}
- (id)initWithBoundMethod:(SharedPtr<kroll::BoundMethod>)method args:(const ValueList*)args;
- (void)call;
- (SharedPtr<kroll::Value>)getResult;
- (SharedPtr<kroll::Value>)getException;
@end

@implementation KrollMainThreadCaller
- (id)initWithBoundMethod:(SharedPtr<kroll::BoundMethod>)m args:(const ValueList*)a
{
	self = [super init];
	if (self)
	{
		method = m.get();
		args = a;
		result = new SharedPtr<kroll::Value>();
		exception = new SharedPtr<kroll::Value>();
	}
	return self;
}
- (void)dealloc
{
	delete result;
	delete exception;
	[super dealloc];
}
- (SharedPtr<kroll::Value>)getResult
{
	return *result;
}
- (SharedPtr<kroll::Value>)getException
{
	return *exception;
}
- (void)call
{
	try
	{
		result->assign(method->Call(*args));
	}
	catch (ValueException &e)
	{
		exception->assign(e.GetValue());
	}
	catch (std::exception &e)
	{
		exception->assign(Value::NewString(e.what()));
	}
	catch (...)
	{
		exception->assign(Value::NewString("unhandled exception"));
	}
}
@end

namespace kroll
{
	SharedValue OSXHost::InvokeMethodOnMainThread(SharedBoundMethod method,
	                                              const ValueList& args)
	{
		// make sure to just invoke if we're already on the
		// main thread
		if ([NSThread isMainThread])
		{
			return method->Call(args);
		}
		NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
		KrollMainThreadCaller *caller = [[[KrollMainThreadCaller alloc] initWithBoundMethod:method args:&args] autorelease];
		[caller performSelectorOnMainThread:@selector(call) withObject:nil waitUntilDone:YES];
		SharedValue exception = [caller getException];
		if (exception.isNull())
		{
			SharedValue result = [caller getResult];
			[pool release];
			return result;
		}
		[pool release];
		return exception;
	}
}

extern "C"
{
	int Execute(int argc,const char **argv)
	{
		kroll::Host *host = new kroll::OSXHost(argc,argv);
		return host->Run();
	}
}
<commit_msg>minor osx event loop update found from more examples on net<commit_after>/**
 * Appcelerator Kroll - licensed under the Apache Public License 2
 * see LICENSE in the root folder for details on the license.
 * Copyright (c) 2008 Appcelerator, Inc. All Rights Reserved.
 */
#include <iostream>
#include <vector>
#include <cstring>
#include <dlfcn.h>
#include <string>
#import <Cocoa/Cocoa.h>
#include "host.h"

namespace kroll
{
	OSXHost::OSXHost(int _argc, const char **_argv) : Host(_argc,_argv)
	{
	}

	OSXHost::~OSXHost()
	{
	}

	const char* OSXHost::GetPlatform()
	{
		return "osx";
	}

	const char* OSXHost::GetModuleSuffix()
	{
		return "module.dylib";
	}

	bool OSXHost::Start()
	{
		Host::Start();
		NSApplication *app = [NSApplication sharedApplication];
		[app finishLaunching];
		return true;
	}

	bool OSXHost::RunLoop()
	{
		NSApplication *app = [NSApplication sharedApplication];
		// we pull out an event from the queue, blocking a little bit before returning
		try
		{
			@try
			{
				NSEvent *event = [app nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantFuture] inMode:NSDefaultRunLoopMode dequeue:YES];
				if (event)
				{
					[app sendEvent:event];
					[app updateWindows];
				}
			}
			@catch(NSException *e)
			{
				std::cerr << "Caught NSException in main loop: " << [[e reason] UTF8String] << std::endl;
			}
		}
		catch (std::exception &e)
		{
			std::cerr << "Caught exception in main loop: " << e.what() << std::endl;
		}
		catch (...)
		{
			std::cerr << "Caught unhandled exception in main loop: " << std::endl;
		}
		return true;
	}

	Module* OSXHost::CreateModule(std::string& path)
	{
		void* lib_handle = dlopen(path.c_str(), RTLD_LAZY | RTLD_GLOBAL);
		if (!lib_handle)
		{
			std::cerr << "Error load module: " << path << ", error: " << dlerror() << std::endl;
			return 0;
		}

		// get the module factory
		ModuleCreator* create = (ModuleCreator*)dlsym(lib_handle, "CreateModule");
		if (!create)
		{
			std::cerr << "Error load create entry from module: " << path << std::endl;
			return 0;
		}

		std::string dir = FileUtils::GetDirectory(path);
		return create(this,dir.c_str());
	}
}

@interface KrollMainThreadCaller : NSObject
{
	kroll::BoundMethod *method;
	SharedPtr<kroll::Value> *result;
	const ValueList* args;
	SharedPtr<kroll::Value> *exception;
}
- (id)initWithBoundMethod:(SharedPtr<kroll::BoundMethod>)method args:(const ValueList*)args;
- (void)call;
- (SharedPtr<kroll::Value>)getResult;
- (SharedPtr<kroll::Value>)getException;
@end

@implementation KrollMainThreadCaller
- (id)initWithBoundMethod:(SharedPtr<kroll::BoundMethod>)m args:(const ValueList*)a
{
	self = [super init];
	if (self)
	{
		method = m.get();
		args = a;
		result = new SharedPtr<kroll::Value>();
		exception = new SharedPtr<kroll::Value>();
	}
	return self;
}
- (void)dealloc
{
	delete result;
	delete exception;
	[super dealloc];
}
- (SharedPtr<kroll::Value>)getResult
{
	return *result;
}
- (SharedPtr<kroll::Value>)getException
{
	return *exception;
}
- (void)call
{
	try
	{
		result->assign(method->Call(*args));
	}
	catch (ValueException &e)
	{
		exception->assign(e.GetValue());
	}
	catch (std::exception &e)
	{
		exception->assign(Value::NewString(e.what()));
	}
	catch (...)
	{
		exception->assign(Value::NewString("unhandled exception"));
	}
}
@end

namespace kroll
{
	SharedValue OSXHost::InvokeMethodOnMainThread(SharedBoundMethod method,
	                                              const ValueList& args)
	{
		// make sure to just invoke if we're already on the
		// main thread
		if ([NSThread isMainThread])
		{
			return method->Call(args);
		}
		NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
		KrollMainThreadCaller *caller = [[[KrollMainThreadCaller alloc] initWithBoundMethod:method args:&args] autorelease];
		[caller performSelectorOnMainThread:@selector(call) withObject:nil waitUntilDone:YES];
		SharedValue exception = [caller getException];
		if (exception.isNull())
		{
			SharedValue result = [caller getResult];
			[pool release];
			return result;
		}
		[pool release];
		return exception;
	}
}

extern "C"
{
	int Execute(int argc,const char **argv)
	{
		kroll::Host *host = new kroll::OSXHost(argc,argv);
		return host->Run();
	}
}
<|endoftext|>


<commit_before>#include <iostream>
#include <vector>

#include "host_window.h"

/**
 * @brief Functor returning a gaussian
 * \f[
   f(x,y) = Ae^{-(\frac{(x-x_0)^2}{2\sigma_x^2} + \frac{(y-y_0)^2}{2\sigma_y^2}}
   \f]
 */
struct Gaussian
{
    /**
     * @brief Functor returning a gaussian
     *
     * @param x0 x-center-coordinate
     * @param y0 y-center-coordinate
     * @param sigma_x x - variance
     * @param sigma_y y - variance
     * @param amp Amplitude
     */
    Gaussian( double x0, double y0, double sigma_x, double sigma_y, double amp)
        : x00(x0), y00(y0), sigma_x(sigma_x), sigma_y(sigma_y), amplitude(amp){}
    /**
     * @brief Return the value of the gaussian
     *
     * \f[
       f(x,y) = Ae^{-(\frac{(x-x_0)^2}{2\sigma_x^2} + \frac{(y-y_0)^2}{2\sigma_y^2}}
       \f]
     * @param x x - coordinate
     * @param y y - coordinate
     *
     * @return gaussian
     */
    double operator()(double x, double y)
    {
        return  amplitude*
                   exp( -((x-x00)*(x-x00)/2./sigma_x/sigma_x +
                          (y-y00)*(y-y00)/2./sigma_y/sigma_y) );
    }
  private:
    double  x00, y00, sigma_x, sigma_y, amplitude;

};

const unsigned Nx = 7000, Ny = 4000;
const double lx = 2., ly = 2.;
const double hx = lx/(double)Nx, hy = ly/(double)Ny;

int main()
{
    //Create Window and set window title
    GLFWwindow* w = draw::glfwInitAndCreateWindow( 400, 800, "Hello world!");
    draw::RenderHostData render( 2, 1);
    // generate a vector on the grid to visualize
    Gaussian g( 1.2, 0.3, .1, .1, 1);
    std::vector<float> visual(Nx*Ny);
    for(unsigned i=0; i<Ny; i++)
        for( unsigned j=0; j<Nx; j++)
            visual[i*Nx+j] = -g( (double)j*hx, (double)i*hy);

    //create a colormap
    draw::ColorMapRedBlueExt colors( 1.);
    //set scale
    colors.scale() =  1.;
    while (!glfwWindowShouldClose( w ))
    {
        render.renderQuad( visual.begin(), visual.end(), Nx, Ny, colors);
        render.renderQuad( visual.begin(), visual.end(), Nx, Ny, colors);
        glfwSwapBuffers(w);
        glfwWaitEvents();
    }
    glfwTerminate();

    return 0;
}
<commit_msg>error in test file<commit_after>#include <iostream>
#include <vector>

#include "host_window.h"

/**
 * @brief Functor returning a gaussian
 * \f[
   f(x,y) = Ae^{-(\frac{(x-x_0)^2}{2\sigma_x^2} + \frac{(y-y_0)^2}{2\sigma_y^2}}
   \f]
 */
struct Gaussian
{
    /**
     * @brief Functor returning a gaussian
     *
     * @param x0 x-center-coordinate
     * @param y0 y-center-coordinate
     * @param sigma_x x - variance
     * @param sigma_y y - variance
     * @param amp Amplitude
     */
    Gaussian( double x0, double y0, double sigma_x, double sigma_y, double amp)
        : x00(x0), y00(y0), sigma_x(sigma_x), sigma_y(sigma_y), amplitude(amp){}
    /**
     * @brief Return the value of the gaussian
     *
     * \f[
       f(x,y) = Ae^{-(\frac{(x-x_0)^2}{2\sigma_x^2} + \frac{(y-y_0)^2}{2\sigma_y^2}}
       \f]
     * @param x x - coordinate
     * @param y y - coordinate
     *
     * @return gaussian
     */
    double operator()(double x, double y)
    {
        return  amplitude*
                   exp( -((x-x00)*(x-x00)/2./sigma_x/sigma_x +
                          (y-y00)*(y-y00)/2./sigma_y/sigma_y) );
    }
  private:
    double  x00, y00, sigma_x, sigma_y, amplitude;

};

const unsigned Nx = 7000, Ny = 4000;
const double lx = 2., ly = 2.;
const double hx = lx/(double)Nx, hy = ly/(double)Ny;

int main()
{
    //Create Window and set window title
    GLFWwindow* w = draw::glfwInitAndCreateWindow( 400, 800, "Hello world!");
    draw::RenderHostData render( 2, 1);
    // generate a vector on the grid to visualize
    Gaussian g( 1.2, 0.3, .1, .1, 1);
    std::vector<float> visual(Nx*Ny);
    for(unsigned i=0; i<Ny; i++)
        for( unsigned j=0; j<Nx; j++)
            visual[i*Nx+j] = -g( (double)j*hx, (double)i*hy);

    //create a colormap
    draw::ColorMapRedBlueExt colors( 1.);
    //set scale
    colors.scale() =  1.;
    while (!glfwWindowShouldClose( w ))
    {
        render.renderQuad( visual, Nx, Ny, colors);
        render.renderQuad( visual, Nx, Ny, colors);
        glfwSwapBuffers(w);
        glfwWaitEvents();
    }
    glfwTerminate();

    return 0;
}
<|endoftext|>


<commit_before>/*****************************************************************************************
 *                                                                                *
 * OpenSpace                                                                             *
 *                                                                                *
 * Copyright (c) 2014-2022                                                               *
 *                                                                                *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this  *
 * software and associated documentation files (the "Software"), to deal in the Software *
 * without restriction, including without limitation the rights to use, copy, modify,    *
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to    *
 * permit persons to whom the Software is furnished to do so, subject to the following   *
 * conditions:                                                                           *
 *                                                                                *
 * The above copyright notice and this permission notice shall be included in all copies *
 * or substantial portions of the Software.                                              *
 *                                                                                *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,   *
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A         *
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT    *
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  *
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE  *
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                         *
 ****************************************************************************************/

#include <modules/sync/syncs/urlsynchronization.h>

#include <openspace/documentation/documentation.h>
#include <openspace/documentation/verifier.h>
#include <openspace/util/httprequest.h>
#include <ghoul/logging/logmanager.h>
#include <numeric>
#include <mutex>
#include <optional>
#include <unordered_map>
#include <variant>

namespace {
    constexpr const char* TempSuffix = ".tmp";

    struct [[codegen::Dictionary(UrlSynchronization)]] Parameters {
        // The URL or urls from where the files are downloaded. If multiple URLs are
        // provided, all files will be downloaded to the same directory and the filename
        // parameter must not be specified simultaneously
        std::variant<std::string, std::vector<std::string>> url;

        // This identifier will be part of the used folder structure and, can be used to
        // manually find the downloaded folder in the synchronization folder
        std::string identifier;

        // If this value is set to 'true' and it is not overwritten by the global
        // settings, the file(s) pointed to by this URLSynchronization will always be
        // downloaded, thus overwriting the local files. This is useful for files that are
        // updated regularly remotely and should be fetch at every startup
        std::optional<bool> forceOverride [[codegen::key("Override")]];

        // If this value is set to 'true' (the default), the hash of the URL is appended
        // to the directory name to produce a unique directory under all circumstances. If
        // this is not desired, the URLSynchronization use the bare directory name alone
        // if this value is 'false'. If this value is 'false', the identifier has to be
        // specified
        std::optional<bool> useHash;

        // Optional to provide filename to override the one which is otherwise
        // automatically created from the url. If this value is specified, the url
        // parameter only only contain exactly one URL
        std::optional<std::string> filename;
    };
#include "urlsynchronization_codegen.cpp"
} // namespace

namespace openspace {

documentation::Documentation UrlSynchronization::Documentation() {
    return codegen::doc<Parameters>("sync_synchronization_url");
}

UrlSynchronization::UrlSynchronization(const ghoul::Dictionary& dictionary,
                                       std::filesystem::path synchronizationRoot)
    : ResourceSynchronization(std::move(synchronizationRoot))
{
    const Parameters p = codegen::bake<Parameters>(dictionary);

    if (std::holds_alternative<std::string>(p.url)) {
        _urls.push_back(std::get<std::string>(p.url));

    }
    else if (std::holds_alternative<std::vector<std::string>>(p.url)) {
        _urls = std::get<std::vector<std::string>>(p.url);
    }
    else {
        throw ghoul::MissingCaseException();
    }

    if (p.filename.has_value() && _urls.size() > 1) {
        throw ghoul::RuntimeError(fmt::format(
            "UrlSynchronization ({}) requested overwrite filename but specified {} URLs "
            "to download, which is not legal",
            p.identifier, _urls.size()
        ));
    }
    _filename = p.filename.value_or(_filename);
    _forceOverride = p.forceOverride.value_or(_forceOverride);

    const bool useHash = p.useHash.value_or(true);

    _identifier = p.identifier;

    if (useHash) {
        // We just merge all of the URLs together to generate a hash that works for this
        std::vector<std::string> urls = _urls;
        std::sort(urls.begin(), urls.end());

        size_t hash = std::hash<std::string>{}(
            std::accumulate(urls.begin(), urls.end(), std::string())
        );
        _identifier += fmt::format("({})", hash);
    }
}

UrlSynchronization::~UrlSynchronization() {
    if (_syncThread.joinable()) {
        cancel();
        _syncThread.join();
    }
}

std::filesystem::path UrlSynchronization::directory() const {
    return _synchronizationRoot / "url" / _identifier / "files";
}

void UrlSynchronization::start() {
    if (isSyncing()) {
        return;
    }
    _state = State::Syncing;

    if (hasSyncFile() && !_forceOverride) {
        _state = State::Resolved;
        return;
    }

    _syncThread = std::thread([this]() {
        std::unordered_map<std::string, size_t> fileSizes;
        std::mutex fileSizeMutex;
        size_t nDownloads = 0;
        std::atomic_bool startedAllDownloads = false;
        std::vector<std::unique_ptr<HttpFileDownload>> downloads;

        for (const std::string& url : _urls) {
            if (_filename.empty()) {
                std::string name = std::filesystem::path(url).filename().string();

                // We can not create filenames with question marks
                name.erase(std::remove(name.begin(), name.end(), '?'), name.end());
                _filename = name;
            }
            std::filesystem::path destination = directory() / (_filename + TempSuffix);

            auto download = std::make_unique<HttpFileDownload>(
                url,
                destination,
                HttpFileDownload::Overwrite::Yes
            );
            HttpFileDownload* dl = download.get();

            downloads.push_back(std::move(download));

            ++nDownloads;

            dl->onProgress(
                [this, url, &fileSizes, &fileSizeMutex,
                &startedAllDownloads, &nDownloads](int64_t,
                                                   std::optional<int64_t> totalBytes)
            {
                if (!totalBytes.has_value()) {
                    return !_shouldCancel;
                }

                std::lock_guard guard(fileSizeMutex);
                fileSizes[url] = *totalBytes;

                if (!_nTotalBytesKnown && startedAllDownloads &&
                    fileSizes.size() == nDownloads)
                {
                    _nTotalBytesKnown = true;
                    _nTotalBytes = 0;
                    for (const std::pair<const std::string, size_t>& fs : fileSizes) {
                        _nTotalBytes += fs.second;
                    }
                }
                return !_shouldCancel;
            });

            dl->start();
        }

        startedAllDownloads = true;

        bool failed = false;
        for (const std::unique_ptr<HttpFileDownload>& d : downloads) {
            d->wait();
            if (!d->hasSucceeded()) {
                failed = true;
                continue;
            }

            // If we are forcing the override, we download to a temporary file first, so
            // when we are done here, we need to rename the file to the original name

            std::filesystem::path tempName = d->destination();
            std::filesystem::path originalName = tempName;
            // Remove the .tmp extension
            originalName.replace_extension("");

            if (std::filesystem::is_regular_file(originalName)) {
                std::filesystem::remove(originalName);
            }

            std::error_code ec;
            std::filesystem::rename(tempName, originalName, ec);
            if (ec) {
                LERRORC(
                    "URLSynchronization",
                    fmt::format("Error renaming file {} to {}", tempName, originalName)
                );

                failed = true;
            }
        }

        if (!failed) {
            createSyncFile();
        }
        else {
            for (const std::unique_ptr<HttpFileDownload>& d : downloads) {
                d->cancel();
            }
        }
        _state = State::Resolved;
    });
}

void UrlSynchronization::cancel() {
    _shouldCancel = true;
    _state = State::Unsynced;
}

std::string UrlSynchronization::generateUid() {
    return _identifier;
}

} // namespace openspace
<commit_msg>Fix filename when downloading multiple files in urlsync<commit_after>/*****************************************************************************************
 *                                                                                *
 * OpenSpace                                                                             *
 *                                                                                *
 * Copyright (c) 2014-2022                                                               *
 *                                                                                *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this  *
 * software and associated documentation files (the "Software"), to deal in the Software *
 * without restriction, including without limitation the rights to use, copy, modify,    *
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to    *
 * permit persons to whom the Software is furnished to do so, subject to the following   *
 * conditions:                                                                           *
 *                                                                                *
 * The above copyright notice and this permission notice shall be included in all copies *
 * or substantial portions of the Software.                                              *
 *                                                                                *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,   *
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A         *
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT    *
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF  *
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE  *
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                                         *
 ****************************************************************************************/

#include <modules/sync/syncs/urlsynchronization.h>

#include <openspace/documentation/documentation.h>
#include <openspace/documentation/verifier.h>
#include <openspace/util/httprequest.h>
#include <ghoul/logging/logmanager.h>
#include <numeric>
#include <mutex>
#include <optional>
#include <unordered_map>
#include <variant>

namespace {
    constexpr const char* TempSuffix = ".tmp";

    struct [[codegen::Dictionary(UrlSynchronization)]] Parameters {
        // The URL or urls from where the files are downloaded. If multiple URLs are
        // provided, all files will be downloaded to the same directory and the filename
        // parameter must not be specified simultaneously
        std::variant<std::string, std::vector<std::string>> url;

        // This identifier will be part of the used folder structure and, can be used to
        // manually find the downloaded folder in the synchronization folder
        std::string identifier;

        // If this value is set to 'true' and it is not overwritten by the global
        // settings, the file(s) pointed to by this URLSynchronization will always be
        // downloaded, thus overwriting the local files. This is useful for files that are
        // updated regularly remotely and should be fetch at every startup
        std::optional<bool> forceOverride [[codegen::key("Override")]];

        // If this value is set to 'true' (the default), the hash of the URL is appended
        // to the directory name to produce a unique directory under all circumstances. If
        // this is not desired, the URLSynchronization use the bare directory name alone
        // if this value is 'false'. If this value is 'false', the identifier has to be
        // specified
        std::optional<bool> useHash;

        // Optional to provide filename to override the one which is otherwise
        // automatically created from the url. If this value is specified, the url
        // parameter only only contain exactly one URL
        std::optional<std::string> filename;
    };
#include "urlsynchronization_codegen.cpp"
} // namespace

namespace openspace {

documentation::Documentation UrlSynchronization::Documentation() {
    return codegen::doc<Parameters>("sync_synchronization_url");
}

UrlSynchronization::UrlSynchronization(const ghoul::Dictionary& dictionary,
                                       std::filesystem::path synchronizationRoot)
    : ResourceSynchronization(std::move(synchronizationRoot))
{
    const Parameters p = codegen::bake<Parameters>(dictionary);

    if (std::holds_alternative<std::string>(p.url)) {
        _urls.push_back(std::get<std::string>(p.url));

    }
    else if (std::holds_alternative<std::vector<std::string>>(p.url)) {
        _urls = std::get<std::vector<std::string>>(p.url);
    }
    else {
        throw ghoul::MissingCaseException();
    }

    if (p.filename.has_value() && _urls.size() > 1) {
        throw ghoul::RuntimeError(fmt::format(
            "UrlSynchronization ({}) requested overwrite filename but specified {} URLs "
            "to download, which is not legal",
            p.identifier, _urls.size()
        ));
    }
    _filename = p.filename.value_or(_filename);
    _forceOverride = p.forceOverride.value_or(_forceOverride);

    const bool useHash = p.useHash.value_or(true);

    _identifier = p.identifier;

    if (useHash) {
        // We just merge all of the URLs together to generate a hash that works for this
        std::vector<std::string> urls = _urls;
        std::sort(urls.begin(), urls.end());

        size_t hash = std::hash<std::string>{}(
            std::accumulate(urls.begin(), urls.end(), std::string())
        );
        _identifier += fmt::format("({})", hash);
    }
}

UrlSynchronization::~UrlSynchronization() {
    if (_syncThread.joinable()) {
        cancel();
        _syncThread.join();
    }
}

std::filesystem::path UrlSynchronization::directory() const {
    return _synchronizationRoot / "url" / _identifier / "files";
}

void UrlSynchronization::start() {
    if (isSyncing()) {
        return;
    }
    _state = State::Syncing;

    if (hasSyncFile() && !_forceOverride) {
        _state = State::Resolved;
        return;
    }

    _syncThread = std::thread([this]() {
        std::unordered_map<std::string, size_t> fileSizes;
        std::mutex fileSizeMutex;
        size_t nDownloads = 0;
        std::atomic_bool startedAllDownloads = false;
        std::vector<std::unique_ptr<HttpFileDownload>> downloads;

        for (const std::string& url : _urls) {
            if (_filename.empty() || _urls.size() > 1) {
                std::string name = std::filesystem::path(url).filename().string();

                // We can not create filenames with question marks
                name.erase(std::remove(name.begin(), name.end(), '?'), name.end());
                _filename = name;
            }
            std::filesystem::path destination = directory() / (_filename + TempSuffix);

            auto download = std::make_unique<HttpFileDownload>(
                url,
                destination,
                HttpFileDownload::Overwrite::Yes
            );
            HttpFileDownload* dl = download.get();

            downloads.push_back(std::move(download));

            ++nDownloads;

            dl->onProgress(
                [this, url, &fileSizes, &fileSizeMutex,
                &startedAllDownloads, &nDownloads](int64_t,
                                                   std::optional<int64_t> totalBytes)
            {
                if (!totalBytes.has_value()) {
                    return !_shouldCancel;
                }

                std::lock_guard guard(fileSizeMutex);
                fileSizes[url] = *totalBytes;

                if (!_nTotalBytesKnown && startedAllDownloads &&
                    fileSizes.size() == nDownloads)
                {
                    _nTotalBytesKnown = true;
                    _nTotalBytes = 0;
                    for (const std::pair<const std::string, size_t>& fs : fileSizes) {
                        _nTotalBytes += fs.second;
                    }
                }
                return !_shouldCancel;
            });

            dl->start();
        }

        startedAllDownloads = true;

        bool failed = false;
        for (const std::unique_ptr<HttpFileDownload>& d : downloads) {
            d->wait();
            if (!d->hasSucceeded()) {
                failed = true;
                continue;
            }

            // If we are forcing the override, we download to a temporary file first, so
            // when we are done here, we need to rename the file to the original name

            std::filesystem::path tempName = d->destination();
            std::filesystem::path originalName = tempName;
            // Remove the .tmp extension
            originalName.replace_extension("");

            if (std::filesystem::is_regular_file(originalName)) {
                std::filesystem::remove(originalName);
            }

            std::error_code ec;
            std::filesystem::rename(tempName, originalName, ec);
            if (ec) {
                LERRORC(
                    "URLSynchronization",
                    fmt::format("Error renaming file {} to {}", tempName, originalName)
                );

                failed = true;
            }
        }

        if (!failed) {
            createSyncFile();
        }
        else {
            for (const std::unique_ptr<HttpFileDownload>& d : downloads) {
                d->cancel();
            }
        }
        _state = State::Resolved;
    });
}

void UrlSynchronization::cancel() {
    _shouldCancel = true;
    _state = State::Unsynced;
}

std::string UrlSynchronization::generateUid() {
    return _identifier;
}

} // namespace openspace
<|endoftext|>


<commit_before>#include "Widget.hpp"

#include "../App.hpp"
#include "Container.hpp"
#include "../shaders/SimpleSingleColoringShader.hpp"
#include "../util/util.hpp"

using namespace morda;

Widget::Widget(const stob::Node* desc){
	if(!desc){
		return;
	}

	if(const stob::Node* p = desc->Child("prop").node()){
		this->prop = p->Clone();
		this->prop->SetValue();//clear value of the prop node, we don't need it
	}

	if(const stob::Node* p = desc->GetProperty("pos")){
		this->rect.p = morda::DimVec2f(p);
	}

	if(const stob::Node* p = desc->GetProperty("dim")){
		this->rect.d = morda::DimVec2f(p);
	}

	if(const stob::Node* p = desc->GetProperty("name")){
		this->name = p->Value();
	}

	if(const stob::Node* p = desc->GetProperty("clip")){
		this->clip = p->AsBool();
	}

	if(const stob::Node* p = desc->GetProperty("background")){
		this->background = Background::New(*p);
	}
}

void Widget::RemoveFromParent(){
	if(this->parent){
		this->parent->Remove(*this);
	}
}

void Widget::SetRelayoutNeeded()NOEXCEPT{
	this->minDimNeedsRecomputing = true;
	if(this->relayoutNeeded){
		return;
	}
	this->relayoutNeeded = true;
	if(this->parent){
		this->parent->SetRelayoutNeeded();
	}
}

void Widget::RenderInternal(const morda::Matr4f& matrix)const{
	if(this->clip){
//		TRACE(<< "Widget::RenderInternal(): oldScissorBox = " << Rect2i(oldcissorBox[0], oldcissorBox[1], oldcissorBox[2], oldcissorBox[3]) << std::endl)

		//set scissor test
		Rect2i scissor(
				((matrix * Vec2f(0, 0) + Vec2f(1, 1)) / 2)
						.CompMulBy(App::Inst().viewportDim())
						.ConvertTo<int>(),
				this->rect.d.ConvertTo<int>()
			);

		Rect2i oldScissor;
		bool scissorTestWasEnabled = glIsEnabled(GL_SCISSOR_TEST) ? true : false;
		if(scissorTestWasEnabled){
			GLint osb[4];
			glGetIntegerv(GL_SCISSOR_BOX, osb);
			oldScissor = Rect2i(osb[0], osb[1], osb[2], osb[3]);
			scissor.Intersect(oldScissor);
		}else{
			glEnable(GL_SCISSOR_TEST);
		}

		glScissor(scissor.p.x, scissor.p.y, scissor.d.x, scissor.d.y);

		if(this->background){
			this->background->Render(matrix, this->Rect().d);
		}

		this->Render(matrix);

		if(scissorTestWasEnabled){
			glScissor(oldScissor.p.x, oldScissor.p.y, oldScissor.d.x, oldScissor.d.y);
		}else{
			glDisable(GL_SCISSOR_TEST);
		}
	}else{
		if(this->background){
			this->background->Render(matrix, this->Rect().d);
		}

		this->Render(matrix);
	}

	//render border
#ifdef M_MORDA_RENDER_WIDGET_BORDERS
	morda::SimpleSingleColoringShader& s = App::Inst().Shaders().simpleSingleColoring;
	s.Bind();
	morda::Matr4f matr(matrix);
	matr.Scale(this->Rect().d);
	s.SetMatrix(matr);

	if(this->IsHovered()){
		s.SetColor(morda::Vec3f(0, 1, 0));
	}else{
		s.SetColor(morda::Vec3f(1, 0, 1));
	}
	s.DrawQuad01(GL_LINE_LOOP);
#endif
}

void Widget::OnKeyInternal(bool isDown, EKey keyCode){
	if(this->OnKey(isDown, keyCode)){
		return;
	}

	//pass key event to parent
	if(this->Parent()){
		this->Parent()->OnKeyInternal(isDown, keyCode);
	}
}

void Widget::Focus()NOEXCEPT{
	ASSERT(App::Inst().ThisIsUIThread())

	if(this->IsFocused()){
		return;
	}

	if(auto w = App::Inst().focusedWidget.lock()){
		w->isFocused = false;
	}
	App::Inst().focusedWidget = this->SharedFromThis(this);
	this->isFocused = true;
}

void Widget::Unfocus()NOEXCEPT{
	ASSERT(App::Inst().ThisIsUIThread())

	if(!this->IsFocused()){
		return;
	}

	ASSERT(App::Inst().focusedWidget.lock() && App::Inst().focusedWidget.lock().operator->() == this)

	App::Inst().focusedWidget.reset();
	this->isFocused = false;
}
<commit_msg>scissor correction<commit_after>#include "Widget.hpp"

#include "../App.hpp"
#include "Container.hpp"
#include "../shaders/SimpleSingleColoringShader.hpp"
#include "../util/util.hpp"

using namespace morda;

Widget::Widget(const stob::Node* desc){
	if(!desc){
		return;
	}

	if(const stob::Node* p = desc->Child("prop").node()){
		this->prop = p->Clone();
		this->prop->SetValue();//clear value of the prop node, we don't need it
	}

	if(const stob::Node* p = desc->GetProperty("pos")){
		this->rect.p = morda::DimVec2f(p);
	}

	if(const stob::Node* p = desc->GetProperty("dim")){
		this->rect.d = morda::DimVec2f(p);
	}

	if(const stob::Node* p = desc->GetProperty("name")){
		this->name = p->Value();
	}

	if(const stob::Node* p = desc->GetProperty("clip")){
		this->clip = p->AsBool();
	}

	if(const stob::Node* p = desc->GetProperty("background")){
		this->background = Background::New(*p);
	}
}

void Widget::RemoveFromParent(){
	if(this->parent){
		this->parent->Remove(*this);
	}
}

void Widget::SetRelayoutNeeded()NOEXCEPT{
	this->minDimNeedsRecomputing = true;
	if(this->relayoutNeeded){
		return;
	}
	this->relayoutNeeded = true;
	if(this->parent){
		this->parent->SetRelayoutNeeded();
	}
}

void Widget::RenderInternal(const morda::Matr4f& matrix)const{
	if(this->clip){
//		TRACE(<< "Widget::RenderInternal(): oldScissorBox = " << Rect2i(oldcissorBox[0], oldcissorBox[1], oldcissorBox[2], oldcissorBox[3]) << std::endl)

		//set scissor test
		Rect2i scissor(
				RoundVec(
						((matrix * Vec2f(0, 0) + Vec2f(1, 1)) / 2)
								.CompMulBy(App::Inst().viewportDim())
					).ConvertTo<int>(),
				this->rect.d.ConvertTo<int>()
			);

		Rect2i oldScissor;
		bool scissorTestWasEnabled = glIsEnabled(GL_SCISSOR_TEST) ? true : false;
		if(scissorTestWasEnabled){
			GLint osb[4];
			glGetIntegerv(GL_SCISSOR_BOX, osb);
			oldScissor = Rect2i(osb[0], osb[1], osb[2], osb[3]);
			scissor.Intersect(oldScissor);
		}else{
			glEnable(GL_SCISSOR_TEST);
		}

		glScissor(scissor.p.x, scissor.p.y, scissor.d.x, scissor.d.y);

		if(this->background){
			this->background->Render(matrix, this->Rect().d);
		}

		this->Render(matrix);

		if(scissorTestWasEnabled){
			glScissor(oldScissor.p.x, oldScissor.p.y, oldScissor.d.x, oldScissor.d.y);
		}else{
			glDisable(GL_SCISSOR_TEST);
		}
	}else{
		if(this->background){
			this->background->Render(matrix, this->Rect().d);
		}

		this->Render(matrix);
	}

	//render border
#ifdef M_MORDA_RENDER_WIDGET_BORDERS
	morda::SimpleSingleColoringShader& s = App::Inst().Shaders().simpleSingleColoring;
	s.Bind();
	morda::Matr4f matr(matrix);
	matr.Scale(this->Rect().d);
	s.SetMatrix(matr);

	if(this->IsHovered()){
		s.SetColor(morda::Vec3f(0, 1, 0));
	}else{
		s.SetColor(morda::Vec3f(1, 0, 1));
	}
	s.DrawQuad01(GL_LINE_LOOP);
#endif
}

void Widget::OnKeyInternal(bool isDown, EKey keyCode){
	if(this->OnKey(isDown, keyCode)){
		return;
	}

	//pass key event to parent
	if(this->Parent()){
		this->Parent()->OnKeyInternal(isDown, keyCode);
	}
}

void Widget::Focus()NOEXCEPT{
	ASSERT(App::Inst().ThisIsUIThread())

	if(this->IsFocused()){
		return;
	}

	if(auto w = App::Inst().focusedWidget.lock()){
		w->isFocused = false;
	}
	App::Inst().focusedWidget = this->SharedFromThis(this);
	this->isFocused = true;
}

void Widget::Unfocus()NOEXCEPT{
	ASSERT(App::Inst().ThisIsUIThread())

	if(!this->IsFocused()){
		return;
	}

	ASSERT(App::Inst().focusedWidget.lock() && App::Inst().focusedWidget.lock().operator->() == this)

	App::Inst().focusedWidget.reset();
	this->isFocused = false;
}
<|endoftext|>


<commit_before>/*
** Copyright 2011 Merethis
** This file is part of Centreon Broker.
**
** Centreon Broker is free software: you can redistribute it and/or
** modify it under the terms of the GNU General Public License version 2
** as published by the Free Software Foundation.
**
** Centreon Broker 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
** General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Centreon Broker. If not, see
** <http://www.gnu.org/licenses/>.
*/

#include <algorithm>
#include <assert.h>
#include <stdlib.h>
#include "config/applier/endpoint.hh"
#include "exceptions/basic.hh"
#include "io/acceptor.hh"
#include "io/connector.hh"
#include "io/protocols.hh"
#include "logging/logging.hh"

using namespace com::centreon::broker;
using namespace com::centreon::broker::config::applier;

/**************************************
*                                     *
*            Local Objects            *
*                                     *
**************************************/

/**
 *  Comparison classes.
 */
class                  failover_match_name {
 private:
  QString              _failover;

 public:
                       failover_match_name(QString const& fo)
    : _failover(fo) {}
                       failover_match_name(failover_match_name const& fmn)
    : _failover(fmn._failover) {}
                       ~failover_match_name() {}
  failover_match_name& operator=(failover_match_name& fmn) {
    _failover = fmn._failover;
    return (*this);
  }
  bool                 operator()(config::endpoint const& endp) const {
    return (_failover == endp.name);
  }
};
class                  name_match_failover {
 private:
  QString              _name;

 public:
                       name_match_failover(QString const& name)
    : _name(name) {}
                       name_match_failover(name_match_failover const& nmf)
    : _name(nmf._name) {}
                       ~name_match_failover() {}
  name_match_failover& operator=(name_match_failover const& nmf) {
    _name = nmf._name;
    return (*this);
  }
  bool                 operator()(config::endpoint const& endp) const {
    return (_name == endp.failover);
  }
};

/**************************************
*                                     *
*           Private Methods           *
*                                     *
**************************************/

/**
 *  Default constructor.
 */
endpoint::endpoint() : QObject() {}

/**
 *  @brief Copy constructor.
 *
 *  Any call to this constructor will result in a call to abort().
 *
 *  @param[in] e Object to copy.
 */
endpoint::endpoint(endpoint const& e) : QObject() {
  (void)e;
  assert(false);
  abort();
}

/**
 *  @brief Assignment operator.
 *
 *  Any call to this method will result in a call to abort().
 *
 *  @param[in] e Object to copy.
 *
 *  @return This object.
 */
endpoint& endpoint::operator=(endpoint const& e) {
  (void)e;
  assert(false);
  abort();
  return (*this);
}

/**
 *  Create and register an endpoint according to configuration.
 *
 *  @param[in] cfg       Endpoint configuration.
 *  @param[in] is_input  true if the endpoint will act as input.
 *  @param[in] is_output true if the endpoint will act as output.
 *  @param[in] l         List of endpoints.
 */
processing::failover* endpoint::_create_endpoint(config::endpoint const& cfg,
                                                 bool is_input,
                                                 bool is_output,
                                                 QList<config::endpoint> const& l) {
  // Debug message.
  logging::config << logging::MEDIUM << "creating new endpoint '"
    << cfg.name.toStdString().c_str() << "'";

  // Check that failover is configured.
  QSharedPointer<processing::failover> failovr;
  if (!cfg.failover.isEmpty()) {
    QList<config::endpoint>::const_iterator it(std::find_if(l.begin(), l.end(), failover_match_name(cfg.failover)));
    if (it == l.end())
      throw (exceptions::basic() << "could not find failover '"
               << cfg.failover.toStdString().c_str()
               << "' for endpoint '"
               << cfg.name.toStdString().c_str()) << "'";
    failovr = QSharedPointer<processing::failover>(_create_endpoint(*it, is_input || is_output, is_output, l));
  }

  // Create endpoint object.
  QSharedPointer<io::endpoint> endp;
  bool is_acceptor;
  int level;
  for (QMap<QString, io::protocols::protocol>::const_iterator it = io::protocols::instance().begin(),
         end = io::protocols::instance().end();
       it != end;
       ++it) {
    if ((it.value().osi_from == 1)
        && it.value().endpntfactry->has_endpoint(cfg, !is_output, is_output)) {
      endp = QSharedPointer<io::endpoint>(it.value().endpntfactry->new_endpoint(cfg, is_input, is_output, is_acceptor));
      level = it.value().osi_to + 1;
      break ;
    }
  }
  if (endp.isNull())
    throw (exceptions::basic() << "no matching protocol found for endpoint '"
             << cfg.name.toStdString().c_str() << "'");

  // Create remaining objects.
  while (level <= 7) {
    // Browse protocol list.
    QMap<QString, io::protocols::protocol>::const_iterator it(io::protocols::instance().begin());
    QMap<QString, io::protocols::protocol>::const_iterator end(io::protocols::instance().end());
    while (it != end) {
      if ((it.value().osi_from == level)
          && (it.value().endpntfactry->has_endpoint(cfg, !is_output, is_output))) {
        if (is_acceptor) {
          QSharedPointer<io::acceptor> current(static_cast<io::acceptor*>(it.value().endpntfactry->new_endpoint(cfg, !is_output, is_output, is_acceptor)));
          current->from(endp.staticCast<io::acceptor>());
          endp = current;
        }
        else {
          QSharedPointer<io::connector> current(static_cast<io::connector*>(it.value().endpntfactry->new_endpoint(cfg, !is_output, is_output, is_acceptor)));
          current->from(endp.staticCast<io::connector>());
          endp = current;
        }
        level = it.value().osi_to;
        break ;
      }
      ++it;
    }
    if ((7 == level) && (it == end))
      throw (exceptions::basic() << "no matching protocol found for endpoint '"
               << cfg.name.toStdString().c_str() << "'");
    ++level;
  }

  // Return failover thread.
  QScopedPointer<processing::failover> fo(new processing::failover(true));
  fo->set_endpoint(endp);
  fo->set_failover(failovr);
  return (fo.take());
}

/**
 *  Diff the current configuration with the new configuration.
 *
 *  @param[in]  current       Current endpoints.
 *  @param[in]  new_endpoints New endpoints configuration.
 *  @param[out] to_create     Endpoints that should be created.
 */
void endpoint::_diff_endpoints(QMap<config::endpoint, processing::failover*> & current,
                               QList<config::endpoint> const& new_endpoints,
                               QList<config::endpoint>& to_create) {
  // Find which endpoints will be kept, created and deleted.
  QMap<config::endpoint, processing::failover*> to_delete(current);
  for (QList<config::endpoint>::const_iterator it = new_endpoints.begin(),
         end = new_endpoints.end();
       it != end;
       ++it) {
    QMap<config::endpoint, processing::failover*>::iterator endp(to_delete.find(*it));
    if (endp != to_delete.end())
      to_delete.erase(endp);
    else
      to_create.push_back(*it);
  }

  // Remove old endpoints.
  for (QMap<config::endpoint, processing::failover*>::iterator it = to_delete.begin(),
         end = to_delete.end();
       it != end;
       ++it) {
    // Send only termination request, object will be destroyed by event
    // loop on termination. But wait for threads because they hold
    // resources that might be used by other endpoints.
    (*it)->exit();
    (*it)->wait();
  }

  return ;
}

/**************************************
*                                     *
*           Public Methods            *
*                                     *
**************************************/

/**
 *  Destructor.
 */
endpoint::~endpoint() {}

/**
 *  Apply the endpoint configuration.
 *
 *  @param[in] inputs  Inputs configuration.
 *  @param[in] outputs Outputs configuration.
 */
void endpoint::apply(QList<config::endpoint> const& inputs,
                     QList<config::endpoint> const& outputs) {
  // Debug message.
  logging::config << logging::HIGH << "loading endpoint configuration";
  logging::debug << logging::HIGH << "endpoint applier: "
    << inputs.size() << " inputs, "
    << outputs.size() << " outputs";

  // Remove old inputs and generate inputs to create.
  QList<config::endpoint> in_to_create;
  _diff_endpoints(_inputs, inputs, in_to_create);

  // Remove old outputs and generate outputs to create.
  QList<config::endpoint> out_to_create;
  _diff_endpoints(_outputs, outputs, out_to_create);

  // Debug message.
  logging::debug << logging::HIGH << "endpoint applier: "
    << in_to_create.size() << " inputs to create, "
    << out_to_create.size() << " outputs to create";

  // Create new outputs.
  for (QList<config::endpoint>::iterator it = out_to_create.begin(),
         end = out_to_create.end();
       it != end;
       ++it)
    // Check that output is not a failover.
    if (std::find_if(out_to_create.begin(),
            out_to_create.end(),
            name_match_failover(it->name))
          == out_to_create.end()) {
      // Create endpoint.
      QScopedPointer<processing::failover> endp(_create_endpoint(*it, false, true, out_to_create));
      connect(endp.data(), SIGNAL(finished()), endp.data(), SLOT(deleteLater()));
      connect(endp.data(), SIGNAL(finished()), this, SLOT(terminated_output()));
      _outputs[*it] = endp.data();

      // Run thread.
      endp.take()->start();
    }

  // Create new inputs.
  for (QList<config::endpoint>::iterator it = in_to_create.begin(),
         end = in_to_create.end();
       it != end;
       ++it)
    // Check that output is not a failover.
    if (std::find_if(in_to_create.begin(),
            in_to_create.end(),
            name_match_failover(it->name))
          == in_to_create.end()) {
      // Create endpoint.
      QScopedPointer<processing::failover> endp(_create_endpoint(*it, true, false, in_to_create));
      connect(endp.data(), SIGNAL(finished()), endp.data(), SLOT(deleteLater()));
      connect(endp.data(), SIGNAL(finished()), this, SLOT(terminated_input()));
      _inputs[*it] = endp.data();

      // Run thread.
      endp.take()->start();
    }

  return ;
}

/**
 *  Get the class instance.
 *
 *  @return Class instance.
 */
endpoint& endpoint::instance() {
  static endpoint gl_endpoint;
  return (gl_endpoint);
}

/**
 *  An input thread finished executing.
 */
void endpoint::terminated_input() {
  // XXX
}

/**
 *  An output thread finished executing.
 */
void endpoint::terminated_output() {
  // XXX
}
<commit_msg>Endpoints with empty names are now properly created.<commit_after>/*
** Copyright 2011 Merethis
** This file is part of Centreon Broker.
**
** Centreon Broker is free software: you can redistribute it and/or
** modify it under the terms of the GNU General Public License version 2
** as published by the Free Software Foundation.
**
** Centreon Broker 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
** General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Centreon Broker. If not, see
** <http://www.gnu.org/licenses/>.
*/

#include <algorithm>
#include <assert.h>
#include <stdlib.h>
#include "config/applier/endpoint.hh"
#include "exceptions/basic.hh"
#include "io/acceptor.hh"
#include "io/connector.hh"
#include "io/protocols.hh"
#include "logging/logging.hh"

using namespace com::centreon::broker;
using namespace com::centreon::broker::config::applier;

/**************************************
*                                     *
*            Local Objects            *
*                                     *
**************************************/

/**
 *  Comparison classes.
 */
class                  failover_match_name {
 private:
  QString              _failover;

 public:
                       failover_match_name(QString const& fo)
    : _failover(fo) {}
                       failover_match_name(failover_match_name const& fmn)
    : _failover(fmn._failover) {}
                       ~failover_match_name() {}
  failover_match_name& operator=(failover_match_name& fmn) {
    _failover = fmn._failover;
    return (*this);
  }
  bool                 operator()(config::endpoint const& endp) const {
    return (_failover == endp.name);
  }
};
class                  name_match_failover {
 private:
  QString              _name;

 public:
                       name_match_failover(QString const& name)
    : _name(name) {}
                       name_match_failover(name_match_failover const& nmf)
    : _name(nmf._name) {}
                       ~name_match_failover() {}
  name_match_failover& operator=(name_match_failover const& nmf) {
    _name = nmf._name;
    return (*this);
  }
  bool                 operator()(config::endpoint const& endp) const {
    return (_name == endp.failover);
  }
};

/**************************************
*                                     *
*           Private Methods           *
*                                     *
**************************************/

/**
 *  Default constructor.
 */
endpoint::endpoint() : QObject() {}

/**
 *  @brief Copy constructor.
 *
 *  Any call to this constructor will result in a call to abort().
 *
 *  @param[in] e Object to copy.
 */
endpoint::endpoint(endpoint const& e) : QObject() {
  (void)e;
  assert(false);
  abort();
}

/**
 *  @brief Assignment operator.
 *
 *  Any call to this method will result in a call to abort().
 *
 *  @param[in] e Object to copy.
 *
 *  @return This object.
 */
endpoint& endpoint::operator=(endpoint const& e) {
  (void)e;
  assert(false);
  abort();
  return (*this);
}

/**
 *  Create and register an endpoint according to configuration.
 *
 *  @param[in] cfg       Endpoint configuration.
 *  @param[in] is_input  true if the endpoint will act as input.
 *  @param[in] is_output true if the endpoint will act as output.
 *  @param[in] l         List of endpoints.
 */
processing::failover* endpoint::_create_endpoint(config::endpoint const& cfg,
                                                 bool is_input,
                                                 bool is_output,
                                                 QList<config::endpoint> const& l) {
  // Debug message.
  logging::config << logging::MEDIUM << "endpoint applier: creating new endpoint '"
    << cfg.name.toStdString().c_str() << "'";

  // Check that failover is configured.
  QSharedPointer<processing::failover> failovr;
  if (!cfg.failover.isEmpty()) {
    QList<config::endpoint>::const_iterator it(std::find_if(l.begin(), l.end(), failover_match_name(cfg.failover)));
    if (it == l.end())
      throw (exceptions::basic() << "endpoint applier: could not find failover '"
               << cfg.failover.toStdString().c_str()
               << "' for endpoint '"
               << cfg.name.toStdString().c_str()) << "'";
    failovr = QSharedPointer<processing::failover>(_create_endpoint(*it, is_input || is_output, is_output, l));
  }

  // Create endpoint object.
  QSharedPointer<io::endpoint> endp;
  bool is_acceptor;
  int level;
  for (QMap<QString, io::protocols::protocol>::const_iterator it = io::protocols::instance().begin(),
         end = io::protocols::instance().end();
       it != end;
       ++it) {
    if ((it.value().osi_from == 1)
        && it.value().endpntfactry->has_endpoint(cfg, !is_output, is_output)) {
      endp = QSharedPointer<io::endpoint>(it.value().endpntfactry->new_endpoint(cfg, is_input, is_output, is_acceptor));
      level = it.value().osi_to + 1;
      break ;
    }
  }
  if (endp.isNull())
    throw (exceptions::basic() << "endpoint applier: no matching protocol found for endpoint '"
             << cfg.name.toStdString().c_str() << "'");

  // Create remaining objects.
  while (level <= 7) {
    // Browse protocol list.
    QMap<QString, io::protocols::protocol>::const_iterator it(io::protocols::instance().begin());
    QMap<QString, io::protocols::protocol>::const_iterator end(io::protocols::instance().end());
    while (it != end) {
      if ((it.value().osi_from == level)
          && (it.value().endpntfactry->has_endpoint(cfg, !is_output, is_output))) {
        if (is_acceptor) {
          QSharedPointer<io::acceptor> current(static_cast<io::acceptor*>(it.value().endpntfactry->new_endpoint(cfg, !is_output, is_output, is_acceptor)));
          current->from(endp.staticCast<io::acceptor>());
          endp = current;
        }
        else {
          QSharedPointer<io::connector> current(static_cast<io::connector*>(it.value().endpntfactry->new_endpoint(cfg, !is_output, is_output, is_acceptor)));
          current->from(endp.staticCast<io::connector>());
          endp = current;
        }
        level = it.value().osi_to;
        break ;
      }
      ++it;
    }
    if ((7 == level) && (it == end))
      throw (exceptions::basic() << "no matching protocol found for endpoint '"
               << cfg.name.toStdString().c_str() << "'");
    ++level;
  }

  // Return failover thread.
  QScopedPointer<processing::failover> fo(new processing::failover(true));
  fo->set_endpoint(endp);
  fo->set_failover(failovr);
  return (fo.take());
}

/**
 *  Diff the current configuration with the new configuration.
 *
 *  @param[in]  current       Current endpoints.
 *  @param[in]  new_endpoints New endpoints configuration.
 *  @param[out] to_create     Endpoints that should be created.
 */
void endpoint::_diff_endpoints(QMap<config::endpoint, processing::failover*> & current,
                               QList<config::endpoint> const& new_endpoints,
                               QList<config::endpoint>& to_create) {
  // Find which endpoints will be kept, created and deleted.
  QMap<config::endpoint, processing::failover*> to_delete(current);
  for (QList<config::endpoint>::const_iterator it = new_endpoints.begin(),
         end = new_endpoints.end();
       it != end;
       ++it) {
    QMap<config::endpoint, processing::failover*>::iterator endp(to_delete.find(*it));
    if (endp != to_delete.end())
      to_delete.erase(endp);
    else
      to_create.push_back(*it);
  }

  // Remove old endpoints.
  for (QMap<config::endpoint, processing::failover*>::iterator it = to_delete.begin(),
         end = to_delete.end();
       it != end;
       ++it) {
    // Send only termination request, object will be destroyed by event
    // loop on termination. But wait for threads because they hold
    // resources that might be used by other endpoints.
    (*it)->exit();
    (*it)->wait();
  }

  return ;
}

/**************************************
*                                     *
*           Public Methods            *
*                                     *
**************************************/

/**
 *  Destructor.
 */
endpoint::~endpoint() {}

/**
 *  Apply the endpoint configuration.
 *
 *  @param[in] inputs  Inputs configuration.
 *  @param[in] outputs Outputs configuration.
 */
void endpoint::apply(QList<config::endpoint> const& inputs,
                     QList<config::endpoint> const& outputs) {
  // Debug message.
  logging::config << logging::HIGH << "endpoint applier: loading configuration";
  logging::debug << logging::HIGH << "endpoint applier: "
    << inputs.size() << " inputs, "
    << outputs.size() << " outputs";

  // Remove old inputs and generate inputs to create.
  QList<config::endpoint> in_to_create;
  _diff_endpoints(_inputs, inputs, in_to_create);

  // Remove old outputs and generate outputs to create.
  QList<config::endpoint> out_to_create;
  _diff_endpoints(_outputs, outputs, out_to_create);

  // Debug message.
  logging::debug << logging::HIGH << "endpoint applier: "
    << in_to_create.size() << " inputs to create, "
    << out_to_create.size() << " outputs to create";

  // Create new outputs.
  for (QList<config::endpoint>::iterator it = out_to_create.begin(),
         end = out_to_create.end();
       it != end;
       ++it)
    // Check that output is not a failover.
    if (it->name.isEmpty()
        || (std::find_if(out_to_create.begin(),
              out_to_create.end(),
              name_match_failover(it->name))
            == out_to_create.end())) {
      // Create endpoint.
      QScopedPointer<processing::failover> endp(_create_endpoint(*it, false, true, out_to_create));
      connect(endp.data(), SIGNAL(finished()), endp.data(), SLOT(deleteLater()));
      connect(endp.data(), SIGNAL(finished()), this, SLOT(terminated_output()));
      _outputs[*it] = endp.data();

      // Run thread.
      endp.take()->start();
    }

  // Create new inputs.
  for (QList<config::endpoint>::iterator it = in_to_create.begin(),
         end = in_to_create.end();
       it != end;
       ++it)
    // Check that output is not a failover.
    if (it->name.isEmpty()
        || (std::find_if(in_to_create.begin(),
              in_to_create.end(),
              name_match_failover(it->name))
            == in_to_create.end())) {
      // Create endpoint.
      QScopedPointer<processing::failover> endp(_create_endpoint(*it, true, false, in_to_create));
      connect(endp.data(), SIGNAL(finished()), endp.data(), SLOT(deleteLater()));
      connect(endp.data(), SIGNAL(finished()), this, SLOT(terminated_input()));
      _inputs[*it] = endp.data();

      // Run thread.
      endp.take()->start();
    }

  return ;
}

/**
 *  Get the class instance.
 *
 *  @return Class instance.
 */
endpoint& endpoint::instance() {
  static endpoint gl_endpoint;
  return (gl_endpoint);
}

/**
 *  An input thread finished executing.
 */
void endpoint::terminated_input() {
  // XXX
}

/**
 *  An output thread finished executing.
 */
void endpoint::terminated_output() {
  // XXX
}
<|endoftext|>