<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include "main.h"

#include <Eigen/CXX11/Tensor>

using Eigen::Tensor;
using Eigen::RowMajor;

static void test_simple_lvalue_ref()
{
  Tensor<int, 1> input(6);
  input.setRandom();

  TensorRef<Tensor<int, 1>> ref3(input);
  TensorRef<Tensor<int, 1>> ref4 = input;

  VERIFY_IS_EQUAL(ref3.data(), input.data());
  VERIFY_IS_EQUAL(ref4.data(), input.data());

  for (int i = 0; i < 6; ++i) {
    VERIFY_IS_EQUAL(ref3(i), input(i));
    VERIFY_IS_EQUAL(ref4(i), input(i));
  }

  for (int i = 0; i < 6; ++i) {
    ref3.coeffRef(i) = i;
  }
  for (int i = 0; i < 6; ++i) {
    VERIFY_IS_EQUAL(input(i), i);
  }
  for (int i = 0; i < 6; ++i) {
    ref4.coeffRef(i) = -i * 2;
  }
  for (int i = 0; i < 6; ++i) {
    VERIFY_IS_EQUAL(input(i), -i*2);
  }
}

static void test_simple_rvalue_ref()
{
  Tensor<int, 1> input1(6);
  input1.setRandom();
  Tensor<int, 1> input2(6);
  input2.setRandom();

  TensorRef<Tensor<int, 1>> ref3(input1 + input2);
  TensorRef<Tensor<int, 1>> ref4 = input1 + input2;

  VERIFY_IS_NOT_EQUAL(ref3.data(), input1.data());
  VERIFY_IS_NOT_EQUAL(ref4.data(), input1.data());
  VERIFY_IS_NOT_EQUAL(ref3.data(), input2.data());
  VERIFY_IS_NOT_EQUAL(ref4.data(), input2.data());

  for (int i = 0; i < 6; ++i) {
    VERIFY_IS_EQUAL(ref3(i), input1(i) + input2(i));
    VERIFY_IS_EQUAL(ref4(i), input1(i) + input2(i));
  }
}

static void test_multiple_dims()
{
  Tensor<float, 3> input(3,5,7);
  input.setRandom();

  TensorRef<Tensor<float, 3>> ref(input);
  VERIFY_IS_EQUAL(ref.data(), input.data());
  VERIFY_IS_EQUAL(ref.dimension(0), 3);
  VERIFY_IS_EQUAL(ref.dimension(1), 5);
  VERIFY_IS_EQUAL(ref.dimension(2), 7);

  for (int i = 0; i < 3; ++i) {
    for (int j = 0; j < 5; ++j) {
      for (int k = 0; k < 7; ++k) {
        VERIFY_IS_EQUAL(ref(i,j,k), input(i,j,k));
      }
    }
  }
}

static void test_slice()
{
  Tensor<float, 5> tensor(2,3,5,7,11);
  tensor.setRandom();

  Eigen::DSizes<ptrdiff_t, 5> indices(1,2,3,4,5);
  Eigen::DSizes<ptrdiff_t, 5> sizes(1,1,1,1,1);
  TensorRef<Tensor<float, 5>> slice = tensor.slice(indices, sizes);
  VERIFY_IS_EQUAL(slice(0,0,0,0,0), tensor(1,2,3,4,5));

  Eigen::DSizes<ptrdiff_t, 5> indices2(1,1,3,4,5);
  Eigen::DSizes<ptrdiff_t, 5> sizes2(1,1,2,2,3);
  slice = tensor.slice(indices2, sizes2);
  for (int i = 0; i < 2; ++i) {
    for (int j = 0; j < 2; ++j) {
      for (int k = 0; k < 3; ++k) {
        VERIFY_IS_EQUAL(slice(0,0,i,j,k), tensor(1,1,3+i,4+j,5+k));
      }
    }
  }

  Eigen::DSizes<ptrdiff_t, 5> indices3(0,0,0,0,0);
  Eigen::DSizes<ptrdiff_t, 5> sizes3(2,3,1,1,1);
  slice = tensor.slice(indices3, sizes3);
  VERIFY_IS_EQUAL(slice.data(), tensor.data());
}

static void test_ref_of_ref()
{
  Tensor<float, 3> input(3,5,7);
  input.setRandom();

  TensorRef<Tensor<float, 3>> ref(input);
  TensorRef<Tensor<float, 3>> ref_of_ref(ref);
  TensorRef<Tensor<float, 3>> ref_of_ref2;
  ref_of_ref2 = ref;

  VERIFY_IS_EQUAL(ref_of_ref.data(), input.data());
  VERIFY_IS_EQUAL(ref_of_ref.dimension(0), 3);
  VERIFY_IS_EQUAL(ref_of_ref.dimension(1), 5);
  VERIFY_IS_EQUAL(ref_of_ref.dimension(2), 7);

  VERIFY_IS_EQUAL(ref_of_ref2.data(), input.data());
  VERIFY_IS_EQUAL(ref_of_ref2.dimension(0), 3);
  VERIFY_IS_EQUAL(ref_of_ref2.dimension(1), 5);
  VERIFY_IS_EQUAL(ref_of_ref2.dimension(2), 7);

  for (int i = 0; i < 3; ++i) {
    for (int j = 0; j < 5; ++j) {
      for (int k = 0; k < 7; ++k) {
        VERIFY_IS_EQUAL(ref_of_ref(i,j,k), input(i,j,k));
        VERIFY_IS_EQUAL(ref_of_ref2(i,j,k), input(i,j,k));
     }
    }
  }
}

static void test_ref_in_expr()
{
  Tensor<float, 3> input(3,5,7);
  input.setRandom();
  TensorRef<Tensor<float, 3>> input_ref(input);

  Tensor<float, 3> result(3,5,7);
  result.setRandom();
  TensorRef<Tensor<float, 3>> result_ref(result);

  Tensor<float, 3> bias(3,5,7);
  bias.setRandom();

  result_ref = input_ref + bias;
  for (int i = 0; i < 3; ++i) {
    for (int j = 0; j < 5; ++j) {
      for (int k = 0; k < 7; ++k) {
        VERIFY_IS_EQUAL(result_ref(i,j,k), input(i,j,k) + bias(i,j,k));
        VERIFY_IS_NOT_EQUAL(result(i,j,k), input(i,j,k) + bias(i,j,k));
      }
    }
  }

  result = result_ref;
  for (int i = 0; i < 3; ++i) {
    for (int j = 0; j < 5; ++j) {
      for (int k = 0; k < 7; ++k) {
        VERIFY_IS_EQUAL(result(i,j,k), input(i,j,k) + bias(i,j,k));
      }
    }
  }
}

static void test_coeff_ref()
{
  Tensor<float, 5> tensor(2,3,5,7,11);
  tensor.setRandom();
  Tensor<float, 5> original = tensor;

  TensorRef<Tensor<float, 4>> slice = tensor.chip(7, 4);
  slice.coeffRef(0, 0, 0, 0) = 1.0f;
  slice.coeffRef(1, 0, 0, 0) += 2.0f;

  VERIFY_IS_EQUAL(tensor(0,0,0,0,7), 1.0f);
  VERIFY_IS_EQUAL(tensor(1,0,0,0,7), original(1,0,0,0,7) + 2.0f);
}

static void test_nested_ops_with_ref()
{
  Tensor<float, 4> t(2, 3, 5, 7);
  t.setRandom();
  TensorMap<Tensor<const float, 4> > m(t.data(), 2, 3, 5, 7);
  array<pair<ptrdiff_t, ptrdiff_t>, 4> paddings;
  paddings[0] = make_pair(0, 0);
  paddings[1] = make_pair(2, 1);
  paddings[2] = make_pair(3, 4);
  paddings[3] = make_pair(0, 0);
  Eigen::DSizes<Eigen::DenseIndex, 4> shuffle_dims{0, 1, 2, 3};
  TensorRef<Tensor<const float, 4> > ref(m.pad(paddings));
  array<pair<ptrdiff_t, ptrdiff_t>, 4> trivial;
  trivial[0] = make_pair(0, 0);
  trivial[1] = make_pair(0, 0);
  trivial[2] = make_pair(0, 0);
  trivial[3] = make_pair(0, 0);
  Tensor<float, 4> padded = ref.shuffle(shuffle_dims).pad(trivial);
  VERIFY_IS_EQUAL(padded.dimension(0), 2+0);
  VERIFY_IS_EQUAL(padded.dimension(1), 3+3);
  VERIFY_IS_EQUAL(padded.dimension(2), 5+7);
  VERIFY_IS_EQUAL(padded.dimension(3), 7+0);

  for (int i = 0; i < 2; ++i) {
    for (int j = 0; j < 6; ++j) {
      for (int k = 0; k < 12; ++k) {
        for (int l = 0; l < 7; ++l) {
          if (j >= 2 && j < 5 && k >= 3 && k < 8) {
            VERIFY_IS_EQUAL(padded(i,j,k,l), t(i,j-2,k-3,l));
          } else {
            VERIFY_IS_EQUAL(padded(i,j,k,l), 0.0f);
          }
        }
      }
    }
  }
}

void test_cxx11_tensor_ref()
{
  CALL_SUBTEST(test_simple_lvalue_ref());
  CALL_SUBTEST(test_simple_rvalue_ref());
  CALL_SUBTEST(test_multiple_dims());
  CALL_SUBTEST(test_slice());
  CALL_SUBTEST(test_ref_of_ref());
  CALL_SUBTEST(test_ref_in_expr());
  CALL_SUBTEST(test_coeff_ref());
  CALL_SUBTEST(test_nested_ops_with_ref());
}
<commit_msg>Fixed compilation error with clang<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include "main.h"

#include <Eigen/CXX11/Tensor>

using Eigen::Tensor;
using Eigen::RowMajor;

static void test_simple_lvalue_ref()
{
  Tensor<int, 1> input(6);
  input.setRandom();

  TensorRef<Tensor<int, 1>> ref3(input);
  TensorRef<Tensor<int, 1>> ref4 = input;

  VERIFY_IS_EQUAL(ref3.data(), input.data());
  VERIFY_IS_EQUAL(ref4.data(), input.data());

  for (int i = 0; i < 6; ++i) {
    VERIFY_IS_EQUAL(ref3(i), input(i));
    VERIFY_IS_EQUAL(ref4(i), input(i));
  }

  for (int i = 0; i < 6; ++i) {
    ref3.coeffRef(i) = i;
  }
  for (int i = 0; i < 6; ++i) {
    VERIFY_IS_EQUAL(input(i), i);
  }
  for (int i = 0; i < 6; ++i) {
    ref4.coeffRef(i) = -i * 2;
  }
  for (int i = 0; i < 6; ++i) {
    VERIFY_IS_EQUAL(input(i), -i*2);
  }
}

static void test_simple_rvalue_ref()
{
  Tensor<int, 1> input1(6);
  input1.setRandom();
  Tensor<int, 1> input2(6);
  input2.setRandom();

  TensorRef<Tensor<int, 1>> ref3(input1 + input2);
  TensorRef<Tensor<int, 1>> ref4 = input1 + input2;

  VERIFY_IS_NOT_EQUAL(ref3.data(), input1.data());
  VERIFY_IS_NOT_EQUAL(ref4.data(), input1.data());
  VERIFY_IS_NOT_EQUAL(ref3.data(), input2.data());
  VERIFY_IS_NOT_EQUAL(ref4.data(), input2.data());

  for (int i = 0; i < 6; ++i) {
    VERIFY_IS_EQUAL(ref3(i), input1(i) + input2(i));
    VERIFY_IS_EQUAL(ref4(i), input1(i) + input2(i));
  }
}

static void test_multiple_dims()
{
  Tensor<float, 3> input(3,5,7);
  input.setRandom();

  TensorRef<Tensor<float, 3>> ref(input);
  VERIFY_IS_EQUAL(ref.data(), input.data());
  VERIFY_IS_EQUAL(ref.dimension(0), 3);
  VERIFY_IS_EQUAL(ref.dimension(1), 5);
  VERIFY_IS_EQUAL(ref.dimension(2), 7);

  for (int i = 0; i < 3; ++i) {
    for (int j = 0; j < 5; ++j) {
      for (int k = 0; k < 7; ++k) {
        VERIFY_IS_EQUAL(ref(i,j,k), input(i,j,k));
      }
    }
  }
}

static void test_slice()
{
  Tensor<float, 5> tensor(2,3,5,7,11);
  tensor.setRandom();

  Eigen::DSizes<ptrdiff_t, 5> indices(1,2,3,4,5);
  Eigen::DSizes<ptrdiff_t, 5> sizes(1,1,1,1,1);
  TensorRef<Tensor<float, 5>> slice = tensor.slice(indices, sizes);
  VERIFY_IS_EQUAL(slice(0,0,0,0,0), tensor(1,2,3,4,5));

  Eigen::DSizes<ptrdiff_t, 5> indices2(1,1,3,4,5);
  Eigen::DSizes<ptrdiff_t, 5> sizes2(1,1,2,2,3);
  slice = tensor.slice(indices2, sizes2);
  for (int i = 0; i < 2; ++i) {
    for (int j = 0; j < 2; ++j) {
      for (int k = 0; k < 3; ++k) {
        VERIFY_IS_EQUAL(slice(0,0,i,j,k), tensor(1,1,3+i,4+j,5+k));
      }
    }
  }

  Eigen::DSizes<ptrdiff_t, 5> indices3(0,0,0,0,0);
  Eigen::DSizes<ptrdiff_t, 5> sizes3(2,3,1,1,1);
  slice = tensor.slice(indices3, sizes3);
  VERIFY_IS_EQUAL(slice.data(), tensor.data());
}

static void test_ref_of_ref()
{
  Tensor<float, 3> input(3,5,7);
  input.setRandom();

  TensorRef<Tensor<float, 3>> ref(input);
  TensorRef<Tensor<float, 3>> ref_of_ref(ref);
  TensorRef<Tensor<float, 3>> ref_of_ref2;
  ref_of_ref2 = ref;

  VERIFY_IS_EQUAL(ref_of_ref.data(), input.data());
  VERIFY_IS_EQUAL(ref_of_ref.dimension(0), 3);
  VERIFY_IS_EQUAL(ref_of_ref.dimension(1), 5);
  VERIFY_IS_EQUAL(ref_of_ref.dimension(2), 7);

  VERIFY_IS_EQUAL(ref_of_ref2.data(), input.data());
  VERIFY_IS_EQUAL(ref_of_ref2.dimension(0), 3);
  VERIFY_IS_EQUAL(ref_of_ref2.dimension(1), 5);
  VERIFY_IS_EQUAL(ref_of_ref2.dimension(2), 7);

  for (int i = 0; i < 3; ++i) {
    for (int j = 0; j < 5; ++j) {
      for (int k = 0; k < 7; ++k) {
        VERIFY_IS_EQUAL(ref_of_ref(i,j,k), input(i,j,k));
        VERIFY_IS_EQUAL(ref_of_ref2(i,j,k), input(i,j,k));
     }
    }
  }
}

static void test_ref_in_expr()
{
  Tensor<float, 3> input(3,5,7);
  input.setRandom();
  TensorRef<Tensor<float, 3>> input_ref(input);

  Tensor<float, 3> result(3,5,7);
  result.setRandom();
  TensorRef<Tensor<float, 3>> result_ref(result);

  Tensor<float, 3> bias(3,5,7);
  bias.setRandom();

  result_ref = input_ref + bias;
  for (int i = 0; i < 3; ++i) {
    for (int j = 0; j < 5; ++j) {
      for (int k = 0; k < 7; ++k) {
        VERIFY_IS_EQUAL(result_ref(i,j,k), input(i,j,k) + bias(i,j,k));
        VERIFY_IS_NOT_EQUAL(result(i,j,k), input(i,j,k) + bias(i,j,k));
      }
    }
  }

  result = result_ref;
  for (int i = 0; i < 3; ++i) {
    for (int j = 0; j < 5; ++j) {
      for (int k = 0; k < 7; ++k) {
        VERIFY_IS_EQUAL(result(i,j,k), input(i,j,k) + bias(i,j,k));
      }
    }
  }
}

static void test_coeff_ref()
{
  Tensor<float, 5> tensor(2,3,5,7,11);
  tensor.setRandom();
  Tensor<float, 5> original = tensor;

  TensorRef<Tensor<float, 4>> slice = tensor.chip(7, 4);
  slice.coeffRef(0, 0, 0, 0) = 1.0f;
  slice.coeffRef(1, 0, 0, 0) += 2.0f;

  VERIFY_IS_EQUAL(tensor(0,0,0,0,7), 1.0f);
  VERIFY_IS_EQUAL(tensor(1,0,0,0,7), original(1,0,0,0,7) + 2.0f);
}

static void test_nested_ops_with_ref()
{
  Tensor<float, 4> t(2, 3, 5, 7);
  t.setRandom();
  TensorMap<Tensor<const float, 4> > m(t.data(), 2, 3, 5, 7);
  array<std::pair<ptrdiff_t, ptrdiff_t>, 4> paddings;
  paddings[0] = std::make_pair(0, 0);
  paddings[1] = std::make_pair(2, 1);
  paddings[2] = std::make_pair(3, 4);
  paddings[3] = std::make_pair(0, 0);
  DSizes<Eigen::DenseIndex, 4> shuffle_dims{0, 1, 2, 3};
  TensorRef<Tensor<const float, 4> > ref(m.pad(paddings));
  array<std::pair<ptrdiff_t, ptrdiff_t>, 4> trivial;
  trivial[0] = std::make_pair(0, 0);
  trivial[1] = std::make_pair(0, 0);
  trivial[2] = std::make_pair(0, 0);
  trivial[3] = std::make_pair(0, 0);
  Tensor<float, 4> padded = ref.shuffle(shuffle_dims).pad(trivial);
  VERIFY_IS_EQUAL(padded.dimension(0), 2+0);
  VERIFY_IS_EQUAL(padded.dimension(1), 3+3);
  VERIFY_IS_EQUAL(padded.dimension(2), 5+7);
  VERIFY_IS_EQUAL(padded.dimension(3), 7+0);

  for (int i = 0; i < 2; ++i) {
    for (int j = 0; j < 6; ++j) {
      for (int k = 0; k < 12; ++k) {
        for (int l = 0; l < 7; ++l) {
          if (j >= 2 && j < 5 && k >= 3 && k < 8) {
            VERIFY_IS_EQUAL(padded(i,j,k,l), t(i,j-2,k-3,l));
          } else {
            VERIFY_IS_EQUAL(padded(i,j,k,l), 0.0f);
          }
        }
      }
    }
  }
}

void test_cxx11_tensor_ref()
{
  CALL_SUBTEST(test_simple_lvalue_ref());
  CALL_SUBTEST(test_simple_rvalue_ref());
  CALL_SUBTEST(test_multiple_dims());
  CALL_SUBTEST(test_slice());
  CALL_SUBTEST(test_ref_of_ref());
  CALL_SUBTEST(test_ref_in_expr());
  CALL_SUBTEST(test_coeff_ref());
  CALL_SUBTEST(test_nested_ops_with_ref());
}
<|endoftext|>


<commit_before>/* -*- mode: c++; c-basic-offset:4 -*-
    certificatepickerwidget.cpp

    This file is part of Kleopatra, the KDE keymanager
    Copyright (c) 2007 Klarälvdalens Datakonsult AB

    Kleopatra is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    Kleopatra 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 this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include "certificatepickerwidget.h"
#include "keyselectiondialog.h"
#include "models/keycache.h"
#include "utils/formatting.h"

#include <gpgme++/key.h>

#include <KLocale>

#include <QCheckBox>
#include <QComboBox>
#include <QLabel>
#include <QPointer>
#include <QPushButton>
#include <QGridLayout>
#include <QHash>
#include <QResizeEvent>
#include <QScrollArea>
#include <QVBoxLayout>

#include <cassert>

using namespace Kleo;

class Kleo::RecipientResolvePage::Private {
    friend class ::RecipientResolvePage;
    RecipientResolvePage * const q;
public:
    explicit Private( RecipientResolvePage * qq );
    ~Private();
    void addWidgetForIdentifier( const QString& identifier );
//    void completionStateChanged( const QString& id );
    void clear();
    QScrollArea* scrollArea;
    QVBoxLayout* lineLayout;
    std::vector<RecipientResolveWidget*> widgets;
    QStringList identifiers;
    GpgME::Protocol protocol;
};

RecipientResolvePage::Private::Private( RecipientResolvePage * qq )
    : q( qq ), protocol( GpgME::UnknownProtocol )
{
}

RecipientResolvePage::Private::~Private() {}

RecipientResolvePage::RecipientResolvePage( QWidget * parent )
    : QWizardPage( parent ), d( new Private( this ) )
{
    QGridLayout* const top = new QGridLayout( this );
    d->scrollArea = new QScrollArea( this );
    d->scrollArea->setFrameShape( QFrame::NoFrame );
    d->scrollArea->setWidgetResizable( true );
    QWidget* const container = new QWidget;
    d->lineLayout = new QVBoxLayout( container );
    QWidget* container2 = new QWidget;
    QVBoxLayout* const layout = new QVBoxLayout( container2 );
    layout->addWidget( container );
    layout->addStretch();
    d->scrollArea->setWidget( container2 );
    top->addWidget( d->scrollArea, 0, 0 );
    // TODO: these texts are mode-dependent
    setTitle( i18n( "Select Certificates for Recipients" ) );
    setSubTitle( i18n( "For every recipient, select a certificate that should be used for encryption. Click Next when done." ) );
}

RecipientResolvePage::~RecipientResolvePage() {}

bool RecipientResolvePage::isComplete() const
{
    Q_FOREACH ( RecipientResolveWidget* const i, d->widgets )
    {
        if ( !i->isComplete() )
            return false;
    }
    return true;
}

void RecipientResolvePage::setIdentifiers( const QStringList& ids )
{
    d->clear();
    Q_FOREACH ( const QString& i, ids )
        d->addWidgetForIdentifier( i );
}

void RecipientResolvePage::Private::clear()
{
    qDeleteAll( widgets );
    widgets.clear();
}

void RecipientResolvePage::Private::addWidgetForIdentifier( const QString& id )
{
    RecipientResolveWidget* const line = new RecipientResolveWidget;
    q->connect( line, SIGNAL( changed() ), q, SIGNAL( completeChanged() ) );
    line->setIdentifier( id );
    widgets.push_back( line );
    identifiers.push_back( id );
    assert( scrollArea->widget() );
    lineLayout->addWidget( line );
    line->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Preferred );
    line->show();
}

QStringList RecipientResolvePage::identifiers() const
{
    return d->identifiers;
}

void RecipientResolvePage::ensureIndexAvailable( unsigned int idx )
{
    if ( idx < d->widgets.size() )
        return;
    for ( int i = 0; idx - d->widgets.size() + 1; ++i )
        d->addWidgetForIdentifier( QString() );
    assert( d->widgets.size() == idx + 1 );
}

unsigned int RecipientResolvePage::numRecipientResolveWidgets() const
{
    return d->widgets.size();
}

RecipientResolveWidget * RecipientResolvePage::recipientResolveWidget( unsigned int idx ) const
{
    return d->widgets[idx];
}

class Kleo::RecipientResolveWidget::Private {
    friend class Kleo::RecipientResolveWidget;
    RecipientResolveWidget * const q;
public:
    explicit Private( RecipientResolveWidget * qq );

    void selectAnotherCertificate();
    void currentIndexChanged( int );

private:

    QVariant currentData() const;
    void addCertificate( const GpgME::Key& key );

    QString m_identifier;
    QComboBox* m_combo;
    QLabel* m_recipientLabel;
    QPushButton* m_selectButton;
    QCheckBox* m_rememberChoiceCO;
    GpgME::Protocol m_protocol;
};

RecipientResolveWidget::Private::Private( RecipientResolveWidget * qq ) : q( qq ), m_identifier(), m_protocol( GpgME::UnknownProtocol )
{
    QGridLayout* const layout = new QGridLayout( q );
    m_recipientLabel = new QLabel;
    layout->addWidget( m_recipientLabel, 0, 0, /*rowSpan=*/1, /*columnSpan=*/-1 );
    QLabel* const certificateLabel = new QLabel;
    certificateLabel->setText( i18n( "Certificate:" ) );
    layout->addWidget( certificateLabel, 1, 0 );
    m_combo = new QComboBox;
    certificateLabel->setBuddy( m_combo );
    layout->addWidget( m_combo, 1, 1 );
    m_selectButton = new QPushButton;
    m_selectButton->setText( i18n( "..." ) );
    q->connect( m_selectButton, SIGNAL( clicked() ), SLOT( selectAnotherCertificate() ) );
    layout->addWidget( m_selectButton, 1, 2 );
    m_rememberChoiceCO = new QCheckBox;
    m_rememberChoiceCO->setText( i18n( "Remember choice" ) );
    layout->addWidget( m_rememberChoiceCO, 2, 0, /*rowSpan=*/1, /*columnSpan=*/-1 );
}

RecipientResolveWidget::RecipientResolveWidget( QWidget* parent ) : QWidget( parent ), d( new Private( this ) )
{
}

bool RecipientResolveWidget::rememberSelection() const
{
    return d->m_rememberChoiceCO->checkState() == Qt::Checked;
}

void RecipientResolveWidget::Private::addCertificate( const GpgME::Key& key )
{
    m_combo->addItem( Formatting::formatForComboBox( key ), QByteArray( key.keyID() ) );
}

void RecipientResolveWidget::setIdentifier( const QString& id )
{

    d->m_identifier = id;
    d->m_recipientLabel->setText( i18nc( "%1: email or name", "Recipient: %1", id ) );
}

void RecipientResolveWidget::setCertificates( const std::vector<GpgME::Key>& keys )
{
    d->m_combo->clear();
    if ( keys.empty() )
        return;
    Q_FOREACH ( const GpgME::Key& i, keys )
        d->addCertificate( i );
    emit changed();
}

GpgME::Key RecipientResolveWidget::chosenCertificate() const
{
    const QByteArray id = d->currentData().toByteArray();
    return KeyCache::instance()->findByKeyIDOrFingerprint( id.constData() );
}

void RecipientResolveWidget::Private::selectAnotherCertificate()
{
    QPointer<KeySelectionDialog> dlg = new KeySelectionDialog( q );
    dlg->setSelectionMode( KeySelectionDialog::SingleSelection );
    dlg->addKeys( KeyCache::instance()->keys() );
    if ( dlg->exec() == QDialog::Accepted )
    {
        const std::vector<GpgME::Key> keys = dlg->selectedKeys();
        if ( !keys.empty() )
        {
            addCertificate( keys[0] );
            //TODO: make sure keys[0] gets selected
        }
    }

    delete dlg;
}

void RecipientResolveWidget::Private::currentIndexChanged( int )
{
    emit q->changed();
}

QVariant RecipientResolveWidget::Private::currentData() const
{
    return m_combo->itemData( m_combo->currentIndex() );
}

bool RecipientResolveWidget::isComplete() const
{
    return !d->currentData().isNull();
}

void RecipientResolveWidget::setProtocol( GpgME::Protocol prot )
{
    d->m_protocol = prot;
}

GpgME::Protocol RecipientResolveWidget::protocol() const
{
    return d->m_protocol;
}

void RecipientResolvePage::setProtocol( GpgME::Protocol prot )
{
    d->protocol = prot;
    for ( int i = 0; i < d->widgets.size(); ++i )
    {
        d->widgets[i]->setProtocol( prot );
    }
}

GpgME::Protocol RecipientResolvePage::protocol() const
{
    return d->protocol;
}

#include "moc_certificatepickerwidget.cpp"

<commit_msg>completeChanged() for the people<commit_after>/* -*- mode: c++; c-basic-offset:4 -*-
    certificatepickerwidget.cpp

    This file is part of Kleopatra, the KDE keymanager
    Copyright (c) 2007 Klarälvdalens Datakonsult AB

    Kleopatra is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    Kleopatra 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 this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include "certificatepickerwidget.h"
#include "keyselectiondialog.h"
#include "models/keycache.h"
#include "utils/formatting.h"

#include <gpgme++/key.h>

#include <KLocale>

#include <QCheckBox>
#include <QComboBox>
#include <QLabel>
#include <QPointer>
#include <QPushButton>
#include <QGridLayout>
#include <QHash>
#include <QResizeEvent>
#include <QScrollArea>
#include <QVBoxLayout>

#include <cassert>

using namespace Kleo;

class Kleo::RecipientResolvePage::Private {
    friend class ::RecipientResolvePage;
    RecipientResolvePage * const q;
public:
    explicit Private( RecipientResolvePage * qq );
    ~Private();
    void addWidgetForIdentifier( const QString& identifier );
//    void completionStateChanged( const QString& id );
    void clear();
    QScrollArea* scrollArea;
    QVBoxLayout* lineLayout;
    std::vector<RecipientResolveWidget*> widgets;
    QStringList identifiers;
    GpgME::Protocol protocol;
};

RecipientResolvePage::Private::Private( RecipientResolvePage * qq )
    : q( qq ), protocol( GpgME::UnknownProtocol )
{
}

RecipientResolvePage::Private::~Private() {}

RecipientResolvePage::RecipientResolvePage( QWidget * parent )
    : QWizardPage( parent ), d( new Private( this ) )
{
    QGridLayout* const top = new QGridLayout( this );
    d->scrollArea = new QScrollArea( this );
    d->scrollArea->setFrameShape( QFrame::NoFrame );
    d->scrollArea->setWidgetResizable( true );
    QWidget* const container = new QWidget;
    d->lineLayout = new QVBoxLayout( container );
    QWidget* container2 = new QWidget;
    QVBoxLayout* const layout = new QVBoxLayout( container2 );
    layout->addWidget( container );
    layout->addStretch();
    d->scrollArea->setWidget( container2 );
    top->addWidget( d->scrollArea, 0, 0 );
    // TODO: these texts are mode-dependent
    setTitle( i18n( "Select Certificates for Recipients" ) );
    setSubTitle( i18n( "For every recipient, select a certificate that should be used for encryption. Click Next when done." ) );
}

RecipientResolvePage::~RecipientResolvePage() {}

bool RecipientResolvePage::isComplete() const
{
    Q_FOREACH ( RecipientResolveWidget* const i, d->widgets )
    {
        if ( !i->isComplete() )
            return false;
    }
    return true;
}

void RecipientResolvePage::setIdentifiers( const QStringList& ids )
{
    d->clear();
    Q_FOREACH ( const QString& i, ids )
        d->addWidgetForIdentifier( i );
}

void RecipientResolvePage::Private::clear()
{
    qDeleteAll( widgets );
    widgets.clear();
}

void RecipientResolvePage::Private::addWidgetForIdentifier( const QString& id )
{
    RecipientResolveWidget* const line = new RecipientResolveWidget;
    q->connect( line, SIGNAL( changed() ), q, SIGNAL( completeChanged() ) );
    line->setIdentifier( id );
    widgets.push_back( line );
    identifiers.push_back( id );
    assert( scrollArea->widget() );
    lineLayout->addWidget( line );
    line->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Preferred );
    line->show();
    emit q->completeChanged();
}

QStringList RecipientResolvePage::identifiers() const
{
    return d->identifiers;
}

void RecipientResolvePage::ensureIndexAvailable( unsigned int idx )
{
    if ( idx < d->widgets.size() )
        return;
    for ( int i = 0; idx - d->widgets.size() + 1; ++i )
        d->addWidgetForIdentifier( QString() );
    assert( d->widgets.size() == idx + 1 );
}

unsigned int RecipientResolvePage::numRecipientResolveWidgets() const
{
    return d->widgets.size();
}

RecipientResolveWidget * RecipientResolvePage::recipientResolveWidget( unsigned int idx ) const
{
    return d->widgets[idx];
}

class Kleo::RecipientResolveWidget::Private {
    friend class Kleo::RecipientResolveWidget;
    RecipientResolveWidget * const q;
public:
    explicit Private( RecipientResolveWidget * qq );

    void selectAnotherCertificate();
    void currentIndexChanged( int );

private:

    QVariant currentData() const;
    void addCertificate( const GpgME::Key& key );

    QString m_identifier;
    QComboBox* m_combo;
    QLabel* m_recipientLabel;
    QPushButton* m_selectButton;
    QCheckBox* m_rememberChoiceCO;
    GpgME::Protocol m_protocol;
};

RecipientResolveWidget::Private::Private( RecipientResolveWidget * qq ) : q( qq ), m_identifier(), m_protocol( GpgME::UnknownProtocol )
{
    QGridLayout* const layout = new QGridLayout( q );
    m_recipientLabel = new QLabel;
    layout->addWidget( m_recipientLabel, 0, 0, /*rowSpan=*/1, /*columnSpan=*/-1 );
    QLabel* const certificateLabel = new QLabel;
    certificateLabel->setText( i18n( "Certificate:" ) );
    layout->addWidget( certificateLabel, 1, 0 );
    m_combo = new QComboBox;
    certificateLabel->setBuddy( m_combo );
    layout->addWidget( m_combo, 1, 1 );
    m_selectButton = new QPushButton;
    m_selectButton->setText( i18n( "..." ) );
    q->connect( m_selectButton, SIGNAL( clicked() ), SLOT( selectAnotherCertificate() ) );
    layout->addWidget( m_selectButton, 1, 2 );
    m_rememberChoiceCO = new QCheckBox;
    m_rememberChoiceCO->setText( i18n( "Remember choice" ) );
    layout->addWidget( m_rememberChoiceCO, 2, 0, /*rowSpan=*/1, /*columnSpan=*/-1 );
}

RecipientResolveWidget::RecipientResolveWidget( QWidget* parent ) : QWidget( parent ), d( new Private( this ) )
{
}

bool RecipientResolveWidget::rememberSelection() const
{
    return d->m_rememberChoiceCO->checkState() == Qt::Checked;
}

void RecipientResolveWidget::Private::addCertificate( const GpgME::Key& key )
{
    m_combo->addItem( Formatting::formatForComboBox( key ), QByteArray( key.keyID() ) );
}

void RecipientResolveWidget::setIdentifier( const QString& id )
{

    d->m_identifier = id;
    d->m_recipientLabel->setText( i18nc( "%1: email or name", "Recipient: %1", id ) );
}

void RecipientResolveWidget::setCertificates( const std::vector<GpgME::Key>& keys )
{
    d->m_combo->clear();
    if ( keys.empty() )
        return;
    Q_FOREACH ( const GpgME::Key& i, keys )
        d->addCertificate( i );
    emit changed();
}

GpgME::Key RecipientResolveWidget::chosenCertificate() const
{
    const QByteArray id = d->currentData().toByteArray();
    return KeyCache::instance()->findByKeyIDOrFingerprint( id.constData() );
}

void RecipientResolveWidget::Private::selectAnotherCertificate()
{
    QPointer<KeySelectionDialog> dlg = new KeySelectionDialog( q );
    dlg->setSelectionMode( KeySelectionDialog::SingleSelection );
    dlg->addKeys( KeyCache::instance()->keys() );
    if ( dlg->exec() == QDialog::Accepted )
    {
        const std::vector<GpgME::Key> keys = dlg->selectedKeys();
        if ( !keys.empty() )
        {
            addCertificate( keys[0] );
            emit q->changed();
            //TODO: make sure keys[0] gets selected
        }
    }

    delete dlg;
}

void RecipientResolveWidget::Private::currentIndexChanged( int )
{
    emit q->changed();
}

QVariant RecipientResolveWidget::Private::currentData() const
{
    return m_combo->itemData( m_combo->currentIndex() );
}

bool RecipientResolveWidget::isComplete() const
{
    return !d->currentData().isNull();
}

void RecipientResolveWidget::setProtocol( GpgME::Protocol prot )
{
    d->m_protocol = prot;
}

GpgME::Protocol RecipientResolveWidget::protocol() const
{
    return d->m_protocol;
}

void RecipientResolvePage::setProtocol( GpgME::Protocol prot )
{
    d->protocol = prot;
    for ( int i = 0; i < d->widgets.size(); ++i )
    {
        d->widgets[i]->setProtocol( prot );
    }
}

GpgME::Protocol RecipientResolvePage::protocol() const
{
    return d->protocol;
}

#include "moc_certificatepickerwidget.cpp"

<|endoftext|>


<commit_before>#include "sdlwrap.hpp"

namespace rs {
	// ----- Mutex -----
	Mutex::Mutex(): _mutex(SDL_CreateMutex()) {}
	Mutex::Mutex(Mutex&& m): _mutex(m._mutex) {
		m._mutex = nullptr;
	}
	Mutex::~Mutex() {
		if(_mutex)
			SDL_DestroyMutex(_mutex);
	}
	bool Mutex::lock() {
		return SDLEC_D(Trap, SDL_LockMutex, _mutex) == 0;
	}
	bool Mutex::try_lock() {
		return SDLEC_D(Trap, SDL_TryLockMutex, _mutex) == 0;
	}
	void Mutex::unlock() {
		SDLEC_D(Trap, SDL_UnlockMutex, _mutex);
	}
	SDL_mutex* Mutex::getMutex() {
		return _mutex;
	}

	// ----- UniLock -----
	UniLock::UniLock(Mutex& m):
		_mutex(&m), _bLocked(true)
	{
		m.lock();
	}
	UniLock::UniLock(Mutex& m, DeferLock_t):
		_mutex(&m), _bLocked(false)
	{}
	UniLock::UniLock(Mutex& m, AdoptLock_t):
		_mutex(&m), _bLocked(true)
	{}
	UniLock::UniLock(Mutex& m, TryLock_t):
		_mutex(&m), _bLocked(m.try_lock())
	{}
	UniLock::~UniLock() {
		unlock();
	}
	UniLock::UniLock(UniLock&& u): _mutex(u._mutex), _bLocked(u._bLocked) {
		u._mutex = nullptr;
		u._bLocked = false;
	}
	void UniLock::lock() {
		if(!_bLocked) {
			_mutex->lock();
			_bLocked = true;
		}
	}
	bool UniLock::tryLock() {
		if(!_bLocked)
			return _bLocked = _mutex->try_lock();
		return true;
	}
	void UniLock::unlock() {
		if(_bLocked) {
			_mutex->unlock();
			_bLocked = false;
		}
	}
	bool UniLock::isLocked() const {
		return _bLocked;
	}
	SDL_mutex* UniLock::getMutex() {
		if(_mutex)
			return _mutex->getMutex();
		return nullptr;
	}

	// ----- CondV -----
	CondV::CondV(): _cond(SDL_CreateCond()) {}
	CondV::~CondV() {
		SDL_DestroyCond(_cond);
	}
	void CondV::wait(UniLock& u) {
		SDLEC_D(Trap, SDL_CondWait, _cond, u.getMutex());
	}
	bool CondV::wait_for(UniLock& u, uint32_t msec) {
		return SDLEC_D(Trap, SDL_CondWaitTimeout, _cond, u.getMutex(), msec) == 0;
	}
	void CondV::signal() {
		SDLEC_D(Trap, SDL_CondSignal, _cond);
	}
	void CondV::signal_all() {
		SDLEC_D(Trap, SDL_CondBroadcast, _cond);
	}
}
<commit_msg>SDL_TryLockMutexがロック出来ない時に失敗する？ので、とりあえずAssertではなくWarningにした<commit_after>#include "sdlwrap.hpp"

namespace rs {
	// ----- Mutex -----
	Mutex::Mutex(): _mutex(SDL_CreateMutex()) {}
	Mutex::Mutex(Mutex&& m): _mutex(m._mutex) {
		m._mutex = nullptr;
	}
	Mutex::~Mutex() {
		if(_mutex)
			SDL_DestroyMutex(_mutex);
	}
	bool Mutex::lock() {
		return SDLEC_D(Trap, SDL_LockMutex, _mutex) == 0;
	}
	bool Mutex::try_lock() {
		return SDLEC_D(Warn, SDL_TryLockMutex, _mutex) == 0;
	}
	void Mutex::unlock() {
		SDLEC_D(Trap, SDL_UnlockMutex, _mutex);
	}
	SDL_mutex* Mutex::getMutex() {
		return _mutex;
	}

	// ----- UniLock -----
	UniLock::UniLock(Mutex& m):
		_mutex(&m), _bLocked(true)
	{
		m.lock();
	}
	UniLock::UniLock(Mutex& m, DeferLock_t):
		_mutex(&m), _bLocked(false)
	{}
	UniLock::UniLock(Mutex& m, AdoptLock_t):
		_mutex(&m), _bLocked(true)
	{}
	UniLock::UniLock(Mutex& m, TryLock_t):
		_mutex(&m), _bLocked(m.try_lock())
	{}
	UniLock::~UniLock() {
		unlock();
	}
	UniLock::UniLock(UniLock&& u): _mutex(u._mutex), _bLocked(u._bLocked) {
		u._mutex = nullptr;
		u._bLocked = false;
	}
	void UniLock::lock() {
		if(!_bLocked) {
			_mutex->lock();
			_bLocked = true;
		}
	}
	bool UniLock::tryLock() {
		if(!_bLocked)
			return _bLocked = _mutex->try_lock();
		return true;
	}
	void UniLock::unlock() {
		if(_bLocked) {
			_mutex->unlock();
			_bLocked = false;
		}
	}
	bool UniLock::isLocked() const {
		return _bLocked;
	}
	SDL_mutex* UniLock::getMutex() {
		if(_mutex)
			return _mutex->getMutex();
		return nullptr;
	}

	// ----- CondV -----
	CondV::CondV(): _cond(SDL_CreateCond()) {}
	CondV::~CondV() {
		SDL_DestroyCond(_cond);
	}
	void CondV::wait(UniLock& u) {
		SDLEC_D(Trap, SDL_CondWait, _cond, u.getMutex());
	}
	bool CondV::wait_for(UniLock& u, uint32_t msec) {
		return SDLEC_D(Trap, SDL_CondWaitTimeout, _cond, u.getMutex(), msec) == 0;
	}
	void CondV::signal() {
		SDLEC_D(Trap, SDL_CondSignal, _cond);
	}
	void CondV::signal_all() {
		SDLEC_D(Trap, SDL_CondBroadcast, _cond);
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/fastos/fastos.h>
#include <iostream>
#include <string>
#include <cstdlib>

#include <boost/program_options.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/noncopyable.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/exception/diagnostic_information.hpp>
#include <boost/scope_exit.hpp>

#include <vespa/fastos/app.h>
#include <vespa/config-zookeepers.h>

#include <vespa/filedistribution/rpcconfig/config-filedistributorrpc.h>
#include <vespa/filedistribution/distributor/config-filedistributor.h>
#include <vespa/filedistribution/model/config-filereferences.h>

#include <vespa/filedistribution/distributor/filedistributortrackerimpl.h>
#include <vespa/filedistribution/distributor/filedownloadermanager.h>
#include <vespa/filedistribution/distributor/filedownloader.h>
#include <vespa/filedistribution/distributor/signalhandling.h>
#include <vespa/filedistribution/distributor/state_server_impl.h>

#include <vespa/filedistribution/model/filedistributionmodelimpl.h>
#include <vespa/filedistribution/rpc/filedistributorrpc.h>
#include <vespa/filedistribution/common/exception.h>
#include <vespa/filedistribution/common/componentsdeleter.h>

namespace {
const char* programName = "filedistributor";
}

#include <vespa/log/log.h>
LOG_SETUP(programName);

namespace ll = boost::lambda;

using namespace filedistribution;
using cloud::config::ZookeepersConfig;
using cloud::config::filedistribution::FiledistributorConfig;
using cloud::config::filedistribution::FiledistributorrpcConfig;

class FileDistributor : public config::IFetcherCallback<ZookeepersConfig>,
                        public config::IFetcherCallback<FiledistributorConfig>,
                        public config::IFetcherCallback<FiledistributorrpcConfig>,
                        public config::IGenerationCallback,
                        boost::noncopyable
{
    class Components : boost::noncopyable {
        ComponentsDeleter _componentsDeleter;
    public:
        const boost::shared_ptr<ZKFacade> _zk;
        const boost::shared_ptr<FileDistributionModelImpl> _model;
        const boost::shared_ptr<FileDistributorTrackerImpl> _tracker;
        const boost::shared_ptr<FileDownloader> _downloader;
        const boost::shared_ptr<FileDownloaderManager> _manager;
        const boost::shared_ptr<FileDistributorRPC> _rpcHandler;
        const boost::shared_ptr<StateServerImpl> _stateServer;

    private:
        boost::thread _downloaderEventLoopThread;
        config::ConfigFetcher _configFetcher;

        template <class T>
        typename boost::shared_ptr<T> track(T* component) {
            return _componentsDeleter.track(component);
        }

    public:

        Components(const boost::shared_ptr<ExceptionRethrower>& exceptionRethrower,
                   const config::ConfigUri & configUri,
                   const ZookeepersConfig& zooKeepersConfig,
                   const FiledistributorConfig& fileDistributorConfig,
                   const FiledistributorrpcConfig& rpcConfig)
            :_zk(track(new ZKFacade(zooKeepersConfig.zookeeperserverlist, exceptionRethrower))),
             _model(track(new FileDistributionModelImpl(
                                     fileDistributorConfig.hostname,
                                     fileDistributorConfig.torrentport,
                                     _zk,
                                     exceptionRethrower))),
             _tracker(track(new FileDistributorTrackerImpl(_model, exceptionRethrower))),
             _downloader(track(new FileDownloader(
                                     _tracker,
                                     fileDistributorConfig.hostname,
                                     fileDistributorConfig.torrentport,
                                     boost::filesystem::path(fileDistributorConfig.filedbpath),
                                     exceptionRethrower))),
             _manager(track(new FileDownloaderManager(_downloader, _model))),
             _rpcHandler(track(new FileDistributorRPC(rpcConfig.connectionspec, _manager))),
             _stateServer(track(new StateServerImpl(fileDistributorConfig.stateport))),
             _downloaderEventLoopThread(
                    ll::bind(&FileDownloader::runEventLoop, _downloader.get())),
             _configFetcher(configUri.getContext())

        {
            _manager->start();
            _rpcHandler->start();

            _tracker->setDownloader(_downloader);
            _configFetcher.subscribe<FilereferencesConfig>(configUri.getConfigId(), _model.get());
            _configFetcher.start();
            updatedConfig(_configFetcher.getGeneration());
        }

        void updatedConfig(int64_t generation) {
            vespalib::ComponentConfigProducer::Config curr("filedistributor", generation);
            _stateServer->myComponents.addConfig(curr);
        }

        ~Components() {
            _configFetcher.close();
            //Do not waste time retrying zookeeper operations when going down.
            _zk->disableRetries();

            _downloaderEventLoopThread.interrupt();
            _downloaderEventLoopThread.join();
        }

    };

    typedef boost::lock_guard<boost::mutex> LockGuard;
    boost::mutex _configMutex;

    bool _completeReconfigurationNeeded;
    std::unique_ptr<ZookeepersConfig> _zooKeepersConfig;
    std::unique_ptr<FiledistributorConfig> _fileDistributorConfig;
    std::unique_ptr<FiledistributorrpcConfig> _rpcConfig;

    boost::shared_ptr<ExceptionRethrower> _exceptionRethrower;
    std::unique_ptr<Components> _components;
public:
    FileDistributor()
        : _configMutex(),
          _completeReconfigurationNeeded(false),
          _zooKeepersConfig(),
          _fileDistributorConfig(),
          _rpcConfig(),
          _exceptionRethrower(),
          _components()
    { }

    void notifyGenerationChange(int64_t generation) {
        if (_components && ! completeReconfigurationNeeded()) {
            _components->updatedConfig(generation);
        }
    }

    //configure overrides
    void configure(std::unique_ptr<ZookeepersConfig> config) {
        LockGuard guard(_configMutex);
        _zooKeepersConfig = std::move(config);
        _completeReconfigurationNeeded = true;
    }

    void configure(std::unique_ptr<FiledistributorConfig> config) {
        LockGuard guard(_configMutex);
        if (_fileDistributorConfig.get() != NULL &&
            (config->torrentport != _fileDistributorConfig->torrentport ||
             config->stateport   != _fileDistributorConfig->stateport ||
             config->hostname    != _fileDistributorConfig->hostname ||
             config->filedbpath  != _fileDistributorConfig->filedbpath))
        {
            _completeReconfigurationNeeded = true;
        } else if (_components.get()) {
            configureSpeedLimits(*config);
        }
        _fileDistributorConfig = std::move(config);

    }

    void configure(std::unique_ptr<FiledistributorrpcConfig> config) {
        LockGuard guard(_configMutex);
        _rpcConfig = std::move(config);
        _completeReconfigurationNeeded = true;
    }

    void run(const config::ConfigUri & configUri) {
        while (!askedToShutDown()) {
            clearReinitializeFlag();
            _exceptionRethrower.reset(new ExceptionRethrower());
            runImpl(configUri);

            if (_exceptionRethrower->exceptionStored())
                _exceptionRethrower->rethrow();
        }
    }

    static void ensureExceptionsStored(const boost::shared_ptr<ExceptionRethrower>& exceptionRethrower) {
        //TODO: this is somewhat hackish, refactor to eliminate this later.
        LOG(debug, "Waiting for shutdown");
        for (int i=0;
             i<50 && !exceptionRethrower.unique();
                ++i) {
            boost::this_thread::sleep(boost::posix_time::milliseconds(100));
        }
        LOG(debug, "Done waiting for shutdown");

        if (!exceptionRethrower.unique()) {
            EV_STOPPING(programName, "Forced termination");
            kill(getpid(), SIGKILL);
        }
    }

    void createComponents(const boost::shared_ptr<ExceptionRethrower>& exceptionRethrower, const config::ConfigUri & configUri) {
        LockGuard guard(_configMutex);
        _components.reset(
                new Components(exceptionRethrower,
                        configUri,
                        *_zooKeepersConfig,
                        *_fileDistributorConfig,
                        *_rpcConfig));

        configureSpeedLimits(*_fileDistributorConfig);
        _completeReconfigurationNeeded = false;
    }

    bool completeReconfigurationNeeded() {
        LockGuard guard(_configMutex);
        if (_completeReconfigurationNeeded) {
            LOG(debug, "Complete reconfiguration needed");
        }
        return _completeReconfigurationNeeded;
    }

    void configureSpeedLimits(const FiledistributorConfig& config) {
        FileDownloader& downloader = *_components->_downloader;
        downloader.setMaxDownloadSpeed(config.maxdownloadspeed);
        downloader.setMaxUploadSpeed(config.maxuploadspeed);
    }

    //avoid warning due to scope exit macro
#pragma GCC diagnostic ignored "-Wshadow"
    void runImpl(const config::ConfigUri & configUri) {

        BOOST_SCOPE_EXIT((&_components)(&_exceptionRethrower)) {
            _components.reset();
            //Ensures that any exception stored during destruction will be available when returning.
            ensureExceptionsStored(_exceptionRethrower);
        } BOOST_SCOPE_EXIT_END

        createComponents(_exceptionRethrower, configUri);

        // We do not want back to back reinitializing as it gives zero time for serving
        // some torrents.
        int postPoneAskedToReinitializedSecs = 50;

        while (!askedToShutDown() &&
	       (postPoneAskedToReinitializedSecs > 0 || !askedToReinitialize()) &&
	       !completeReconfigurationNeeded() &&
	       !_exceptionRethrower->exceptionStored()) {
	  postPoneAskedToReinitializedSecs--;
	  boost::this_thread::sleep(boost::posix_time::seconds(1));
        }
    }
};

//TODO: use pop in gcc 4.6
#pragma GCC diagnostic warning "-Wshadow"

class FileDistributorApplication : public FastOS_Application {
    const config::ConfigUri _configUri;
public:
    FileDistributorApplication(const config::ConfigUri & configUri);

    //overrides
    int Main();
};

namespace {

struct ProgramOptionException {
    std::string _msg;
    ProgramOptionException(const std::string & msg)
        : _msg(msg)
    {}
};

bool exists(const std::string& optionName, const boost::program_options::variables_map& map) {
    return map.find(optionName) != map.end();
}

void ensureExists(const std::string& optionName, const boost::program_options::variables_map& map \
                  ) {
    if (!exists(optionName, map)) {
        throw ProgramOptionException("Error: Missing option " + optionName);
    }
}

} //anonymous namespace

FileDistributorApplication::FileDistributorApplication(const config::ConfigUri & configUri)
    :_configUri(configUri) {
}

int
FileDistributorApplication::Main() {
    try {
        FileDistributor distributor;

        config::ConfigFetcher configFetcher(_configUri.getContext());
        configFetcher.subscribe<ZookeepersConfig>(_configUri.getConfigId(), &distributor);
        configFetcher.subscribe<FiledistributorConfig>(_configUri.getConfigId(), &distributor);
        configFetcher.subscribe<FiledistributorrpcConfig>(_configUri.getConfigId(), &distributor);
        configFetcher.subscribeGenerationChanges(&distributor);
        configFetcher.start();

        distributor.run(_configUri);

        EV_STOPPING(programName, "Clean exit");
        return 0;
    } catch(const FileDoesNotExistException & e) {
        std::string s = boost::diagnostic_information(e);
        EV_STOPPING(programName, s.c_str());
        return 1;
    } catch(const ZKNodeDoesNotExistsException & e) {
        std::string s = boost::diagnostic_information(e);
        EV_STOPPING(programName, s.c_str());
        return 2;
    } catch(const ZKSessionExpired & e) {
        std::string s = boost::diagnostic_information(e);
        EV_STOPPING(programName, s.c_str());
        return 3;
    } catch(const ZKGenericException & e) {
        std::string s = boost::diagnostic_information(e);
        EV_STOPPING(programName, s.c_str());
        return 99;
    } catch(const boost::unknown_exception & e) {
        std::string s = boost::diagnostic_information(e);
        LOG(warning, "Caught '%s'", s.c_str());
        EV_STOPPING(programName, s.c_str());
        return 255;
#if 0
    /*
     These are kept hanging around for reference as to how it was when we just held our ears
     singing "na, na, na, na..." no matter if the sun was shining or if the world imploded.
    */
    } catch(const boost::exception& e) {
        std::string s = boost::diagnostic_information(e);
        LOG(error, "Caught '%s'", s.c_str());
        EV_STOPPING(programName, s.c_str());
        return -1;
    } catch(const std::string& msg) {
        std::string s = "Error: " + msg;
        LOG(error, "Caught '%s'", s.c_str());
        EV_STOPPING(programName, s.c_str());
        return -1;
#endif
    }
}

int
executeApplication(int argc, char** argv) {
    const char
        *configId("configid"),
        *help("help");

    namespace po = boost::program_options;
    po::options_description description;
    description.add_options()
        (configId, po::value<std::string > (), "id to request config for")
        (help, "help");

    try {
        po::variables_map values;
        po::store(
                po::parse_command_line(argc, argv, description),
                values);

        if (exists(help, values)) {
            std::cout <<description;
            return 0;
        }
        ensureExists(configId, values);

        FileDistributorApplication application(
                values[configId].as<std::string > ());
        return application.Entry(argc, argv);

    } catch(ProgramOptionException& e) {
        std::cerr <<e._msg <<std::endl;
        return -1;
    }
}

void terminate() {
    std::cerr <<"Terminate called: " <<std::endl;
    Backtrace backtrace;
    std::cerr <<backtrace <<std::endl;
}

int
main(int argc, char** argv) {
    EV_STARTED(programName);
    initSignals();

    std::srand(std::time(0));
    std::set_terminate(terminate);
    filedistribution::setupZooKeeperLogging();

    return executeApplication(argc, argv);
}
<commit_msg>Do not coredump when you do not get config. Just log the stopping event and restart. See bug jira VESPA-4168.<commit_after>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include <vespa/fastos/fastos.h>
#include <iostream>
#include <string>
#include <cstdlib>

#include <boost/program_options.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/noncopyable.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/exception/diagnostic_information.hpp>
#include <boost/scope_exit.hpp>

#include <vespa/fastos/app.h>
#include <vespa/config-zookeepers.h>

#include <vespa/filedistribution/rpcconfig/config-filedistributorrpc.h>
#include <vespa/filedistribution/distributor/config-filedistributor.h>
#include <vespa/filedistribution/model/config-filereferences.h>

#include <vespa/filedistribution/distributor/filedistributortrackerimpl.h>
#include <vespa/filedistribution/distributor/filedownloadermanager.h>
#include <vespa/filedistribution/distributor/filedownloader.h>
#include <vespa/filedistribution/distributor/signalhandling.h>
#include <vespa/filedistribution/distributor/state_server_impl.h>

#include <vespa/filedistribution/model/filedistributionmodelimpl.h>
#include <vespa/filedistribution/rpc/filedistributorrpc.h>
#include <vespa/filedistribution/common/exception.h>
#include <vespa/filedistribution/common/componentsdeleter.h>

namespace {
const char* programName = "filedistributor";
}

#include <vespa/log/log.h>
LOG_SETUP(programName);

namespace ll = boost::lambda;

using namespace filedistribution;
using cloud::config::ZookeepersConfig;
using cloud::config::filedistribution::FiledistributorConfig;
using cloud::config::filedistribution::FiledistributorrpcConfig;

class FileDistributor : public config::IFetcherCallback<ZookeepersConfig>,
                        public config::IFetcherCallback<FiledistributorConfig>,
                        public config::IFetcherCallback<FiledistributorrpcConfig>,
                        public config::IGenerationCallback,
                        boost::noncopyable
{
    class Components : boost::noncopyable {
        ComponentsDeleter _componentsDeleter;
    public:
        const boost::shared_ptr<ZKFacade> _zk;
        const boost::shared_ptr<FileDistributionModelImpl> _model;
        const boost::shared_ptr<FileDistributorTrackerImpl> _tracker;
        const boost::shared_ptr<FileDownloader> _downloader;
        const boost::shared_ptr<FileDownloaderManager> _manager;
        const boost::shared_ptr<FileDistributorRPC> _rpcHandler;
        const boost::shared_ptr<StateServerImpl> _stateServer;

    private:
        boost::thread _downloaderEventLoopThread;
        config::ConfigFetcher _configFetcher;

        template <class T>
        typename boost::shared_ptr<T> track(T* component) {
            return _componentsDeleter.track(component);
        }

    public:

        Components(const boost::shared_ptr<ExceptionRethrower>& exceptionRethrower,
                   const config::ConfigUri & configUri,
                   const ZookeepersConfig& zooKeepersConfig,
                   const FiledistributorConfig& fileDistributorConfig,
                   const FiledistributorrpcConfig& rpcConfig)
            :_zk(track(new ZKFacade(zooKeepersConfig.zookeeperserverlist, exceptionRethrower))),
             _model(track(new FileDistributionModelImpl(
                                     fileDistributorConfig.hostname,
                                     fileDistributorConfig.torrentport,
                                     _zk,
                                     exceptionRethrower))),
             _tracker(track(new FileDistributorTrackerImpl(_model, exceptionRethrower))),
             _downloader(track(new FileDownloader(
                                     _tracker,
                                     fileDistributorConfig.hostname,
                                     fileDistributorConfig.torrentport,
                                     boost::filesystem::path(fileDistributorConfig.filedbpath),
                                     exceptionRethrower))),
             _manager(track(new FileDownloaderManager(_downloader, _model))),
             _rpcHandler(track(new FileDistributorRPC(rpcConfig.connectionspec, _manager))),
             _stateServer(track(new StateServerImpl(fileDistributorConfig.stateport))),
             _downloaderEventLoopThread(
                    ll::bind(&FileDownloader::runEventLoop, _downloader.get())),
             _configFetcher(configUri.getContext())

        {
            _manager->start();
            _rpcHandler->start();

            _tracker->setDownloader(_downloader);
            _configFetcher.subscribe<FilereferencesConfig>(configUri.getConfigId(), _model.get());
            _configFetcher.start();
            updatedConfig(_configFetcher.getGeneration());
        }

        void updatedConfig(int64_t generation) {
            vespalib::ComponentConfigProducer::Config curr("filedistributor", generation);
            _stateServer->myComponents.addConfig(curr);
        }

        ~Components() {
            _configFetcher.close();
            //Do not waste time retrying zookeeper operations when going down.
            _zk->disableRetries();

            _downloaderEventLoopThread.interrupt();
            _downloaderEventLoopThread.join();
        }

    };

    typedef boost::lock_guard<boost::mutex> LockGuard;
    boost::mutex _configMutex;

    bool _completeReconfigurationNeeded;
    std::unique_ptr<ZookeepersConfig> _zooKeepersConfig;
    std::unique_ptr<FiledistributorConfig> _fileDistributorConfig;
    std::unique_ptr<FiledistributorrpcConfig> _rpcConfig;

    boost::shared_ptr<ExceptionRethrower> _exceptionRethrower;
    std::unique_ptr<Components> _components;
public:
    FileDistributor()
        : _configMutex(),
          _completeReconfigurationNeeded(false),
          _zooKeepersConfig(),
          _fileDistributorConfig(),
          _rpcConfig(),
          _exceptionRethrower(),
          _components()
    { }

    void notifyGenerationChange(int64_t generation) {
        if (_components && ! completeReconfigurationNeeded()) {
            _components->updatedConfig(generation);
        }
    }

    //configure overrides
    void configure(std::unique_ptr<ZookeepersConfig> config) {
        LockGuard guard(_configMutex);
        _zooKeepersConfig = std::move(config);
        _completeReconfigurationNeeded = true;
    }

    void configure(std::unique_ptr<FiledistributorConfig> config) {
        LockGuard guard(_configMutex);
        if (_fileDistributorConfig.get() != NULL &&
            (config->torrentport != _fileDistributorConfig->torrentport ||
             config->stateport   != _fileDistributorConfig->stateport ||
             config->hostname    != _fileDistributorConfig->hostname ||
             config->filedbpath  != _fileDistributorConfig->filedbpath))
        {
            _completeReconfigurationNeeded = true;
        } else if (_components.get()) {
            configureSpeedLimits(*config);
        }
        _fileDistributorConfig = std::move(config);

    }

    void configure(std::unique_ptr<FiledistributorrpcConfig> config) {
        LockGuard guard(_configMutex);
        _rpcConfig = std::move(config);
        _completeReconfigurationNeeded = true;
    }

    void run(const config::ConfigUri & configUri) {
        while (!askedToShutDown()) {
            clearReinitializeFlag();
            _exceptionRethrower.reset(new ExceptionRethrower());
            runImpl(configUri);

            if (_exceptionRethrower->exceptionStored())
                _exceptionRethrower->rethrow();
        }
    }

    static void ensureExceptionsStored(const boost::shared_ptr<ExceptionRethrower>& exceptionRethrower) {
        //TODO: this is somewhat hackish, refactor to eliminate this later.
        LOG(debug, "Waiting for shutdown");
        for (int i=0;
             i<50 && !exceptionRethrower.unique();
                ++i) {
            boost::this_thread::sleep(boost::posix_time::milliseconds(100));
        }
        LOG(debug, "Done waiting for shutdown");

        if (!exceptionRethrower.unique()) {
            EV_STOPPING(programName, "Forced termination");
            kill(getpid(), SIGKILL);
        }
    }

    void createComponents(const boost::shared_ptr<ExceptionRethrower>& exceptionRethrower, const config::ConfigUri & configUri) {
        LockGuard guard(_configMutex);
        _components.reset(
                new Components(exceptionRethrower,
                        configUri,
                        *_zooKeepersConfig,
                        *_fileDistributorConfig,
                        *_rpcConfig));

        configureSpeedLimits(*_fileDistributorConfig);
        _completeReconfigurationNeeded = false;
    }

    bool completeReconfigurationNeeded() {
        LockGuard guard(_configMutex);
        if (_completeReconfigurationNeeded) {
            LOG(debug, "Complete reconfiguration needed");
        }
        return _completeReconfigurationNeeded;
    }

    void configureSpeedLimits(const FiledistributorConfig& config) {
        FileDownloader& downloader = *_components->_downloader;
        downloader.setMaxDownloadSpeed(config.maxdownloadspeed);
        downloader.setMaxUploadSpeed(config.maxuploadspeed);
    }

    //avoid warning due to scope exit macro
#pragma GCC diagnostic ignored "-Wshadow"
    void runImpl(const config::ConfigUri & configUri) {

        BOOST_SCOPE_EXIT((&_components)(&_exceptionRethrower)) {
            _components.reset();
            //Ensures that any exception stored during destruction will be available when returning.
            ensureExceptionsStored(_exceptionRethrower);
        } BOOST_SCOPE_EXIT_END

        createComponents(_exceptionRethrower, configUri);

        // We do not want back to back reinitializing as it gives zero time for serving
        // some torrents.
        int postPoneAskedToReinitializedSecs = 50;

        while (!askedToShutDown() &&
	       (postPoneAskedToReinitializedSecs > 0 || !askedToReinitialize()) &&
	       !completeReconfigurationNeeded() &&
	       !_exceptionRethrower->exceptionStored()) {
	  postPoneAskedToReinitializedSecs--;
	  boost::this_thread::sleep(boost::posix_time::seconds(1));
        }
    }
};

//TODO: use pop in gcc 4.6
#pragma GCC diagnostic warning "-Wshadow"

class FileDistributorApplication : public FastOS_Application {
    const config::ConfigUri _configUri;
public:
    FileDistributorApplication(const config::ConfigUri & configUri);

    //overrides
    int Main();
};

namespace {

struct ProgramOptionException {
    std::string _msg;
    ProgramOptionException(const std::string & msg)
        : _msg(msg)
    {}
};

bool exists(const std::string& optionName, const boost::program_options::variables_map& map) {
    return map.find(optionName) != map.end();
}

void ensureExists(const std::string& optionName, const boost::program_options::variables_map& map \
                  ) {
    if (!exists(optionName, map)) {
        throw ProgramOptionException("Error: Missing option " + optionName);
    }
}

} //anonymous namespace

FileDistributorApplication::FileDistributorApplication(const config::ConfigUri & configUri)
    :_configUri(configUri) {
}

int
FileDistributorApplication::Main() {
    try {
        FileDistributor distributor;

        config::ConfigFetcher configFetcher(_configUri.getContext());
        configFetcher.subscribe<ZookeepersConfig>(_configUri.getConfigId(), &distributor);
        configFetcher.subscribe<FiledistributorConfig>(_configUri.getConfigId(), &distributor);
        configFetcher.subscribe<FiledistributorrpcConfig>(_configUri.getConfigId(), &distributor);
        configFetcher.subscribeGenerationChanges(&distributor);
        configFetcher.start();

        distributor.run(_configUri);

        EV_STOPPING(programName, "Clean exit");
        return 0;
    } catch(const FileDoesNotExistException & e) {
        std::string s = boost::diagnostic_information(e);
        EV_STOPPING(programName, s.c_str());
        return 1;
    } catch(const ZKNodeDoesNotExistsException & e) {
        std::string s = boost::diagnostic_information(e);
        EV_STOPPING(programName, s.c_str());
        return 2;
    } catch(const ZKSessionExpired & e) {
        std::string s = boost::diagnostic_information(e);
        EV_STOPPING(programName, s.c_str());
        return 3;
    } catch(const config::ConfigTimeoutException & e) {
        std::string s = boost::diagnostic_information(e);
        EV_STOPPING(programName, s.c_str());
        return 4;
    } catch(const ZKGenericException & e) {
        std::string s = boost::diagnostic_information(e);
        EV_STOPPING(programName, s.c_str());
        return 99;
    } catch(const boost::unknown_exception & e) {
        std::string s = boost::diagnostic_information(e);
        LOG(warning, "Caught '%s'", s.c_str());
        EV_STOPPING(programName, s.c_str());
        return 255;
#if 0
    /*
     These are kept hanging around for reference as to how it was when we just held our ears
     singing "na, na, na, na..." no matter if the sun was shining or if the world imploded.
    */
    } catch(const boost::exception& e) {
        std::string s = boost::diagnostic_information(e);
        LOG(error, "Caught '%s'", s.c_str());
        EV_STOPPING(programName, s.c_str());
        return -1;
    } catch(const std::string& msg) {
        std::string s = "Error: " + msg;
        LOG(error, "Caught '%s'", s.c_str());
        EV_STOPPING(programName, s.c_str());
        return -1;
#endif
    }
}

int
executeApplication(int argc, char** argv) {
    const char
        *configId("configid"),
        *help("help");

    namespace po = boost::program_options;
    po::options_description description;
    description.add_options()
        (configId, po::value<std::string > (), "id to request config for")
        (help, "help");

    try {
        po::variables_map values;
        po::store(
                po::parse_command_line(argc, argv, description),
                values);

        if (exists(help, values)) {
            std::cout <<description;
            return 0;
        }
        ensureExists(configId, values);

        FileDistributorApplication application(
                values[configId].as<std::string > ());
        return application.Entry(argc, argv);

    } catch(ProgramOptionException& e) {
        std::cerr <<e._msg <<std::endl;
        return -1;
    }
}

void terminate() {
    std::cerr <<"Terminate called: " <<std::endl;
    Backtrace backtrace;
    std::cerr <<backtrace <<std::endl;
}

int
main(int argc, char** argv) {
    EV_STARTED(programName);
    initSignals();

    std::srand(std::time(0));
    std::set_terminate(terminate);
    filedistribution::setupZooKeeperLogging();

    return executeApplication(argc, argv);
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include "fnord-base/io/filerepository.h"
#include "fnord-base/io/fileutil.h"
#include "fnord-base/application.h"
#include "fnord-base/logging.h"
#include "fnord-base/random.h"
#include "fnord-base/thread/eventloop.h"
#include "fnord-base/thread/threadpool.h"
#include "fnord-base/wallclock.h"
#include "fnord-base/util/SimpleRateLimit.h"
#include "fnord-rpc/ServerGroup.h"
#include "fnord-rpc/RPC.h"
#include "fnord-rpc/RPCClient.h"
#include "fnord-base/cli/flagparser.h"
#include "fnord-json/json.h"
#include "fnord-json/jsonrpc.h"
#include "fnord-http/httprouter.h"
#include "fnord-http/httpserver.h"
#include "fnord-feeds/FeedService.h"
#include "fnord-feeds/RemoteFeedFactory.h"
#include "fnord-feeds/RemoteFeedReader.h"
#include "fnord-base/stats/statsdagent.h"
#include "fnord-sstable/sstablereader.h"
#include "fnord-logtable/RemoteTableReader.h"
#include "fnord-logtable/LogTableTail.h"
#include "fnord-mdb/MDB.h"
#include "fnord-msg/MessagePrinter.h"
#include "CustomerNamespace.h"
#include "FeatureSchema.h"
#include "FeatureIndexWriter.h"
#include "IndexChangeRequest.h"
#include "IndexWriter.h"
#include "schemas.h"

using namespace cm;
using namespace fnord;

fnord::thread::EventLoop ev;

int main(int argc, const char** argv) {
  Application::init();
  Application::logToStderr();

  cli::FlagParser flags;

  flags.defineFlag(
      "index",
      cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "index dir",
      "<path>");

  flags.defineFlag(
      "statsd_addr",
      fnord::cli::FlagParser::T_STRING,
      false,
      NULL,
      "127.0.0.1:8192",
      "Statsd addr",
      "<addr>");

  flags.defineFlag(
      "batch_size",
      fnord::cli::FlagParser::T_INTEGER,
      false,
      NULL,
      "2048",
      "batch_size",
      "<num>");

  flags.defineFlag(
      "db_size",
      fnord::cli::FlagParser::T_INTEGER,
      false,
      NULL,
      "128",
      "max db size",
      "<MB>");

  flags.defineFlag(
      "loglevel",
      fnord::cli::FlagParser::T_STRING,
      false,
      NULL,
      "INFO",
      "loglevel",
      "<level>");

  flags.parseArgv(argc, argv);

  Logger::get()->setMinimumLogLevel(
      strToLogLevel(flags.getString("loglevel")));

  auto evloop_thread = std::thread([] {
    ev.run();
  });

  http::HTTPConnectionPool http(&ev);

  /* open index */
  fnord::logInfo(
      "cm.indexbuild",
      "Opening index at $0",
      flags.getString("index"));

  FeatureIndexWriter index(
      flags.getString("index"),
      "documents-dawanda",
      false);

  /* open logtable */
  RefPtr<logtable::RemoteTableReader> table(new logtable::RemoteTableReader(
      "index_feed-dawanda",
      indexChangeRequestSchema(),
      URI("http://nue03.prod.fnrd.net:7009/logtable"),
      &http));

  /* open logtable tail at last cursor */
  RefPtr<logtable::LogTableTail> tail(nullptr);
  auto last_cursor = index.getCursor();
  if (last_cursor.isEmpty()) {
    tail = RefPtr<logtable::LogTableTail>(
        new logtable::LogTableTail(table.get()));
  } else {
    util::BinaryMessageReader reader(
        last_cursor.get().data(),
        last_cursor.get().size());

    logtable::LogTableTailCursor cursor;
    cursor.decode(&reader);

    fnord::logInfo(
        "cm.indexbuild",
        "Resuming from cursor: $0",
        cursor.debugPrint());

    tail = RefPtr<logtable::LogTableTail>(
        new logtable::LogTableTail(table.get(), cursor));
  }

  /* start stats reporting */
  fnord::stats::StatsdAgent statsd_agent(
      fnord::net::InetAddr::resolve(flags.getString("statsd_addr")),
      10 * fnord::kMicrosPerSecond);

  statsd_agent.start();

  /* on record callback fn */
  auto schema = indexChangeRequestSchema();
  auto on_record = [&schema, &index] (const msg::MessageObject& rec) -> bool {
    Vector<Pair<String, String>> attrs;
    for (const auto& attr : rec.getObjects(schema.id("attributes"))) {
      auto key = attr->getString(schema.id("attributes.key"));
      auto value = attr->getString(schema.id("attributes.value"));

      if (isIndexAttributeWhitelisted(key)) {
        attrs.emplace_back(key, value);
      }
    }

    DocID docid { .docid = rec.getString(schema.id("docid")) };
    index.updateDocument(docid, attrs);

    return true;
  };

  /* fetch from logtable in batches */
  auto batch_size = flags.getInt("batch_size");
  for (;;) {
    tail->fetchNext(on_record, batch_size);

    auto cursor = tail->getCursor();
    util::BinaryMessageWriter cursor_buf;
    cursor.encode(&cursor_buf);

    fnord::logInfo(
        "cm.indexbuild",
        "Comitting with cursor: $0",
        cursor.debugPrint());

    index.saveCursor(cursor_buf.data(), cursor_buf.size());
    index.commit();
  }

  /* sthudown */
  ev.shutdown();
  evloop_thread.join();

  fnord::logInfo("cm.indexbuild", "Exiting...");
  return 0;
}

<commit_msg>--fetch_from<commit_after>/**
 * Copyright (c) 2015 - The CM Authors <legal@clickmatcher.com>
 *   All Rights Reserved.
 *
 * This file is CONFIDENTIAL -- Distribution or duplication of this material or
 * the information contained herein is strictly forbidden unless prior written
 * permission is obtained.
 */
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include "fnord-base/io/filerepository.h"
#include "fnord-base/io/fileutil.h"
#include "fnord-base/application.h"
#include "fnord-base/logging.h"
#include "fnord-base/random.h"
#include "fnord-base/thread/eventloop.h"
#include "fnord-base/thread/threadpool.h"
#include "fnord-base/wallclock.h"
#include "fnord-base/util/SimpleRateLimit.h"
#include "fnord-rpc/ServerGroup.h"
#include "fnord-rpc/RPC.h"
#include "fnord-rpc/RPCClient.h"
#include "fnord-base/cli/flagparser.h"
#include "fnord-json/json.h"
#include "fnord-json/jsonrpc.h"
#include "fnord-http/httprouter.h"
#include "fnord-http/httpserver.h"
#include "fnord-feeds/FeedService.h"
#include "fnord-feeds/RemoteFeedFactory.h"
#include "fnord-feeds/RemoteFeedReader.h"
#include "fnord-base/stats/statsdagent.h"
#include "fnord-sstable/sstablereader.h"
#include "fnord-logtable/RemoteTableReader.h"
#include "fnord-logtable/LogTableTail.h"
#include "fnord-mdb/MDB.h"
#include "fnord-msg/MessagePrinter.h"
#include "CustomerNamespace.h"
#include "FeatureSchema.h"
#include "FeatureIndexWriter.h"
#include "IndexChangeRequest.h"
#include "IndexWriter.h"
#include "schemas.h"

using namespace cm;
using namespace fnord;

fnord::thread::EventLoop ev;

int main(int argc, const char** argv) {
  Application::init();
  Application::logToStderr();

  cli::FlagParser flags;

  flags.defineFlag(
      "index",
      cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "index dir",
      "<path>");

  flags.defineFlag(
      "fetch_from",
      fnord::cli::FlagParser::T_STRING,
      true,
      NULL,
      NULL,
      "feed source",
      "<addr>");

  flags.defineFlag(
      "statsd_addr",
      fnord::cli::FlagParser::T_STRING,
      false,
      NULL,
      "127.0.0.1:8192",
      "Statsd addr",
      "<addr>");

  flags.defineFlag(
      "batch_size",
      fnord::cli::FlagParser::T_INTEGER,
      false,
      NULL,
      "2048",
      "batch_size",
      "<num>");

  flags.defineFlag(
      "db_size",
      fnord::cli::FlagParser::T_INTEGER,
      false,
      NULL,
      "128",
      "max db size",
      "<MB>");

  flags.defineFlag(
      "loglevel",
      fnord::cli::FlagParser::T_STRING,
      false,
      NULL,
      "INFO",
      "loglevel",
      "<level>");

  flags.parseArgv(argc, argv);

  Logger::get()->setMinimumLogLevel(
      strToLogLevel(flags.getString("loglevel")));

  auto evloop_thread = std::thread([] {
    ev.run();
  });

  http::HTTPConnectionPool http(&ev);

  /* open index */
  fnord::logInfo(
      "cm.indexbuild",
      "Opening index at $0",
      flags.getString("index"));

  FeatureIndexWriter index(
      flags.getString("index"),
      "documents-dawanda",
      false);

  /* open logtable */
  RefPtr<logtable::RemoteTableReader> table(new logtable::RemoteTableReader(
      "index_feed-dawanda",
      indexChangeRequestSchema(),
      URI(flags.getString("fetch_from")),
      &http));

  /* open logtable tail at last cursor */
  RefPtr<logtable::LogTableTail> tail(nullptr);
  auto last_cursor = index.getCursor();
  if (last_cursor.isEmpty()) {
    tail = RefPtr<logtable::LogTableTail>(
        new logtable::LogTableTail(table.get()));
  } else {
    util::BinaryMessageReader reader(
        last_cursor.get().data(),
        last_cursor.get().size());

    logtable::LogTableTailCursor cursor;
    cursor.decode(&reader);

    fnord::logInfo(
        "cm.indexbuild",
        "Resuming from cursor: $0",
        cursor.debugPrint());

    tail = RefPtr<logtable::LogTableTail>(
        new logtable::LogTableTail(table.get(), cursor));
  }

  /* start stats reporting */
  fnord::stats::StatsdAgent statsd_agent(
      fnord::net::InetAddr::resolve(flags.getString("statsd_addr")),
      10 * fnord::kMicrosPerSecond);

  statsd_agent.start();

  /* on record callback fn */
  auto schema = indexChangeRequestSchema();
  auto on_record = [&schema, &index] (const msg::MessageObject& rec) -> bool {
    Vector<Pair<String, String>> attrs;
    for (const auto& attr : rec.getObjects(schema.id("attributes"))) {
      auto key = attr->getString(schema.id("attributes.key"));
      auto value = attr->getString(schema.id("attributes.value"));

      if (isIndexAttributeWhitelisted(key)) {
        attrs.emplace_back(key, value);
      }
    }

    DocID docid { .docid = rec.getString(schema.id("docid")) };
    index.updateDocument(docid, attrs);

    return true;
  };

  /* fetch from logtable in batches */
  auto batch_size = flags.getInt("batch_size");
  for (;;) {
    tail->fetchNext(on_record, batch_size);

    auto cursor = tail->getCursor();
    util::BinaryMessageWriter cursor_buf;
    cursor.encode(&cursor_buf);

    fnord::logInfo(
        "cm.indexbuild",
        "Comitting with cursor: $0",
        cursor.debugPrint());

    index.saveCursor(cursor_buf.data(), cursor_buf.size());
    index.commit();
  }

  /* sthudown */
  ev.shutdown();
  evloop_thread.join();

  fnord::logInfo("cm.indexbuild", "Exiting...");
  return 0;
}

<|endoftext|>


<commit_before>/*
   Mathieu Stefani, 16 janvier 2016

   Cookie implementation
*/

#include <iterator>
#include <unordered_map>

#include <pistache/cookie.h>
#include <pistache/stream.h>

using namespace std;

namespace Pistache {
namespace Http {

namespace {

    StreamCursor::Token matchValue(StreamCursor& cursor) {
        int c;
        if ((c = cursor.current()) != StreamCursor::Eof && c != '=')
            throw std::runtime_error("Invalid cookie");

        if (!cursor.advance(1))
            throw std::runtime_error("Invalid cookie, early eof");

        StreamCursor::Token token(cursor);
        match_until(';', cursor);

        return token;
    }

    template<typename T>
    struct AttributeMatcher;

    template<>
    struct AttributeMatcher<Optional<std::string>> {
        static void match(StreamCursor& cursor, Cookie* obj, Optional<std::string> Cookie::*attr) {
            auto token = matchValue(cursor);
            obj->*attr = Some(token.text());
        }
    };

    template<>
    struct AttributeMatcher<Optional<int>> {
        static void match(StreamCursor& cursor, Cookie* obj, Optional<int> Cookie::*attr) {
            auto token = matchValue(cursor);

            auto strntol = [](const char *str, size_t len) {
                int ret = 0;
                for (size_t i = 0; i < len; ++i) {
                    if (!isdigit(str[i]))
                        throw std::invalid_argument("Invalid conversion");

                    ret *= 10;
                    ret += str[i] - '0';
                };

                return ret;
            };

            obj->*attr = Some(strntol(token.rawText(), token.size()));
        }
    };

    template<>
    struct AttributeMatcher<bool> {
        static void match(StreamCursor& cursor, Cookie* obj, bool Cookie::*attr) {
            UNUSED(cursor)
            obj->*attr = true;
        }
    };

    template<>
    struct AttributeMatcher<Optional<FullDate>> {
        static void match(StreamCursor& cursor, Cookie* obj, Optional<FullDate> Cookie::*attr) {
            auto token = matchValue(cursor);
            obj->*attr = Some(FullDate::fromString(token.text()));
        }
    };

    template<typename T>
    bool match_attribute(const char* name, size_t len, StreamCursor& cursor, Cookie* obj, T Cookie::*attr) {
        if (match_string(name, len, cursor)) {
            AttributeMatcher<T>::match(cursor, obj, attr);
            cursor.advance(1);

            return true;
        }

        return false;
    }

}

Cookie::Cookie(std::string name, std::string value)
    : name(std::move(name))
    , value(std::move(value))
    , secure(false)
    , httpOnly(false)
{
}

Cookie
Cookie::fromRaw(const char* str, size_t len)
{
    std::cout<<"From Raw initiated with" << str <<" " << endl;

    RawStreamBuf<> buf(const_cast<char *>(str), len);
    StreamCursor cursor(&buf);

    StreamCursor::Token nameToken(cursor);

    if (!match_until('=', cursor))
        throw std::runtime_error("Invalid cookie, missing value");

    auto name = nameToken.text();

    if (!cursor.advance(1))
        throw std::runtime_error("Invalid cookie, missing value");

    StreamCursor::Token valueToken(cursor);

    match_until(';', cursor);
    auto value = valueToken.text();

    Cookie cookie(std::move(name), std::move(value));
    if (cursor.eof()) {
        return cookie;
    }

    cursor.advance(1);

#define STR(str) str, sizeof(str) - 1

    do {
        skip_whitespaces(cursor);

        if (match_attribute(STR("Path"), cursor, &cookie, &Cookie::path)) ;
        else if (match_attribute(STR("Domain"), cursor, &cookie, &Cookie::domain)) ;
        else if (match_attribute(STR("Secure"), cursor, &cookie, &Cookie::secure)) ;
        else if (match_attribute(STR("HttpOnly"), cursor, &cookie, &Cookie::httpOnly)) ;
        else if (match_attribute(STR("Max-Age"), cursor, &cookie, &Cookie::maxAge)) ;
        else if (match_attribute(STR("Expires"), cursor, &cookie, &Cookie::expires)) ;
        // ext
        else {
            StreamCursor::Token nameToken(cursor);
            match_until('=', cursor);

            auto name = nameToken.text();
            std::string value;
            if (!cursor.eof()) {
                auto token = matchValue(cursor);
                value = token.text();
            }
            cookie.ext.insert(std::make_pair(std::move(name), std::move(value)));

        }

    } while (!cursor.eof());

#undef STR

    return cookie;
}

Cookie
Cookie::fromString(const std::string& str) {
	std::cout<<"From String initiated with" << str <<" " << endl;
    return Cookie::fromRaw(str.c_str(), str.size());
}

void
Cookie::write(std::ostream& os) const {
    os << name << "=" << value;
    optionally_do(path, [&](const std::string& value) {
       os << "; ";
       os << "Path=" << value;
    });
    optionally_do(domain, [&](const std::string& value) {
        os << "; ";
        os << "Domain=" << value;
    });
    optionally_do(maxAge, [&](int value) {
        os << "; ";
        os << "Max-Age=" << value;
    });
    optionally_do(expires, [&](const FullDate& value) {
        os << "; ";
        os << "Expires=";
        value.write(os);
    });
    if (secure)
        os << "; Secure";
    if (httpOnly)
        os << "; HttpOnly";
    if (!ext.empty()) {
        os << "; ";
        for (auto it = std::begin(ext), end = std::end(ext); it != end; ++it) {
            os << it->first << "=" << it->second;
            if (std::distance(it, end) > 1)
                os << "; ";
        }
    }

}

CookieJar::CookieJar()
{
}

void
CookieJar::add(const Cookie& cookie) {

    std::string cookieName = cookie.name;
    std::string cookieValue = cookie.value;

    Storage::iterator it = cookies.find(cookieName);
    if(it == cookies.end()) {
        HashMapCookies hashmapWithFirstCookie;
        hashmapWithFirstCookie.insert(std::make_pair(cookieValue,cookie));
        cookies.insert(std::make_pair(cookieName, hashmapWithFirstCookie));
    } else {
        it->second.insert(std::make_pair(cookieValue,cookie));
    }

}

void // ADDED later with fix
CookieJar::removeCookie(const std::string& name) {
	// Empty for now, can be used later
}

void
CookieJar::addFromRaw(const char *str, size_t len) {
    RawStreamBuf<> buf(const_cast<char *>(str), len);
    StreamCursor cursor(&buf);

    while (!cursor.eof()) {
        StreamCursor::Token nameToken(cursor);

        if (!match_until('=', cursor))
            throw std::runtime_error("Invalid cookie, missing value");

        auto name = nameToken.text();

        if (!cursor.advance(1))
            throw std::runtime_error("Invalid cookie, missing value");

        StreamCursor::Token valueToken(cursor);

        match_until(';', cursor);
        auto value = valueToken.text();

        Cookie cookie(std::move(name), std::move(value));
        add(cookie);

        cursor.advance(1);
        skip_whitespaces(cursor);
    }
}

Cookie
CookieJar::get(const std::string& name) const {
    Storage::const_iterator it = cookies.find(name);
    if(it != cookies.end()) {
        return it->second.begin()->second;  // it returns begin(), first element, could be changed.
    }
    throw std::runtime_error("Could not find requested cookie");
}

bool
CookieJar::has(const std::string& name) const {
    return cookies.find(name) != cookies.end();
}

} // namespace Http
} // namespace Pistache
<commit_msg>Update cookie.cc<commit_after>/*
   Mathieu Stefani, 16 janvier 2016

   Cookie implementation
*/

#include <iterator>
#include <unordered_map>

#include <pistache/cookie.h>
#include <pistache/stream.h>

using namespace std;

namespace Pistache {
namespace Http {

namespace {

    StreamCursor::Token matchValue(StreamCursor& cursor) {
        int c;
        if ((c = cursor.current()) != StreamCursor::Eof && c != '=')
            throw std::runtime_error("Invalid cookie");

        if (!cursor.advance(1))
            throw std::runtime_error("Invalid cookie, early eof");

        StreamCursor::Token token(cursor);
        match_until(';', cursor);

        return token;
    }

    template<typename T>
    struct AttributeMatcher;

    template<>
    struct AttributeMatcher<Optional<std::string>> {
        static void match(StreamCursor& cursor, Cookie* obj, Optional<std::string> Cookie::*attr) {
            auto token = matchValue(cursor);
            obj->*attr = Some(token.text());
        }
    };

    template<>
    struct AttributeMatcher<Optional<int>> {
        static void match(StreamCursor& cursor, Cookie* obj, Optional<int> Cookie::*attr) {
            auto token = matchValue(cursor);

            auto strntol = [](const char *str, size_t len) {
                int ret = 0;
                for (size_t i = 0; i < len; ++i) {
                    if (!isdigit(str[i]))
                        throw std::invalid_argument("Invalid conversion");

                    ret *= 10;
                    ret += str[i] - '0';
                };

                return ret;
            };

            obj->*attr = Some(strntol(token.rawText(), token.size()));
        }
    };

    template<>
    struct AttributeMatcher<bool> {
        static void match(StreamCursor& cursor, Cookie* obj, bool Cookie::*attr) {
            UNUSED(cursor)
            obj->*attr = true;
        }
    };

    template<>
    struct AttributeMatcher<Optional<FullDate>> {
        static void match(StreamCursor& cursor, Cookie* obj, Optional<FullDate> Cookie::*attr) {
            auto token = matchValue(cursor);
            obj->*attr = Some(FullDate::fromString(token.text()));
        }
    };

    template<typename T>
    bool match_attribute(const char* name, size_t len, StreamCursor& cursor, Cookie* obj, T Cookie::*attr) {
        if (match_string(name, len, cursor)) {
            AttributeMatcher<T>::match(cursor, obj, attr);
            cursor.advance(1);

            return true;
        }

        return false;
    }

}

Cookie::Cookie(std::string name, std::string value)
    : name(std::move(name))
    , value(std::move(value))
    , secure(false)
    , httpOnly(false)
{
}

Cookie
Cookie::fromRaw(const char* str, size_t len)
{
    RawStreamBuf<> buf(const_cast<char *>(str), len);
    StreamCursor cursor(&buf);

    StreamCursor::Token nameToken(cursor);

    if (!match_until('=', cursor))
        throw std::runtime_error("Invalid cookie, missing value");

    auto name = nameToken.text();

    if (!cursor.advance(1))
        throw std::runtime_error("Invalid cookie, missing value");

    StreamCursor::Token valueToken(cursor);

    match_until(';', cursor);
    auto value = valueToken.text();

    Cookie cookie(std::move(name), std::move(value));
    if (cursor.eof()) {
        return cookie;
    }

    cursor.advance(1);

#define STR(str) str, sizeof(str) - 1

    do {
        skip_whitespaces(cursor);

        if (match_attribute(STR("Path"), cursor, &cookie, &Cookie::path)) ;
        else if (match_attribute(STR("Domain"), cursor, &cookie, &Cookie::domain)) ;
        else if (match_attribute(STR("Secure"), cursor, &cookie, &Cookie::secure)) ;
        else if (match_attribute(STR("HttpOnly"), cursor, &cookie, &Cookie::httpOnly)) ;
        else if (match_attribute(STR("Max-Age"), cursor, &cookie, &Cookie::maxAge)) ;
        else if (match_attribute(STR("Expires"), cursor, &cookie, &Cookie::expires)) ;
        // ext
        else {
            StreamCursor::Token nameToken(cursor);
            match_until('=', cursor);

            auto name = nameToken.text();
            std::string value;
            if (!cursor.eof()) {
                auto token = matchValue(cursor);
                value = token.text();
            }
            cookie.ext.insert(std::make_pair(std::move(name), std::move(value)));

        }

    } while (!cursor.eof());

#undef STR

    return cookie;
}

Cookie
Cookie::fromString(const std::string& str) {
    return Cookie::fromRaw(str.c_str(), str.size());
}

void
Cookie::write(std::ostream& os) const {
    os << name << "=" << value;
    optionally_do(path, [&](const std::string& value) {
       os << "; ";
       os << "Path=" << value;
    });
    optionally_do(domain, [&](const std::string& value) {
        os << "; ";
        os << "Domain=" << value;
    });
    optionally_do(maxAge, [&](int value) {
        os << "; ";
        os << "Max-Age=" << value;
    });
    optionally_do(expires, [&](const FullDate& value) {
        os << "; ";
        os << "Expires=";
        value.write(os);
    });
    if (secure)
        os << "; Secure";
    if (httpOnly)
        os << "; HttpOnly";
    if (!ext.empty()) {
        os << "; ";
        for (auto it = std::begin(ext), end = std::end(ext); it != end; ++it) {
            os << it->first << "=" << it->second;
            if (std::distance(it, end) > 1)
                os << "; ";
        }
    }

}

CookieJar::CookieJar()
{
}

void
CookieJar::add(const Cookie& cookie) {

    std::string cookieName = cookie.name;
    std::string cookieValue = cookie.value;

    Storage::iterator it = cookies.find(cookieName);
    if(it == cookies.end()) {
        HashMapCookies hashmapWithFirstCookie;
        hashmapWithFirstCookie.insert(std::make_pair(cookieValue,cookie));
        cookies.insert(std::make_pair(cookieName, hashmapWithFirstCookie));
    } else {
        it->second.insert(std::make_pair(cookieValue,cookie));
    }

}

void // Unimplemented
CookieJar::removeCookie(const std::string& name) {
	// Empty for now, can be used later
}

void
CookieJar::addFromRaw(const char *str, size_t len) {
    RawStreamBuf<> buf(const_cast<char *>(str), len);
    StreamCursor cursor(&buf);

    while (!cursor.eof()) {
        StreamCursor::Token nameToken(cursor);

        if (!match_until('=', cursor))
            throw std::runtime_error("Invalid cookie, missing value");

        auto name = nameToken.text();

        if (!cursor.advance(1))
            throw std::runtime_error("Invalid cookie, missing value");

        StreamCursor::Token valueToken(cursor);

        match_until(';', cursor);
        auto value = valueToken.text();

        Cookie cookie(std::move(name), std::move(value));
        add(cookie);

        cursor.advance(1);
        skip_whitespaces(cursor);
    }
}

Cookie
CookieJar::get(const std::string& name) const {
    Storage::const_iterator it = cookies.find(name);
    if(it != cookies.end()) {
        return it->second.begin()->second;  // it returns begin(), first element, could be changed.
    }
    throw std::runtime_error("Could not find requested cookie");
}

bool
CookieJar::has(const std::string& name) const {
    return cookies.find(name) != cookies.end();
}

} // namespace Http
} // namespace Pistache
<|endoftext|>