<commit_before>
// Includes.
#include "UI/MainWindow.h"
#include "UI/NodeItem.h"
#include "UI/ConnectionItem.h"
#include "App/App.h"
#include "App/Boundary/NodeProxy.h"
#include "App/Boundary/ConnectionProxy.h"

// Qt.
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QInputDialog>
#include <QMessageBox>
#include <QPushButton>
#include <QDialog>
#include <QLabel>
#include <QLineEdit>
#include <QGridLayout>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QTextEdit>
#include <QListWidget>
#include <QStringListModel>
#include <QGraphicsLineItem>
#include <QMouseEvent>
#include <QDrag>
#include <QMimeData>
#include <QCheckBox>

class ParametersDialog : public QDialog
{
public:

    ParametersDialog(const std::vector<std::string>& parameters, QWidget* parent = 0)
        : QDialog(parent)
    {
        QGridLayout* param_layout = new QGridLayout;

        for (int i = 0; i < (int)parameters.size(); ++i)
        {
            std::string parameter = parameters.at(i);
            QLabel* parameter_label = new QLabel(QString::fromStdString(parameter));
            QLineEdit* parameter_field = new QLineEdit;

            param_layout->addWidget(parameter_label, i, 0);
            param_layout->addWidget(parameter_field, i, 1);

            parameter_fields_.insert(parameter, parameter_field);
        }

        QPushButton* ok_button = new QPushButton(tr("Ok"));
        connect(ok_button, &QPushButton::clicked, this, &QDialog::accept);
        QPushButton* cancel_button = new QPushButton(tr("Cancel"));
        connect(cancel_button, &QPushButton::clicked, this, &QDialog::reject);

        ok_button->setFocus();

        QHBoxLayout* button_layout = new QHBoxLayout;
        button_layout->addStretch();
        button_layout->addWidget(ok_button);
        button_layout->addWidget(cancel_button);
        button_layout->addStretch();

        QVBoxLayout* layout = new QVBoxLayout;
        layout->addLayout(param_layout);
        layout->addLayout(button_layout);
        setLayout(layout);
    }

    std::map<std::string, std::string> parameterValues() const
    {
        std::map<std::string, std::string> result;

        foreach (std::string param, parameter_fields_.keys())
        {
            result[param] = parameter_fields_.value(param)->text().toStdString();
        }

        return result;
    }

    std::string valueForParameter(const std::string& parameter) const
    {
        return parameter_fields_[parameter]->text().toStdString();
    }

private:

    QMap<std::string, QLineEdit*> parameter_fields_;

};

class TypesWidget : public QListWidget
{
public:
    TypesWidget(QWidget* parent = nullptr) : QListWidget(parent) {}

protected:

    virtual void mousePressEvent(QMouseEvent* e)
    {
        QListWidget::mousePressEvent(e);
        if (e->button() == Qt::LeftButton)
        {
            drag_start_position_ = e->pos();
        }
    }

    virtual void mouseMoveEvent(QMouseEvent *e)
    {
        QListWidget::mouseMoveEvent(e);

        if ((e->buttons() & Qt::LeftButton) == 0)
        {
            return;
        }
        else
        {
            QDrag *drag = new QDrag(this);
            QMimeData *mimeData = new QMimeData;

            QListWidgetItem* item = itemAt(e->pos());
            if (item != nullptr)
            {
                QString text = item->text();
                mimeData->setData("node/type", text.toUtf8());
                drag->setMimeData(mimeData);
                drag->exec(Qt::CopyAction | Qt::MoveAction);
            }
        }
    }

private:

    QPoint drag_start_position_;

};

MainWindow::MainWindow(App *app, QWidget *parent)
    : QMainWindow(parent)
    , types_list_(nullptr)
    , scene_view_(nullptr)
    , log_view_(nullptr)
    , show_types_box_(nullptr)
    , scene_(nullptr)
    , app_(app)
    , temp_line_item_(new QGraphicsLineItem)
    , selected_connector_on_press_(false)
    , selected_output_node_id_("")
    , selected_output_index_(-1)
    , selected_input_node_id_("")
    , selected_input_index_(-1)
{
    scene_ = new QGraphicsScene;

    QPushButton* add_node_button = new QPushButton(tr("Add node"));
    connect(add_node_button, &QPushButton::clicked, this, &MainWindow::addNodeClicked);
    QPushButton* execute_button = new QPushButton(tr("Execute"));
    connect(execute_button, &QPushButton::clicked, this, &MainWindow::executeClicked);
    QPushButton* clear_button = new QPushButton(tr("Clear"));
    connect(clear_button, &QPushButton::clicked, this, &MainWindow::clearClicked);
    QPushButton* test_button = new QPushButton(tr("Test"));
    connect(test_button, &QPushButton::clicked, this, &MainWindow::testClicked);
    show_types_box_ = new QCheckBox(tr("Show types"));
    connect(show_types_box_, &QCheckBox::stateChanged, this, &MainWindow::showTypes);

    QHBoxLayout* toolbar_layout = new QHBoxLayout;
    toolbar_layout->addWidget(add_node_button);
    toolbar_layout->addWidget(execute_button);
    toolbar_layout->addWidget(clear_button);
    toolbar_layout->addWidget(test_button);
    toolbar_layout->addWidget(show_types_box_);
    toolbar_layout->addStretch();

    scene_view_ = new NetworkSceneView(scene_);
    scene_view_->setDelegate(this);
    scene_view_->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
    scene_view_->setAcceptDrops(true);

    QStringList types;
    std::vector<std::string> available_types = app->availableNodeTypes();
    for (int i = 0; i < (int)available_types.size(); ++i)
    {
        types << QString::fromStdString(available_types[i]);
    }
    types_list_ = new TypesWidget;
    types_list_->setMaximumWidth(150);
    types_list_->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
    types_list_->addItems(types);
    types_list_->setSelectionMode(QAbstractItemView::SingleSelection);

    QHBoxLayout* central_layout = new QHBoxLayout;
    central_layout->addWidget(types_list_);
    central_layout->addWidget(scene_view_);

    log_view_ = new QTextEdit();
    log_view_->setReadOnly(true);
    log_view_->setMaximumHeight(200);
    log_view_->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);

    QVBoxLayout* main_layout = new QVBoxLayout;
    main_layout->addLayout(toolbar_layout);
    main_layout->addLayout(central_layout);
    main_layout->addWidget(log_view_);

    QWidget* central_widget = new QWidget;
    central_widget->setLayout(main_layout);
    setCentralWidget(central_widget);

    Logger::instance().addDelegate(this);
}

MainWindow::~MainWindow()
{
    scene_view_->setScene(nullptr);
    delete scene_;
    delete temp_line_item_;
    node_items_.clear();
    connection_items_.clear();

    Logger::instance().removeDelegate(this);
}

std::string MainWindow::promptString(const std::string &message)
{
    std::string text = QInputDialog::getText(this, tr("Enter Input:"), QString::fromStdString(message)).toStdString();
    return text;
}

bool MainWindow::promptBool(const std::string &message)
{
    QMessageBox::StandardButton button = QMessageBox::question(this, tr("Enter Input:"), QString::fromStdString(message));
    return button == QMessageBox::Yes;
}

std::map<std::string, std::string> MainWindow::promptParameters(const std::vector<std::string> &parameters)
{
    ParametersDialog dialog(parameters, this);
    dialog.setWindowTitle(tr("Enter parameters:"));

    int result = dialog.exec();
    if (result == QDialog::Accepted)
    {
        return dialog.parameterValues();
    }
    else
    {
        return std::map<std::string, std::string>();
    }
}

void MainWindow::displayError(const std::string &message)
{
    QMessageBox::critical(this, "Error!", QString::fromStdString(message));
}

void MainWindow::nodeAdded(NodeProxy node)
{
    addNode(node, this->last_drop_pos_);
}

void MainWindow::connectionAdded(ConnectionProxy connection)
{
    NodeItem* output_node_item = node_items_.value(connection.outputNodeID());
    NodeItem* input_node_item = node_items_.value(connection.inputNodeID());

    ConnectionItem* item = new ConnectionItem(output_node_item, connection.outputIndex(),
                                              input_node_item, connection.inputIndex());
    scene_->addItem(item);

    QString connection_id = createConnectionID(connection.outputNodeID(), connection.outputIndex(),
                                               connection.inputNodeID(), connection.inputIndex());
    connection_items_.insert(connection_id, item);
}

void MainWindow::connectionRemoved(ConnectionProxy connection)
{
    QString connection_id = createConnectionID(connection.outputNodeID(), connection.outputIndex(),
                                               connection.inputNodeID(), connection.inputIndex());
    ConnectionItem* item = connection_items_[connection_id];
    connection_items_.remove(connection_id);

    scene_->removeItem(item);
    scene_->views().at(0)->repaint();

    delete item;
}

void MainWindow::logMessage(const std::string &message)
{
    log_view_->setTextColor(QColor(Qt::black));
    log_view_->append(QString::fromStdString(message));
}

void MainWindow::logError(const std::string &message)
{
    log_view_->setTextColor(QColor(Qt::red));
    log_view_->append(QString::fromStdString(message));
}

void MainWindow::networkSceneViewPressedAt(const QPoint &pos)
{
    selected_input_index_ = -1;
    selected_input_node_id_ = "";
    selected_output_index_ = -1;
    selected_output_node_id_ = "";

    selected_connector_on_press_ = selectInputIfUnderPos(pos) || selectOutputIfUnderPos(pos);

    if (selected_connector_on_press_)
    {
        QPointF item_pos = temp_line_item_->mapFromScene(scene_view_->mapToScene(pos));

        temp_line_.setPoints(item_pos, item_pos);
        temp_line_item_->setLine(temp_line_);
        scene_->addItem(temp_line_item_);
    }
}

void MainWindow::networkSceneViewReleasedAt(const QPoint &pos)
{
    if (temp_line_item_->scene() == scene_)
    {
        scene_->removeItem(temp_line_item_);
    }
    bool selected_connector_on_release = selectInputIfUnderPos(pos) || selectOutputIfUnderPos(pos);

    if (selected_connector_on_press_ && selected_connector_on_release)
    {
        addConnectionBetweenSelectedNodes();
    }

    selected_connector_on_press_ = false;
}

void MainWindow::networkSceneViewMoved(const QPoint &pos)
{
    if (selected_connector_on_press_)
    {
        QPointF item_pos = temp_line_item_->mapFromScene(scene_view_->mapToScene(pos));
        temp_line_.setP2(item_pos);
        temp_line_item_->setLine(temp_line_);
    }
}

void MainWindow::networkSceneViewNodeTypeDroppedAt(const QString &type, const QPoint &pos)
{
    std::string type_str = type.toStdString();
    last_drop_pos_ = pos;
    app_->createNode(type_str);
}

void MainWindow::nodeMoved(NodeItem *item)
{
    scene_->update(scene_view_->sceneRect());
}

bool MainWindow::selectInputIfUnderPos(const QPoint &pos)
{
    QPointF scene_pos = scene_view_->mapToScene(pos);
    NodeItem* item_under_pos = dynamic_cast<NodeItem*>(scene_->itemAt(scene_pos, scene_view_->transform()));

    if (item_under_pos != nullptr)
    {
        QPointF item_pos = item_under_pos->mapFromScene(scene_pos);

        int input_index = item_under_pos->indexOfInputUnder(item_pos);
        if (input_index != -1)
        {
            selected_input_index_ = input_index;
            selected_input_node_id_ = item_under_pos->nodeID();
            return true;
        }
        else
        {
            return false;
        }
    }
    else
    {
        return false;
    }
}

bool MainWindow::selectOutputIfUnderPos(const QPoint& pos)
{
    QPointF scene_pos = scene_view_->mapToScene(pos);
    NodeItem* item_under_pos = dynamic_cast<NodeItem*>(scene_->itemAt(scene_pos, scene_view_->transform()));

    if (item_under_pos != nullptr)
    {
        QPointF item_pos = item_under_pos->mapFromScene(scene_pos);

        int output_index = item_under_pos->indexOfOutputUnder(item_pos);
        if (output_index != -1)
        {
            selected_output_index_ = output_index;
            selected_output_node_id_ = item_under_pos->nodeID();
            return true;
        }
        else
        {
            return false;
        }
    }
    else
    {
        return false;
    }
}

void MainWindow::addNodeClicked()
{
    foreach (QListWidgetItem* item, types_list_->selectedItems())
    {
        std::string type = item->text().toStdString();
        last_drop_pos_ = QPoint(0,0);
        app_->createNode(type);
    }
}

void MainWindow::addNode(const NodeProxy &node, const QPoint &pos)
{
    NodeItem* node_item = new NodeItem(node, show_types_box_->isChecked());

    QPointF scene_pos = scene_view_->mapToScene(pos);
    QTransform transform;
    transform.translate(scene_pos.x(),scene_pos.y());
    node_item->setTransform(transform);

    scene_->addItem(node_item);
    node_items_.insert(node.id(), node_item);
    node_item->addDelegate(this);
}

void MainWindow::addConnectionBetweenSelectedNodes()
{
    if (selected_input_node_id_.empty() || selected_input_index_ == -1 ||
        selected_output_node_id_.empty() || selected_output_index_ == -1)
    {
        return;
    }
    else
    {
        app_->connectNodes(selected_output_node_id_,
                           selected_output_index_,
                           selected_input_node_id_,
                           selected_input_index_);
    }

}

QString MainWindow::createConnectionID(const std::string& outputNodeID, int outputIndex,
                                       const std::string& inputNodeID, int inputIndex) const
{
    QStringList list;

    list << QString::fromStdString(outputNodeID);
    list << QString::number(outputIndex);
    list << QString::fromStdString(inputNodeID);
    list << QString::number(inputIndex);

    return list.join(",");
}

void MainWindow::executeClicked()
{
    app_->executeTerminalNodes();
}

void MainWindow::clearClicked()
{
    bool ok = app_->clearAllNodes();

    if (ok)
    {
        scene_view_->setScene(nullptr);
        delete scene_;
        node_items_.clear();
        connection_items_.clear();

        scene_ = new QGraphicsScene;
        scene_view_->setScene(scene_);
    }
}

void MainWindow::testClicked()
{
    app_->addTestScenario();
}

void MainWindow::showTypes(int state)
{
    foreach (NodeItem* item, node_items_.values())
    {
        item->setShowIONames(state == Qt::Checked);
    }
    scene_->update(scene_view_->sceneRect());
}
<commit_msg>Remove implementation from MainWindow and include the moved implementation.<commit_after>
// Includes.
#include "UI/MainWindow.h"
#include "UI/NodeItem.h"
#include "UI/ConnectionItem.h"
#include "UI/ParametersDialog.h"
#include "App/App.h"
#include "App/Boundary/NodeProxy.h"
#include "App/Boundary/ConnectionProxy.h"

// Qt.
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QInputDialog>
#include <QMessageBox>
#include <QPushButton>
#include <QTextEdit>
#include <QListWidget>
#include <QStringListModel>
#include <QGraphicsLineItem>
#include <QMouseEvent>
#include <QDrag>
#include <QMimeData>
#include <QCheckBox>

class TypesWidget : public QListWidget
{
public:
    TypesWidget(QWidget* parent = nullptr) : QListWidget(parent) {}

protected:

    virtual void mousePressEvent(QMouseEvent* e)
    {
        QListWidget::mousePressEvent(e);
        if (e->button() == Qt::LeftButton)
        {
            drag_start_position_ = e->pos();
        }
    }

    virtual void mouseMoveEvent(QMouseEvent *e)
    {
        QListWidget::mouseMoveEvent(e);

        if ((e->buttons() & Qt::LeftButton) == 0)
        {
            return;
        }
        else
        {
            QDrag *drag = new QDrag(this);
            QMimeData *mimeData = new QMimeData;

            QListWidgetItem* item = itemAt(e->pos());
            if (item != nullptr)
            {
                QString text = item->text();
                mimeData->setData("node/type", text.toUtf8());
                drag->setMimeData(mimeData);
                drag->exec(Qt::CopyAction | Qt::MoveAction);
            }
        }
    }

private:

    QPoint drag_start_position_;

};

MainWindow::MainWindow(App *app, QWidget *parent)
    : QMainWindow(parent)
    , types_list_(nullptr)
    , scene_view_(nullptr)
    , log_view_(nullptr)
    , show_types_box_(nullptr)
    , scene_(nullptr)
    , app_(app)
    , temp_line_item_(new QGraphicsLineItem)
    , selected_connector_on_press_(false)
    , selected_output_node_id_("")
    , selected_output_index_(-1)
    , selected_input_node_id_("")
    , selected_input_index_(-1)
{
    scene_ = new QGraphicsScene;

    QPushButton* add_node_button = new QPushButton(tr("Add node"));
    connect(add_node_button, &QPushButton::clicked, this, &MainWindow::addNodeClicked);
    QPushButton* execute_button = new QPushButton(tr("Execute"));
    connect(execute_button, &QPushButton::clicked, this, &MainWindow::executeClicked);
    QPushButton* clear_button = new QPushButton(tr("Clear"));
    connect(clear_button, &QPushButton::clicked, this, &MainWindow::clearClicked);
    QPushButton* test_button = new QPushButton(tr("Test"));
    connect(test_button, &QPushButton::clicked, this, &MainWindow::testClicked);
    show_types_box_ = new QCheckBox(tr("Show types"));
    connect(show_types_box_, &QCheckBox::stateChanged, this, &MainWindow::showTypes);

    QHBoxLayout* toolbar_layout = new QHBoxLayout;
    toolbar_layout->addWidget(add_node_button);
    toolbar_layout->addWidget(execute_button);
    toolbar_layout->addWidget(clear_button);
    toolbar_layout->addWidget(test_button);
    toolbar_layout->addWidget(show_types_box_);
    toolbar_layout->addStretch();

    scene_view_ = new NetworkSceneView(scene_);
    scene_view_->setDelegate(this);
    scene_view_->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
    scene_view_->setAcceptDrops(true);

    QStringList types;
    std::vector<std::string> available_types = app->availableNodeTypes();
    for (int i = 0; i < (int)available_types.size(); ++i)
    {
        types << QString::fromStdString(available_types[i]);
    }
    types_list_ = new TypesWidget;
    types_list_->setMaximumWidth(150);
    types_list_->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
    types_list_->addItems(types);
    types_list_->setSelectionMode(QAbstractItemView::SingleSelection);

    QHBoxLayout* central_layout = new QHBoxLayout;
    central_layout->addWidget(types_list_);
    central_layout->addWidget(scene_view_);

    log_view_ = new QTextEdit();
    log_view_->setReadOnly(true);
    log_view_->setMaximumHeight(200);
    log_view_->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);

    QVBoxLayout* main_layout = new QVBoxLayout;
    main_layout->addLayout(toolbar_layout);
    main_layout->addLayout(central_layout);
    main_layout->addWidget(log_view_);

    QWidget* central_widget = new QWidget;
    central_widget->setLayout(main_layout);
    setCentralWidget(central_widget);

    Logger::instance().addDelegate(this);
}

MainWindow::~MainWindow()
{
    scene_view_->setScene(nullptr);
    delete scene_;
    delete temp_line_item_;
    node_items_.clear();
    connection_items_.clear();

    Logger::instance().removeDelegate(this);
}

std::string MainWindow::promptString(const std::string &message)
{
    std::string text = QInputDialog::getText(this, tr("Enter Input:"), QString::fromStdString(message)).toStdString();
    return text;
}

bool MainWindow::promptBool(const std::string &message)
{
    QMessageBox::StandardButton button = QMessageBox::question(this, tr("Enter Input:"), QString::fromStdString(message));
    return button == QMessageBox::Yes;
}

std::map<std::string, std::string> MainWindow::promptParameters(const std::vector<std::string> &parameters)
{
    ParametersDialog dialog(parameters, this);
    dialog.setWindowTitle(tr("Enter parameters:"));

    int result = dialog.exec();
    if (result == QDialog::Accepted)
    {
        return dialog.parameterValues();
    }
    else
    {
        return std::map<std::string, std::string>();
    }
}

void MainWindow::displayError(const std::string &message)
{
    QMessageBox::critical(this, "Error!", QString::fromStdString(message));
}

void MainWindow::nodeAdded(NodeProxy node)
{
    addNode(node, this->last_drop_pos_);
}

void MainWindow::connectionAdded(ConnectionProxy connection)
{
    NodeItem* output_node_item = node_items_.value(connection.outputNodeID());
    NodeItem* input_node_item = node_items_.value(connection.inputNodeID());

    ConnectionItem* item = new ConnectionItem(output_node_item, connection.outputIndex(),
                                              input_node_item, connection.inputIndex());
    scene_->addItem(item);

    QString connection_id = createConnectionID(connection.outputNodeID(), connection.outputIndex(),
                                               connection.inputNodeID(), connection.inputIndex());
    connection_items_.insert(connection_id, item);
}

void MainWindow::connectionRemoved(ConnectionProxy connection)
{
    QString connection_id = createConnectionID(connection.outputNodeID(), connection.outputIndex(),
                                               connection.inputNodeID(), connection.inputIndex());
    ConnectionItem* item = connection_items_[connection_id];
    connection_items_.remove(connection_id);

    scene_->removeItem(item);
    scene_->views().at(0)->repaint();

    delete item;
}

void MainWindow::logMessage(const std::string &message)
{
    log_view_->setTextColor(QColor(Qt::black));
    log_view_->append(QString::fromStdString(message));
}

void MainWindow::logError(const std::string &message)
{
    log_view_->setTextColor(QColor(Qt::red));
    log_view_->append(QString::fromStdString(message));
}

void MainWindow::networkSceneViewPressedAt(const QPoint &pos)
{
    selected_input_index_ = -1;
    selected_input_node_id_ = "";
    selected_output_index_ = -1;
    selected_output_node_id_ = "";

    selected_connector_on_press_ = selectInputIfUnderPos(pos) || selectOutputIfUnderPos(pos);

    if (selected_connector_on_press_)
    {
        QPointF item_pos = temp_line_item_->mapFromScene(scene_view_->mapToScene(pos));

        temp_line_.setPoints(item_pos, item_pos);
        temp_line_item_->setLine(temp_line_);
        scene_->addItem(temp_line_item_);
    }
}

void MainWindow::networkSceneViewReleasedAt(const QPoint &pos)
{
    if (temp_line_item_->scene() == scene_)
    {
        scene_->removeItem(temp_line_item_);
    }
    bool selected_connector_on_release = selectInputIfUnderPos(pos) || selectOutputIfUnderPos(pos);

    if (selected_connector_on_press_ && selected_connector_on_release)
    {
        addConnectionBetweenSelectedNodes();
    }

    selected_connector_on_press_ = false;
}

void MainWindow::networkSceneViewMoved(const QPoint &pos)
{
    if (selected_connector_on_press_)
    {
        QPointF item_pos = temp_line_item_->mapFromScene(scene_view_->mapToScene(pos));
        temp_line_.setP2(item_pos);
        temp_line_item_->setLine(temp_line_);
    }
}

void MainWindow::networkSceneViewNodeTypeDroppedAt(const QString &type, const QPoint &pos)
{
    std::string type_str = type.toStdString();
    last_drop_pos_ = pos;
    app_->createNode(type_str);
}

void MainWindow::nodeMoved(NodeItem *item)
{
    scene_->update(scene_view_->sceneRect());
}

bool MainWindow::selectInputIfUnderPos(const QPoint &pos)
{
    QPointF scene_pos = scene_view_->mapToScene(pos);
    NodeItem* item_under_pos = dynamic_cast<NodeItem*>(scene_->itemAt(scene_pos, scene_view_->transform()));

    if (item_under_pos != nullptr)
    {
        QPointF item_pos = item_under_pos->mapFromScene(scene_pos);

        int input_index = item_under_pos->indexOfInputUnder(item_pos);
        if (input_index != -1)
        {
            selected_input_index_ = input_index;
            selected_input_node_id_ = item_under_pos->nodeID();
            return true;
        }
        else
        {
            return false;
        }
    }
    else
    {
        return false;
    }
}

bool MainWindow::selectOutputIfUnderPos(const QPoint& pos)
{
    QPointF scene_pos = scene_view_->mapToScene(pos);
    NodeItem* item_under_pos = dynamic_cast<NodeItem*>(scene_->itemAt(scene_pos, scene_view_->transform()));

    if (item_under_pos != nullptr)
    {
        QPointF item_pos = item_under_pos->mapFromScene(scene_pos);

        int output_index = item_under_pos->indexOfOutputUnder(item_pos);
        if (output_index != -1)
        {
            selected_output_index_ = output_index;
            selected_output_node_id_ = item_under_pos->nodeID();
            return true;
        }
        else
        {
            return false;
        }
    }
    else
    {
        return false;
    }
}

void MainWindow::addNodeClicked()
{
    foreach (QListWidgetItem* item, types_list_->selectedItems())
    {
        std::string type = item->text().toStdString();
        last_drop_pos_ = QPoint(0,0);
        app_->createNode(type);
    }
}

void MainWindow::addNode(const NodeProxy &node, const QPoint &pos)
{
    NodeItem* node_item = new NodeItem(node, show_types_box_->isChecked());

    QPointF scene_pos = scene_view_->mapToScene(pos);
    QTransform transform;
    transform.translate(scene_pos.x(),scene_pos.y());
    node_item->setTransform(transform);

    scene_->addItem(node_item);
    node_items_.insert(node.id(), node_item);
    node_item->addDelegate(this);
}

void MainWindow::addConnectionBetweenSelectedNodes()
{
    if (selected_input_node_id_.empty() || selected_input_index_ == -1 ||
        selected_output_node_id_.empty() || selected_output_index_ == -1)
    {
        return;
    }
    else
    {
        app_->connectNodes(selected_output_node_id_,
                           selected_output_index_,
                           selected_input_node_id_,
                           selected_input_index_);
    }

}

QString MainWindow::createConnectionID(const std::string& outputNodeID, int outputIndex,
                                       const std::string& inputNodeID, int inputIndex) const
{
    QStringList list;

    list << QString::fromStdString(outputNodeID);
    list << QString::number(outputIndex);
    list << QString::fromStdString(inputNodeID);
    list << QString::number(inputIndex);

    return list.join(",");
}

void MainWindow::executeClicked()
{
    app_->executeTerminalNodes();
}

void MainWindow::clearClicked()
{
    bool ok = app_->clearAllNodes();

    if (ok)
    {
        scene_view_->setScene(nullptr);
        delete scene_;
        node_items_.clear();
        connection_items_.clear();

        scene_ = new QGraphicsScene;
        scene_view_->setScene(scene_);
    }
}

void MainWindow::testClicked()
{
    app_->addTestScenario();
}

void MainWindow::showTypes(int state)
{
    foreach (NodeItem* item, node_items_.values())
    {
        item->setShowIONames(state == Qt::Checked);
    }
    scene_->update(scene_view_->sceneRect());
}
<|endoftext|>


<commit_before>// vi:cin:et:sw=4 ts=4
//
//  drafter.cc
//
//  Created by Jiri Kratochvil on 2015-02-11
//  Copyright (c) 2015 Apiary Inc. All rights reserved.
//
//
//

#include <string>
#include <iostream>
#include <sstream>
#include <fstream>

#include <tr1/memory>
#include <tr1/shared_ptr.h>

#include "snowcrash.h"
#include "SectionParserData.h"  // snowcrash::BlueprintParserOptions

#include "sos.h"
#include "sosJSON.h"
#include "sosYAML.h"

#include "SerializeAST.h"
#include "SerializeSourcemap.h"

#include "reporting.h"
#include "config.h"

namespace sc = snowcrash;

template<typename T>
struct dummy_deleter {
    void operator()(T* obj) const {
      // do nothing
    }
};

template<typename T> struct std_io;

template<> struct std_io<std::istream> {
    static std::istream* io() { return &std::cin; }
};

template<> struct std_io<std::ostream> {
    static std::ostream* io() { return &std::cout; }
};

template<typename T> struct std_io_selector {
    typedef T stream_type;
    typedef std::tr1::shared_ptr<stream_type> return_type;

    return_type operator()() { return return_type(std_io<T>::io(), dummy_deleter<stream_type>()); }
};

template <typename Stream> struct to_fstream;

template<>
struct to_fstream<std::istream>{
  typedef std::ifstream stream_type;
};

template<>
struct to_fstream<std::ostream>{
  typedef std::ofstream stream_type;
};

template<typename T> struct file_io_selector{
    typedef typename to_fstream<T>::stream_type stream_type;
    typedef std::tr1::shared_ptr<stream_type> return_type;

    return_type operator()(const char* name) const
    {
        return return_type(new stream_type(name));
    }
};

template<typename T>
std::tr1::shared_ptr<T> CreateStreamFromName(const std::string& file)
{
    if(file.empty()) {
        return std_io_selector<T>()();
    }

    typedef typename file_io_selector<T>::return_type return_type;

    return_type stream = file_io_selector<T>()(file.c_str());

    if (!stream->is_open()) {
      std::cerr << "fatal: unable to open file '" << file << "'\n";
      exit(EXIT_FAILURE);
    }

    return stream;
}

void Serialization(const std::string& out,
    const sos::Object& object,
    sos::Serialize* serializer)
{
    std::tr1::shared_ptr<std::ostream> stream = CreateStreamFromName<std::ostream>(out);
    serializer->process(object, *stream);
    *stream << std::endl;
}

sos::Serialize* CreateSerializer(const std::string& format)
{
    if(format == "json") {
        return new sos::SerializeJSON;
    } else if(format == "yaml") {
        return new sos::SerializeYAML;
    }

    std::cerr << "fatal: unknow serialization format: '" << format << "'\n";
    exit(EXIT_FAILURE);
}

int main(int argc, const char *argv[])
{
    Config config;
    ParseCommadLineOptions(argc, argv, config);

    sc::BlueprintParserOptions options = 0;  // Or snowcrash::RequireBlueprintNameOption
    if(!config.sourceMap.empty()) {
        options |= snowcrash::ExportSourcemapOption;
    }

    std::stringstream inputStream;
    std::tr1::shared_ptr<std::istream> in = CreateStreamFromName<std::istream>(config.input);
    inputStream << in->rdbuf();

    sc::ParseResult<sc::Blueprint> blueprint;
    sc::parse(inputStream.str(), options, blueprint);

    if (!config.validate) {
        sos::Serialize* serializer = CreateSerializer(config.format);

        Serialization(config.output,
            snowcrash::WrapBlueprint(blueprint.node),
            serializer
            );

        Serialization(config.sourceMap,
            snowcrash::WrapBlueprintSourcemap(blueprint.sourceMap),
            serializer
            );

        delete serializer;
    }

    PrintReport(blueprint.report, inputStream.str(), config.lineNumbers);

    return blueprint.report.error.code;

}
<commit_msg>* add some doc * remove Serializate() function - drop microoptimalization * rename template functor file_io_selector to more appropriate fstream_io_selector<commit_after>// vi:cin:et:sw=4 ts=4
//
//  drafter.cc
//
//  Created by Jiri Kratochvil on 2015-02-11
//  Copyright (c) 2015 Apiary Inc. All rights reserved.
//
//
//

#include <string>
#include <iostream>
#include <sstream>
#include <fstream>

#include <tr1/memory>
#include <tr1/shared_ptr.h>

#include "snowcrash.h"
#include "SectionParserData.h"  // snowcrash::BlueprintParserOptions

#include "sos.h"
#include "sosJSON.h"
#include "sosYAML.h"

#include "SerializeAST.h"
#include "SerializeSourcemap.h"

#include "reporting.h"
#include "config.h"

namespace sc = snowcrash;

/**
 *  \brief deleter functor to shared_ptr<> which does nothing
 *  usefull to get system resource like std::cin, std::cout to shared_ptr<>
 */
template<typename T>
struct dummy_deleter {
    void operator()(T* obj) const
    {
      // do nothing
    }
};

/**
 *  \brief functor returns cin/cout ptr in based on istream or ostream
 */
template<typename T> struct std_io;

template<> struct std_io<std::istream> {
    std::istream* operator()() const
    {
        return &std::cin;
    }
};

template<> struct std_io<std::ostream> {
    std::ostream* operator()() const
    {
        return &std::cout;
    }
};

/**
 *  \brief functor returns appropriate cin/cout based on istream/ostream
 */
template<typename T> struct std_io_selector {
    typedef T stream_type;
    typedef std::tr1::shared_ptr<stream_type> return_type;

    return_type operator()() const
    {
        return return_type(std_io<T>()(), dummy_deleter<stream_type>());
    }
};

/**
 *  \brief functor select fstream based on iostream
 */
template <typename Stream> struct to_fstream;

template<>
struct to_fstream<std::istream>{
  typedef std::ifstream stream_type;
};

template<>
struct to_fstream<std::ostream>{
  typedef std::ofstream stream_type;
};

/**
 *  \brief functor select return appropriate opened fstream based on type of stream
 */
template<typename T> struct fstream_io_selector{
    typedef typename to_fstream<T>::stream_type stream_type;
    typedef std::tr1::shared_ptr<stream_type> return_type;

    return_type operator()(const char* name) const
    {
        return return_type(new stream_type(name));
    }
};

/**
 *  \brief return writable stream or report error and exit()
 *
 *  return is based on \template param T (must be std::ostream or std::istream)
 *
 *  For std::istream it return opened std::ifstream with filename as in \param `file`
 *  if \param `file` is empty it will return std::cin
 *
 *  In similar way it work for std::ostream
 *
 *  \param template<T> type of returned stream
 *  \param file - name of file to open for read/write if empty use standart input/output
 *
 */
template<typename T>
std::tr1::shared_ptr<T> CreateStreamFromName(const std::string& file)
{
    if(file.empty()) {
        return std_io_selector<T>()();
    }

    typedef typename fstream_io_selector<T>::return_type return_type;

    return_type stream = fstream_io_selector<T>()(file.c_str());

    if (!stream->is_open()) {
      std::cerr << "fatal: unable to open file '" << file << "'\n";
      exit(EXIT_FAILURE);
    }

    return stream;
}

/**
 *  \brief  return instance sos::Serializer based on \param `format`
 *
 *  \param format - output format for serialization
 */

sos::Serialize* CreateSerializer(const std::string& format)
{
    if(format == "json") {
        return new sos::SerializeJSON;
    } else if(format == "yaml") {
        return new sos::SerializeYAML;
    }

    std::cerr << "fatal: unknow serialization format: '" << format << "'\n";
    exit(EXIT_FAILURE);
}

int main(int argc, const char *argv[])
{
    Config config;
    ParseCommadLineOptions(argc, argv, config);

    sc::BlueprintParserOptions options = 0;  // Or snowcrash::RequireBlueprintNameOption
    if(!config.sourceMap.empty()) {
        options |= snowcrash::ExportSourcemapOption;
    }

    std::stringstream inputStream;
    std::tr1::shared_ptr<std::istream> in = CreateStreamFromName<std::istream>(config.input);
    inputStream << in->rdbuf();

    sc::ParseResult<sc::Blueprint> blueprint;
    sc::parse(inputStream.str(), options, blueprint);

    if (!config.validate) {  // not just validate -> we will serialize
        sos::Serialize* serializer = CreateSerializer(config.format);

        serializer->process(
            snowcrash::WrapBlueprint(blueprint.node),
            *CreateStreamFromName<std::ostream>(config.output)
            );

        serializer->process(
            snowcrash::WrapBlueprintSourcemap(blueprint.sourceMap),
            *CreateStreamFromName<std::ostream>(config.sourceMap)
            );

        delete serializer;
    }

    PrintReport(blueprint.report, inputStream.str(), config.lineNumbers);

    return blueprint.report.error.code;

}
<|endoftext|>


<commit_before>/*************************************************************************
 *   Copyright (C) 2011-2012 by Paul-Louis Ageneau                       *
 *   paul-louis (at) ageneau (dot) org                                   *
 *                                                                       *
 *   This file is part of Arcanet.                                       *
 *                                                                       *
 *   Arcanet is free software: you can redistribute it and/or modify     *
 *   it under the terms of the GNU Affero General Public License as      *
 *   published by the Free Software Foundation, either version 3 of      *
 *   the License, or (at your option) any later version.                 *
 *                                                                       *
 *   Arcanet 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 Affero General Public License for more details.                 *
 *                                                                       *
 *   You should have received a copy of the GNU Affero General Public    *
 *   License along with Arcanet.                                         *
 *   If not, see <http://www.gnu.org/licenses/>.                         *
 *************************************************************************/

#include "addressbook.h"
#include "core.h"
#include "sha512.h"
#include "config.h"

namespace arc
{

AddressBook::AddressBook(void)
{

}

AddressBook::~AddressBook(void)
{

}

const Identifier &AddressBook::addContact(String &name, String &secret)
{
	synchronize(this);

	Identifier peering;
	computePeering(name, secret, peering);

	Contact &contact = mContacts[peering];
	contact.name = name;
	contact.secret = secret;
	contact.peering = peering;

	contact.remotePeering.clear();
	computeRemotePeering(name, secret, contact.remotePeering);

	notify();
	return contact.peering;
}

void AddressBook::removeContact(Identifier &peering)
{
	synchronize(this);
 	mContacts.erase(peering);
}

void AddressBook::computePeering(const String &name, const ByteString &secret, ByteStream &out)
{
  	String agregate;
	agregate.writeLine(secret);
	agregate.writeLine(mLocalName);
	agregate.writeLine(name);
	Sha512::Hash(agregate, out, Sha512::CryptRounds);
}

void AddressBook::computeRemotePeering(const String &name, const ByteString &secret, ByteStream &out)
{
  	String agregate;
	agregate.writeLine(secret);
	agregate.writeLine(name);
	agregate.writeLine(mLocalName);
	Sha512::Hash(agregate, out, Sha512::CryptRounds);
}

void AddressBook::http(Http::Request &request)
{
	synchronize(this);

}

void AddressBook::run(void)
{
	synchronize(this);

	while(true)
	{
		for(Map<Identifier, Contact>::iterator it = mContacts.begin();
				      it != mContacts.end();
				      ++it)
		{
		    Contact &contact = it->second;

		    if(query(contact.peering, contact.addrs))
		    {
		    	if(!Core::Instance->hasPeer(contact.peering))
			{
				for(int i=0; i<contact.addrs.size(); ++i)
				{
					const Address &addr = contact.addrs[contact.addrs.size()-(i+1)];
					unlock();
					try {
						Socket *sock = new Socket(addr);
						Core::Instance->addPeer(sock, contact.peering, contact.remotePeering);
					}
					catch(...)
					{

					}
				}
			}
		    }

		    publish(contact.remotePeering);
		}

		wait(30*60*1000);
	}
}

bool AddressBook::publish(const Identifier &remotePeering)
{
	try {
		String url("http://" + Config::Get("tracker") + "/" + remotePeering.toString());

		StringMap post;
		post["port"] = Config::Get("port");
		if(Http::Post(url, post) != 200) return false;
	}
	catch(...)
	{
		// LOG
		return false;
	}
	return true;
}

bool AddressBook::query(const Identifier &peering, Array<Address> &addrs)
{
	try {
		String url("http://" + Config::Get("tracker") + "/" + peering.toString());

		String output;
		if(Http::Get(url, &output) != 200) return false;

		Address a;
		while(output.read(a))
			if(!addrs.contains(a))
				addrs.push_back(a);
	}
	catch(...)
	{
		// LOG
		return false;
	}
	return true;
}

}
<commit_msg>Added missing lock()<commit_after>/*************************************************************************
 *   Copyright (C) 2011-2012 by Paul-Louis Ageneau                       *
 *   paul-louis (at) ageneau (dot) org                                   *
 *                                                                       *
 *   This file is part of Arcanet.                                       *
 *                                                                       *
 *   Arcanet is free software: you can redistribute it and/or modify     *
 *   it under the terms of the GNU Affero General Public License as      *
 *   published by the Free Software Foundation, either version 3 of      *
 *   the License, or (at your option) any later version.                 *
 *                                                                       *
 *   Arcanet 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 Affero General Public License for more details.                 *
 *                                                                       *
 *   You should have received a copy of the GNU Affero General Public    *
 *   License along with Arcanet.                                         *
 *   If not, see <http://www.gnu.org/licenses/>.                         *
 *************************************************************************/

#include "addressbook.h"
#include "core.h"
#include "sha512.h"
#include "config.h"

namespace arc
{

AddressBook::AddressBook(void)
{

}

AddressBook::~AddressBook(void)
{

}

const Identifier &AddressBook::addContact(String &name, String &secret)
{
	synchronize(this);

	Identifier peering;
	computePeering(name, secret, peering);

	Contact &contact = mContacts[peering];
	contact.name = name;
	contact.secret = secret;
	contact.peering = peering;

	contact.remotePeering.clear();
	computeRemotePeering(name, secret, contact.remotePeering);

	notify();
	return contact.peering;
}

void AddressBook::removeContact(Identifier &peering)
{
	synchronize(this);
 	mContacts.erase(peering);
}

void AddressBook::computePeering(const String &name, const ByteString &secret, ByteStream &out)
{
  	String agregate;
	agregate.writeLine(secret);
	agregate.writeLine(mLocalName);
	agregate.writeLine(name);
	Sha512::Hash(agregate, out, Sha512::CryptRounds);
}

void AddressBook::computeRemotePeering(const String &name, const ByteString &secret, ByteStream &out)
{
  	String agregate;
	agregate.writeLine(secret);
	agregate.writeLine(name);
	agregate.writeLine(mLocalName);
	Sha512::Hash(agregate, out, Sha512::CryptRounds);
}

void AddressBook::http(Http::Request &request)
{
	synchronize(this);

}

void AddressBook::run(void)
{
	synchronize(this);

	while(true)
	{
		for(Map<Identifier, Contact>::iterator it = mContacts.begin();
				      it != mContacts.end();
				      ++it)
		{
		    Contact &contact = it->second;

		    if(query(contact.peering, contact.addrs))
		    {
		    	if(!Core::Instance->hasPeer(contact.peering))
			{
				for(int i=0; i<contact.addrs.size(); ++i)
				{
					const Address &addr = contact.addrs[contact.addrs.size()-(i+1)];
					unlock();
					try {
						Socket *sock = new Socket(addr);
						Core::Instance->addPeer(sock, contact.peering, contact.remotePeering);
					}
					catch(...)
					{

					}
					lock();
				}
			}
		    }

		    publish(contact.remotePeering);
		}

		wait(30*60*1000);
	}
}

bool AddressBook::publish(const Identifier &remotePeering)
{
	try {
		String url("http://" + Config::Get("tracker") + "/" + remotePeering.toString());

		StringMap post;
		post["port"] = Config::Get("port");
		if(Http::Post(url, post) != 200) return false;
	}
	catch(...)
	{
		// LOG
		return false;
	}
	return true;
}

bool AddressBook::query(const Identifier &peering, Array<Address> &addrs)
{
	try {
		String url("http://" + Config::Get("tracker") + "/" + peering.toString());

		String output;
		if(Http::Get(url, &output) != 200) return false;

		Address a;
		while(output.read(a))
			if(!addrs.contains(a))
				addrs.push_back(a);
	}
	catch(...)
	{
		// LOG
		return false;
	}
	return true;
}

}
<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <dirent.h>
#include <cstring>
#include <pwd.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <errno.h>
#include "agfs-server.hpp"
#include "constants.hpp"
#include "agfsio.hpp"

ClientConnection::ClientConnection(int connfd) {

	//Set timeout
	struct timeval tv;
	tv.tv_sec = SERVER_BLOCK_SEC;
	tv.tv_usec = SERVER_BLOCK_USEC;
	setsockopt(connfd, SOL_SOCKET, SO_RCVTIMEO, (struct timeval *)(&tv), sizeof(struct timeval));
	int iMode = 0;
	ioctl(connfd, FIONBIO, &iMode);

	//Verify server key
	char key[ASCII_KEY_LEN+1];
	memset(key, 0, ASCII_KEY_LEN+1);
	read(connfd, key, ASCII_KEY_LEN);

	std::fstream authkeys;
	authkeys.open(KEY_LIST_PATH, std::fstream::in);

	std::string clientKey{key};
	std::string mountPath, user, serverKey;
	bool validKey = false;

	while(!authkeys.eof()) {
		authkeys >> mountPath >> user >> serverKey;
		std::cout << "CLIENT: " << clientKey << std::endl;
		std::cout << "SERVER: " << serverKey << std::endl;
		std::cout << serverKey.length() << " " << clientKey.length() << std::endl;
		if(serverKey.compare(clientKey) == 0) {
			validKey = true;
			break;
		}
	}

	if(validKey == false) {
		agfs_write_cmd(connfd, cmd::INVALID_KEY);
		close(connfd);
		fd_ = -1;
		return;
	}

	//Change user
	struct passwd* userPwd = getpwnam(user.c_str());
	if(userPwd == NULL) {
		agfs_write_cmd(connfd, cmd::USER_NOT_FOUND);
		close(connfd);
		fd_ = -1;
		return;
	} else {
		setuid(userPwd->pw_uid);
		setgid(userPwd->pw_gid);
	}

	//Check that mount point exists
	if(!boost::filesystem::exists(mountPath)) {
		agfs_write_cmd(connfd, cmd::MOUNT_NOT_FOUND);
		close(connfd);
		fd_ = -1;
		return;
	}

	fd_ = connfd;
	mountPoint_ = mountPath;
}

bool ClientConnection::connected() {
	return fd_ > -1;
}

void ClientConnection::processCommands() {
	//Passed all checks accept connection and keep alive until heartbeat
	//failure or explicit stop
	agfs_write_cmd(fd_, cmd::ACCEPT);
	while(1) {
		cmd_t cmd = cmd::GETATTR;
		int respVal = agfs_read_cmd(fd_, cmd);
		if(respVal == -1) {
			std::cout << "Missed heartbeat" << std::endl;
		} else {
			switch(cmd) {
			case cmd::STOP:
				std::cerr << "STOP called" << std::endl;
				close(fd_);
				fd_ = -1;
				return;
			case cmd::HEARTBEAT:
				processHeartbeat();
				break;
			case cmd::GETATTR:
				std::cerr << "GETATTR called" << std::endl;
				processGetAttr();
				break;
			case cmd::READDIR:
				processReaddir();
				break;
			case cmd::ACCESS:
				processAccess();
				break;
			default:
				std::cerr << "Unknown command" << std::endl;
			}
		}
		//Do stuff here
	}
}

void ClientConnection::processHeartbeat() {
	agfs_write_cmd(fd_, cmd::HEARTBEAT);
}

/*
 * Incoming stack looks like:
 *
 *      STRING
 *
 * Outgoing stack looks like:
 *
 *      ERROR STAT
 */
void ClientConnection::processGetAttr() {
	std::string path;
	agfs_read_string(fd_, path);
	boost::filesystem::path fusePath{path};
	boost::filesystem::path file{mountPoint_};
	file /= fusePath;

	struct stat retValue;
	memset(&retValue, 0, sizeof(struct stat));
	agerr_t error;
	if ((error = lstat(file.c_str(), &retValue)) < 0) {
		error = errno;
	}

	agfs_write_error(fd_, error);
	agfs_write_stat(fd_, retValue);
}

/*
 * Incoming stack looks like:
 *
 *      STRING MASK
 *
 * Outgoing stack looks like:
 *
 *      ERROR
 */
void ClientConnection::processAccess() {
	std::string path;
	agfs_read_string(fd_, path);

	//Cosntruct the filepath
	boost::filesystem::path fusePath{path};
	boost::filesystem::path file{mountPoint_};
	file /= fusePath;

	//Grab the access mask.
	agmask_t mask;
	read(fd_, &mask, sizeof(agmask_t));

	//Attempt to access the file.
	agerr_t result = access(file.c_str(), mask);

	//Write our result
	agfs_write_error(fd_, result);
}

/*
 * Incoming stack looks like:
 *
 *      STRING
 *
 * Outgoing stack looks like:
 *
 *      ERROR COUNT STRING [STRING]*
 */
void ClientConnection::processReaddir() {
	std::string path;
	agfs_read_string(fd_, path);

	//Cosntruct the filepath
	boost::filesystem::path fusePath{path};
	boost::filesystem::path file{mountPoint_};
	file /= fusePath;

	agerr_t error = 0;
	if (!boost::filesystem::exists(file)) {
		error = ENOENT;
	}

	if (!boost::filesystem::is_directory(file)) {
		error = ENOTDIR;
	}
	agfs_write_error(fd_, -error);

	agsize_t count = 0;
	boost::filesystem::directory_iterator end_itr{};
	for (boost::filesystem::directory_iterator dir_itr(file);
		dir_itr != end_itr; count++) {
	}
	count = htobe64(count);
	write(fd_, &count, sizeof(agsize_t));

	for (boost::filesystem::directory_iterator dir_itr(file);
		dir_itr != end_itr; count++) {
		agfs_write_string(fd_, dir_itr->path().filename().c_str());
	}
}

<commit_msg>Trying to avoid problems with the stop command.<commit_after>#include <iostream>
#include <fstream>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <dirent.h>
#include <cstring>
#include <pwd.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <errno.h>
#include "agfs-server.hpp"
#include "constants.hpp"
#include "agfsio.hpp"

ClientConnection::ClientConnection(int connfd) {

	//Set timeout
	struct timeval tv;
	tv.tv_sec = SERVER_BLOCK_SEC;
	tv.tv_usec = SERVER_BLOCK_USEC;
	setsockopt(connfd, SOL_SOCKET, SO_RCVTIMEO, (struct timeval *)(&tv), sizeof(struct timeval));
	int iMode = 0;
	ioctl(connfd, FIONBIO, &iMode);

	//Verify server key
	char key[ASCII_KEY_LEN+1];
	memset(key, 0, ASCII_KEY_LEN+1);
	read(connfd, key, ASCII_KEY_LEN);

	std::fstream authkeys;
	authkeys.open(KEY_LIST_PATH, std::fstream::in);

	std::string clientKey{key};
	std::string mountPath, user, serverKey;
	bool validKey = false;

	while(!authkeys.eof()) {
		authkeys >> mountPath >> user >> serverKey;
		std::cout << "CLIENT: " << clientKey << std::endl;
		std::cout << "SERVER: " << serverKey << std::endl;
		std::cout << serverKey.length() << " " << clientKey.length() << std::endl;
		if(serverKey.compare(clientKey) == 0) {
			validKey = true;
			break;
		}
	}

	if(validKey == false) {
		agfs_write_cmd(connfd, cmd::INVALID_KEY);
		close(connfd);
		fd_ = -1;
		return;
	}

	//Change user
	struct passwd* userPwd = getpwnam(user.c_str());
	if(userPwd == NULL) {
		agfs_write_cmd(connfd, cmd::USER_NOT_FOUND);
		close(connfd);
		fd_ = -1;
		return;
	} else {
		setuid(userPwd->pw_uid);
		setgid(userPwd->pw_gid);
	}

	//Check that mount point exists
	if(!boost::filesystem::exists(mountPath)) {
		agfs_write_cmd(connfd, cmd::MOUNT_NOT_FOUND);
		close(connfd);
		fd_ = -1;
		return;
	}

	fd_ = connfd;
	mountPoint_ = mountPath;
}

bool ClientConnection::connected() {
	return fd_ > -1;
}

void ClientConnection::processCommands() {
	//Passed all checks accept connection and keep alive until heartbeat
	//failure or explicit stop
	agfs_write_cmd(fd_, cmd::ACCEPT);
	while(1) {
		cmd_t cmd = cmd::GETATTR;
		int respVal = agfs_read_cmd(fd_, cmd);
		if(respVal <= 0) {
			std::cout << "Missed heartbeat" << std::endl;
		} else {
			switch(cmd) {
			case cmd::STOP:
				std::cerr << "STOP called" << std::endl;
				close(fd_);
				fd_ = -1;
				return;
			case cmd::HEARTBEAT:
				processHeartbeat();
				break;
			case cmd::GETATTR:
				std::cerr << "GETATTR called" << std::endl;
				processGetAttr();
				break;
			case cmd::READDIR:
				processReaddir();
				break;
			case cmd::ACCESS:
				processAccess();
				break;
			default:
				std::cerr << "Unknown command" << std::endl;
			}
		}
		//Do stuff here
	}
}

void ClientConnection::processHeartbeat() {
	agfs_write_cmd(fd_, cmd::HEARTBEAT);
}

/*
 * Incoming stack looks like:
 *
 *      STRING
 *
 * Outgoing stack looks like:
 *
 *      ERROR STAT
 */
void ClientConnection::processGetAttr() {
	std::string path;
	agfs_read_string(fd_, path);
	boost::filesystem::path fusePath{path};
	boost::filesystem::path file{mountPoint_};
	file /= fusePath;

	struct stat retValue;
	memset(&retValue, 0, sizeof(struct stat));
	agerr_t error;
	if ((error = lstat(file.c_str(), &retValue)) < 0) {
		error = errno;
	}

	agfs_write_error(fd_, error);
	agfs_write_stat(fd_, retValue);
}

/*
 * Incoming stack looks like:
 *
 *      STRING MASK
 *
 * Outgoing stack looks like:
 *
 *      ERROR
 */
void ClientConnection::processAccess() {
	std::string path;
	agfs_read_string(fd_, path);

	//Cosntruct the filepath
	boost::filesystem::path fusePath{path};
	boost::filesystem::path file{mountPoint_};
	file /= fusePath;

	//Grab the access mask.
	agmask_t mask;
	read(fd_, &mask, sizeof(agmask_t));

	//Attempt to access the file.
	agerr_t result = access(file.c_str(), mask);

	//Write our result
	agfs_write_error(fd_, result);
}

/*
 * Incoming stack looks like:
 *
 *      STRING
 *
 * Outgoing stack looks like:
 *
 *      ERROR COUNT STRING [STRING]*
 */
void ClientConnection::processReaddir() {
	std::string path;
	agfs_read_string(fd_, path);

	//Cosntruct the filepath
	boost::filesystem::path fusePath{path};
	boost::filesystem::path file{mountPoint_};
	file /= fusePath;

	agerr_t error = 0;
	if (!boost::filesystem::exists(file)) {
		error = ENOENT;
	}

	if (!boost::filesystem::is_directory(file)) {
		error = ENOTDIR;
	}
	agfs_write_error(fd_, -error);

	agsize_t count = 0;
	boost::filesystem::directory_iterator end_itr{};
	for (boost::filesystem::directory_iterator dir_itr(file);
		dir_itr != end_itr; count++) {
	}
	count = htobe64(count);
	write(fd_, &count, sizeof(agsize_t));

	for (boost::filesystem::directory_iterator dir_itr(file);
		dir_itr != end_itr; count++) {
		agfs_write_string(fd_, dir_itr->path().filename().c_str());
	}
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2012-2014 Yule Fox. All rights reserved.
 * http://www.yulefox.com/
 */

#include <elf/db.h>
#include <elf/log.h>
#include <elf/memory.h>
#include <elf/pc.h>
#include <elf/thread.h>
#include <deque>
#include <map>
#include <string>

using namespace google::protobuf;

namespace elf {
struct db_req_t {
    bool read; // need restore query result
    std::string cmd; // sql command
    oid_t sid; // session id
};

struct db_res_t {
    int status; // status
    MYSQL_RES *data; // query result
    oid_t sid; // session id
};

struct session_t {
    oid_t id; // session id
    oid_t oid; // associated object id
    pb_t *out; // store query data
    std::string field; // pb field
    db_callback proc; // callback function
};

typedef std::map<oid_t, session_t *> session_list;

static session_list s_sessions;
static MYSQL *s_mysql = NULL;
static thread_t s_tid_req = 0;
static xqueue<db_req_t *> s_queue_req;
static xqueue<db_res_t *> s_queue_res;

static void *handle(void *args);
static void query(db_req_t *req);
static void retrieve(MYSQL_RES *res, pb_t *out);
static void retrieve(MYSQL_RES *res, pb_t *out, const std::string &field);

static void *handle(void *args)
{
    while (true) {
        db_req_t *req;

        s_queue_req.pop(req);
        query(req);
        E_DELETE(req);
    }
    return NULL;
}

static void query(db_req_t *req)
{
    try {
        assert(req);

        // query
        int status = mysql_query(s_mysql, req->cmd.c_str());
        db_res_t *res = E_NEW db_res_t;

        res->sid = req->sid;
        res->status = status;
        res->data = NULL;

        if (res->status != 0) {
            LOG_ERROR("db", "`%s` failed: %s.",
                    req->cmd.c_str(), mysql_error(s_mysql));
        } else {
            do {
                MYSQL_RES *data = mysql_store_result(s_mysql);

                if (data) {
                    if (req->read) {
                        res->data = data;
                    } else {
                        mysql_free_result(data);
                    }
                }
            } while (!mysql_next_result(s_mysql));
        }
        s_queue_res.push(res);
    } catch(...) {
        LOG_ERROR("db", "`%s` failed: %s.",
                req->cmd.c_str(), mysql_error(s_mysql));
    }
}

static void retrieve(MYSQL_RES *res, pb_t *out)
{
    const Descriptor *des = out->GetDescriptor();
    const int field_num = mysql_num_fields(res);
    const MYSQL_ROW row = mysql_fetch_row(res);

    for (int c = 0; c < field_num; ++c) {
        const MYSQL_FIELD *ifd = mysql_fetch_field_direct(res, c);
        const FieldDescriptor *ofd = des->FindFieldByName(ifd->name);

        assert(ofd);
        if (row[c] == NULL || (strlen(row[c]) == 0)) {
            pb_set_field(out, ofd, "");
        } else {
            pb_set_field(out, ofd, row[c]);
        }
    }
}

static void retrieve(MYSQL_RES *res, pb_t *out, const std::string &field)
{
    const Reflection *ref = out->GetReflection();
    const Descriptor *des = out->GetDescriptor();
    const FieldDescriptor *ctn = des->FindFieldByName(field);
    const int row_num = mysql_num_rows(res);
    const int field_num = mysql_num_fields(res);

    assert(ctn);
    for (int r = 0; r < row_num; ++r) {
        pb_t *item = ref->AddMessage(out, ctn);
        const MYSQL_ROW row = mysql_fetch_row(res);

        des = item->GetDescriptor();
        for (int c = 0; c < field_num; ++c) {
            const MYSQL_FIELD *ifd = mysql_fetch_field_direct(res, c);
            const FieldDescriptor *ofd =
                des->FindFieldByName(ifd->name);

            assert(ofd);
            if (row[c] == NULL || (strlen(row[c]) == 0)) {
                pb_set_field(item, ofd, "");
            } else {
                pb_set_field(item, ofd, row[c]);
            }
        }
    }
}

int db_init(void)
{
    MODULE_IMPORT_SWITCH;
    return ELF_RC_DB_OK;
}

int db_fini(void)
{
    MODULE_IMPORT_SWITCH;
    thread_fini(s_tid_req);
    return ELF_RC_DB_OK;
}

int db_connect(const std::string &host, const std::string &user,
        const std::string &passwd, const std::string &db, unsigned int port)
{
    try {
        char value = 1;

        if (s_mysql && 0 == mysql_ping(s_mysql)) {
            return ELF_RC_DB_OK;
        }
        s_mysql = mysql_init(NULL);
        mysql_options(s_mysql, MYSQL_OPT_RECONNECT, (char *)&value);
        mysql_options(s_mysql, MYSQL_SET_CHARSET_NAME, "utf8");
        s_mysql = mysql_real_connect(s_mysql, host.c_str(), user.c_str(),
                passwd.c_str(), db.c_str(), port,
                NULL, CLIENT_MULTI_STATEMENTS);
        if (!s_mysql) {
            LOG_ERROR("db", "Connect DB failed: %s.",
                    mysql_error(s_mysql));
            return ELF_RC_DB_INIT_FAILED;
        }
    } catch(...) {
        LOG_ERROR("db", "Connect DB failed: %s.",
                mysql_error(s_mysql));
        return ELF_RC_DB_INIT_FAILED;
    }
    s_tid_req = thread_init(handle, NULL);
    return ELF_RC_DB_OK;
}

int db_proc(void)
{
    if (s_mysql == NULL) return -1;

    std::deque<db_res_t *> list;
    std::deque<db_res_t *>::iterator itr;

    s_queue_res.swap(list);
    for (itr = list.begin(); itr != list.end(); ++itr) {
        db_res_t *res = *itr;
        session_list::iterator itr_s = s_sessions.find(res->sid);

        assert(itr_s != s_sessions.end());

        session_t *s = itr_s->second;

        assert(s);

        // object has not been destroyed
        if (res->status == 0 && res->data != NULL
                && s->out != NULL && s->proc != NULL) {
            db_res(res->data, s->out, s->field);
            s->proc(s->oid, s->out);
        }
        if (res->data != NULL) {
            mysql_free_result(res->data);
        }
        E_DELETE(res);
    }
    return 0;
}

void db_req(const char *cmd, oid_t oid, pb_t *out,
        const std::string &field, db_callback proc)
{
    db_req_t *req = E_NEW db_req_t;
    session_t *s = E_NEW session_t;

    s->id = oid_gen();
    s->oid = oid;
    s->out = out;
    s->field = field;
    s->proc = proc;
    s_sessions[s->id] = s;

    req->cmd = cmd;
    req->sid = s->id;
    req->read = (out != NULL);
    s_queue_req.push(req);
}

void db_res(MYSQL_RES *res, pb_t *out, const std::string &field)
{
    assert(res && out);

    if (field == "") {
        retrieve(res, out);
    } else {
        retrieve(res, out, field);
    }
}

db_rc db_query(const char *cmd)
{
    assert(s_mysql);
    try {
        // query
        int status = mysql_query(s_mysql, cmd);

        if (status != 0) {
            LOG_ERROR("db", "`%s` failed: %s.",
                    cmd, mysql_error(s_mysql));
            return ELF_RC_DB_EXECUTE_FAILED;
        }

        do {
            MYSQL_RES *res = mysql_store_result(s_mysql);

            if (res) {
                mysql_free_result(res);
            }
        } while (!mysql_next_result(s_mysql));
        return ELF_RC_DB_OK;
    } catch(...) {
        LOG_ERROR("db", "`%s` failed: %s.",
                cmd, mysql_error(s_mysql));
        return ELF_RC_DB_EXECUTE_FAILED;
    }
    return ELF_RC_DB_OK;
}

db_rc db_query(const char *cmd, pb_t *out)
{
    assert(s_mysql && out);
    LOG_TRACE("db", "Query DB: %s.", cmd);
    try {
        // query
        int status = mysql_query(s_mysql, cmd);

        if (status != 0) {
            LOG_ERROR("db", "`%s` failed: %s.",
                    cmd, mysql_error(s_mysql));
            return ELF_RC_DB_EXECUTE_FAILED;
        }

        MYSQL_RES *res = mysql_store_result(s_mysql);

        if (res) {
            const int row_num = mysql_num_rows(res);
            const Descriptor *des = out->GetDescriptor();
            const int field_num = mysql_num_fields(res);
            const MYSQL_ROW row = mysql_fetch_row(res);

            for (int c = 0; row_num > 0 && c < field_num; ++c) {
                const MYSQL_FIELD *ifd =
                    mysql_fetch_field_direct(res, c);
                const FieldDescriptor *ofd =
                    des->FindFieldByName(ifd->name);

                assert(ofd);
                if (row[c] == NULL || (strlen(row[c]) == 0)) {
                    pb_set_field(out, ofd, "");
                } else {
                    pb_set_field(out, ofd, row[c]);
                }
            }
            mysql_free_result(res);
            return ELF_RC_DB_OK;
        } else if (mysql_field_count(s_mysql) == 0) {
            return ELF_RC_DB_OK;
        } else {
            LOG_ERROR("db", "`%s` failed: %s.",
                    cmd, mysql_error(s_mysql));
            return ELF_RC_DB_EXECUTE_FAILED;
        }
    } catch(...) {
        LOG_ERROR("db", "`%s` failed: %s.",
                cmd, mysql_error(s_mysql));
        return ELF_RC_DB_EXECUTE_FAILED;
    }
    return ELF_RC_DB_OK;
}

db_rc db_query(const char *cmd, pb_t *out, const std::string &field)
{
    assert(s_mysql && out);
    LOG_TRACE("db", "Query DB: %s.", cmd);
    try {
        // query
        int status = mysql_query(s_mysql, cmd);

        if (status != 0) {
            LOG_ERROR("db", "`%s` failed: %s.",
                    cmd, mysql_error(s_mysql));
            return ELF_RC_DB_EXECUTE_FAILED;
        }

        MYSQL_RES *res = mysql_store_result(s_mysql);

        if (res) {
            const int row_num = mysql_num_rows(res);
            const Reflection *ref = out->GetReflection();
            const Descriptor *des = out->GetDescriptor();
            const FieldDescriptor *ctn = des->FindFieldByName(field);
            const int field_num = mysql_num_fields(res);

            assert(ctn);
            for (int r = 0; r < row_num; ++r) {
                pb_t *item = ref->AddMessage(out, ctn);
                const MYSQL_ROW row = mysql_fetch_row(res);

                des = item->GetDescriptor();
                for (int c = 0; c < field_num; ++c) {
                    const MYSQL_FIELD *ifd =
                        mysql_fetch_field_direct(res, c);
                    const FieldDescriptor *ofd =
                        des->FindFieldByName(ifd->name);

                    assert(ofd);
                    if (row[c] == NULL || (strlen(row[c]) == 0)) {
                        pb_set_field(item, ofd, "");
                    } else {
                        pb_set_field(item, ofd, row[c]);
                    }
                }
            }
            mysql_free_result(res);
            return ELF_RC_DB_OK;
        } else if (mysql_field_count(s_mysql) == 0) {
            return ELF_RC_DB_OK;
        } else {
            LOG_ERROR("db", "`%s` failed: %s.",
                    cmd, mysql_error(s_mysql));
            return ELF_RC_DB_EXECUTE_FAILED;
        }
    } catch(...) {
        LOG_ERROR("db", "`%s` failed: %s.",
                cmd, mysql_error(s_mysql));
        return ELF_RC_DB_EXECUTE_FAILED;
    }
    return ELF_RC_DB_OK;
}
} // namespace elf

<commit_msg>[MOD] db.<commit_after>/*
 * Copyright (C) 2012-2014 Yule Fox. All rights reserved.
 * http://www.yulefox.com/
 */

#include <elf/db.h>
#include <elf/log.h>
#include <elf/memory.h>
#include <elf/pc.h>
#include <elf/thread.h>
#include <elf/time.h>
#include <deque>
#include <map>
#include <string>

using namespace google::protobuf;

namespace elf {
struct db_req_t {
    bool read; // need restore query result
    std::string cmd; // sql command
    oid_t sid; // session id
    elf::time64_t stamp; // request time stamp
};

struct db_res_t {
    int status; // status
    MYSQL_RES *data; // query result
    oid_t sid; // session id
};

struct session_t {
    oid_t id; // session id
    oid_t oid; // associated object id
    pb_t *out; // store query data
    std::string field; // pb field
    db_callback proc; // callback function
};

typedef std::map<oid_t, session_t *> session_list;

static session_list s_sessions;
static MYSQL *s_mysql = NULL;
static thread_t s_tid_req = 0;
static xqueue<db_req_t *> s_queue_req;
static xqueue<db_res_t *> s_queue_res;

static void *handle(void *args);
static void query(db_req_t *req);
static void retrieve(MYSQL_RES *res, pb_t *out);
static void retrieve(MYSQL_RES *res, pb_t *out, const std::string &field);

static void *handle(void *args)
{
    while (true) {
        db_req_t *req;

        s_queue_req.pop(req);
        query(req);
        E_DELETE(req);
    }
    return NULL;
}

static void query(db_req_t *req)
{
    try {
        assert(req);

        // query
        int status = mysql_query(s_mysql, req->cmd.c_str());
        db_res_t *res = E_NEW db_res_t;

        res->sid = req->sid;
        res->status = status;
        res->data = NULL;

        if (res->status != 0) {
            LOG_ERROR("db", "`%s` failed: %s.",
                    req->cmd.c_str(), mysql_error(s_mysql));
        } else {
            do {
                MYSQL_RES *data = mysql_store_result(s_mysql);

                if (data) {
                    if (req->read) {
                        res->data = data;
                    } else {
                        mysql_free_result(data);
                    }
                }
            } while (!mysql_next_result(s_mysql));

            elf::time64_t ct = time_ms();
            elf::time64_t delta = time_diff(ct, req->stamp);
            static elf::time64_t leap = 5000; // 5s
            static elf::time64_t times = 1;

            if (delta > leap * times) {
                LOG_WARN("db", "DB Server is busying for %d.%03ds.",
                        delta / 1000,
                        delta % 1000,
                        req->cmd.c_str());
                ++times;
            } else if (delta < leap) {
                times = 1;
            }
        }
        s_queue_res.push(res);
    } catch(...) {
        LOG_ERROR("db", "`%s` failed: %s.",
                req->cmd.c_str(), mysql_error(s_mysql));
    }
}

static void retrieve(MYSQL_RES *res, pb_t *out)
{
    const Descriptor *des = out->GetDescriptor();
    const int field_num = mysql_num_fields(res);
    const MYSQL_ROW row = mysql_fetch_row(res);

    for (int c = 0; c < field_num; ++c) {
        const MYSQL_FIELD *ifd = mysql_fetch_field_direct(res, c);
        const FieldDescriptor *ofd = des->FindFieldByName(ifd->name);

        assert(ofd);
        if (row[c] == NULL || (strlen(row[c]) == 0)) {
            pb_set_field(out, ofd, "");
        } else {
            pb_set_field(out, ofd, row[c]);
        }
    }
}

static void retrieve(MYSQL_RES *res, pb_t *out, const std::string &field)
{
    const Reflection *ref = out->GetReflection();
    const Descriptor *des = out->GetDescriptor();
    const FieldDescriptor *ctn = des->FindFieldByName(field);
    const int row_num = mysql_num_rows(res);
    const int field_num = mysql_num_fields(res);

    assert(ctn);
    for (int r = 0; r < row_num; ++r) {
        pb_t *item = ref->AddMessage(out, ctn);
        const MYSQL_ROW row = mysql_fetch_row(res);

        des = item->GetDescriptor();
        for (int c = 0; c < field_num; ++c) {
            const MYSQL_FIELD *ifd = mysql_fetch_field_direct(res, c);
            const FieldDescriptor *ofd =
                des->FindFieldByName(ifd->name);

            assert(ofd);
            if (row[c] == NULL || (strlen(row[c]) == 0)) {
                pb_set_field(item, ofd, "");
            } else {
                pb_set_field(item, ofd, row[c]);
            }
        }
    }
}

int db_init(void)
{
    MODULE_IMPORT_SWITCH;
    return ELF_RC_DB_OK;
}

int db_fini(void)
{
    MODULE_IMPORT_SWITCH;
    thread_fini(s_tid_req);
    return ELF_RC_DB_OK;
}

int db_connect(const std::string &host, const std::string &user,
        const std::string &passwd, const std::string &db, unsigned int port)
{
    try {
        char value = 1;

        if (s_mysql && 0 == mysql_ping(s_mysql)) {
            return ELF_RC_DB_OK;
        }
        s_mysql = mysql_init(NULL);
        mysql_options(s_mysql, MYSQL_OPT_RECONNECT, (char *)&value);
        mysql_options(s_mysql, MYSQL_SET_CHARSET_NAME, "utf8");
        s_mysql = mysql_real_connect(s_mysql, host.c_str(), user.c_str(),
                passwd.c_str(), db.c_str(), port,
                NULL, CLIENT_MULTI_STATEMENTS);
        if (!s_mysql) {
            LOG_ERROR("db", "Connect DB failed: %s.",
                    mysql_error(s_mysql));
            return ELF_RC_DB_INIT_FAILED;
        }
    } catch(...) {
        LOG_ERROR("db", "Connect DB failed: %s.",
                mysql_error(s_mysql));
        return ELF_RC_DB_INIT_FAILED;
    }
    s_tid_req = thread_init(handle, NULL);
    return ELF_RC_DB_OK;
}

int db_proc(void)
{
    if (s_mysql == NULL) return -1;

    std::deque<db_res_t *> list;
    std::deque<db_res_t *>::iterator itr;

    s_queue_res.swap(list);
    for (itr = list.begin(); itr != list.end(); ++itr) {
        db_res_t *res = *itr;
        session_list::iterator itr_s = s_sessions.find(res->sid);

        assert(itr_s != s_sessions.end());

        session_t *s = itr_s->second;

        assert(s);

        // object has not been destroyed
        if (res->status == 0 && res->data != NULL
                && s->out != NULL && s->proc != NULL) {
            db_res(res->data, s->out, s->field);
            s->proc(s->oid, s->out);
        }
        if (res->data != NULL) {
            mysql_free_result(res->data);
        }
        E_DELETE(res);
    }
    return 0;
}

void db_req(const char *cmd, oid_t oid, pb_t *out,
        const std::string &field, db_callback proc)
{
    db_req_t *req = E_NEW db_req_t;
    session_t *s = E_NEW session_t;

    s->id = oid_gen();
    s->oid = oid;
    s->out = out;
    s->field = field;
    s->proc = proc;
    s_sessions[s->id] = s;

    req->cmd = cmd;
    req->sid = s->id;
    req->stamp = time_ms();
    req->read = (out != NULL);
    s_queue_req.push(req);
}

void db_res(MYSQL_RES *res, pb_t *out, const std::string &field)
{
    assert(res && out);

    if (field == "") {
        retrieve(res, out);
    } else {
        retrieve(res, out, field);
    }
}

db_rc db_query(const char *cmd)
{
    assert(s_mysql);
    try {
        // query
        int status = mysql_query(s_mysql, cmd);

        if (status != 0) {
            LOG_ERROR("db", "`%s` failed: %s.",
                    cmd, mysql_error(s_mysql));
            return ELF_RC_DB_EXECUTE_FAILED;
        }

        do {
            MYSQL_RES *res = mysql_store_result(s_mysql);

            if (res) {
                mysql_free_result(res);
            }
        } while (!mysql_next_result(s_mysql));
        return ELF_RC_DB_OK;
    } catch(...) {
        LOG_ERROR("db", "`%s` failed: %s.",
                cmd, mysql_error(s_mysql));
        return ELF_RC_DB_EXECUTE_FAILED;
    }
    return ELF_RC_DB_OK;
}

db_rc db_query(const char *cmd, pb_t *out)
{
    assert(s_mysql && out);
    LOG_TRACE("db", "Query DB: %s.", cmd);
    try {
        // query
        int status = mysql_query(s_mysql, cmd);

        if (status != 0) {
            LOG_ERROR("db", "`%s` failed: %s.",
                    cmd, mysql_error(s_mysql));
            return ELF_RC_DB_EXECUTE_FAILED;
        }

        MYSQL_RES *res = mysql_store_result(s_mysql);

        if (res) {
            const int row_num = mysql_num_rows(res);
            const Descriptor *des = out->GetDescriptor();
            const int field_num = mysql_num_fields(res);
            const MYSQL_ROW row = mysql_fetch_row(res);

            for (int c = 0; row_num > 0 && c < field_num; ++c) {
                const MYSQL_FIELD *ifd =
                    mysql_fetch_field_direct(res, c);
                const FieldDescriptor *ofd =
                    des->FindFieldByName(ifd->name);

                assert(ofd);
                if (row[c] == NULL || (strlen(row[c]) == 0)) {
                    pb_set_field(out, ofd, "");
                } else {
                    pb_set_field(out, ofd, row[c]);
                }
            }
            mysql_free_result(res);
            return ELF_RC_DB_OK;
        } else if (mysql_field_count(s_mysql) == 0) {
            return ELF_RC_DB_OK;
        } else {
            LOG_ERROR("db", "`%s` failed: %s.",
                    cmd, mysql_error(s_mysql));
            return ELF_RC_DB_EXECUTE_FAILED;
        }
    } catch(...) {
        LOG_ERROR("db", "`%s` failed: %s.",
                cmd, mysql_error(s_mysql));
        return ELF_RC_DB_EXECUTE_FAILED;
    }
    return ELF_RC_DB_OK;
}

db_rc db_query(const char *cmd, pb_t *out, const std::string &field)
{
    assert(s_mysql && out);
    LOG_TRACE("db", "Query DB: %s.", cmd);
    try {
        // query
        int status = mysql_query(s_mysql, cmd);

        if (status != 0) {
            LOG_ERROR("db", "`%s` failed: %s.",
                    cmd, mysql_error(s_mysql));
            return ELF_RC_DB_EXECUTE_FAILED;
        }

        MYSQL_RES *res = mysql_store_result(s_mysql);

        if (res) {
            const int row_num = mysql_num_rows(res);
            const Reflection *ref = out->GetReflection();
            const Descriptor *des = out->GetDescriptor();
            const FieldDescriptor *ctn = des->FindFieldByName(field);
            const int field_num = mysql_num_fields(res);

            assert(ctn);
            for (int r = 0; r < row_num; ++r) {
                pb_t *item = ref->AddMessage(out, ctn);
                const MYSQL_ROW row = mysql_fetch_row(res);

                des = item->GetDescriptor();
                for (int c = 0; c < field_num; ++c) {
                    const MYSQL_FIELD *ifd =
                        mysql_fetch_field_direct(res, c);
                    const FieldDescriptor *ofd =
                        des->FindFieldByName(ifd->name);

                    assert(ofd);
                    if (row[c] == NULL || (strlen(row[c]) == 0)) {
                        pb_set_field(item, ofd, "");
                    } else {
                        pb_set_field(item, ofd, row[c]);
                    }
                }
            }
            mysql_free_result(res);
            return ELF_RC_DB_OK;
        } else if (mysql_field_count(s_mysql) == 0) {
            return ELF_RC_DB_OK;
        } else {
            LOG_ERROR("db", "`%s` failed: %s.",
                    cmd, mysql_error(s_mysql));
            return ELF_RC_DB_EXECUTE_FAILED;
        }
    } catch(...) {
        LOG_ERROR("db", "`%s` failed: %s.",
                cmd, mysql_error(s_mysql));
        return ELF_RC_DB_EXECUTE_FAILED;
    }
    return ELF_RC_DB_OK;
}
} // namespace elf

<|endoftext|>


<commit_before>//
// Copyright (C) 2011-13 Mark Wiebe, DyND Developers
// BSD 2-Clause License, see LICENSE.txt
//

#include <Python.h>
#include <datetime.h>

#include "array_as_py.hpp"
#include "array_functions.hpp"
#include "dtype_functions.hpp"
#include "utility_functions.hpp"

#include <dynd/dtypes/strided_dim_dtype.hpp>
#include <dynd/dtypes/base_struct_dtype.hpp>
#include <dynd/dtypes/date_dtype.hpp>
#include <dynd/dtypes/datetime_dtype.hpp>
#include <dynd/dtypes/bytes_dtype.hpp>
#include <dynd/dtypes/dtype_dtype.hpp>

using namespace std;
using namespace dynd;
using namespace pydynd;

// Initialize the pydatetime API
namespace {
struct init_pydatetime {
    init_pydatetime() {
        PyDateTime_IMPORT;
    }
};
init_pydatetime pdt;
} // anonymous namespace

static PyObject* element_as_pyobject(const ndt::type& d, const char *data, const char *metadata)
{
    switch (d.get_type_id()) {
        case bool_type_id:
            if (*(const dynd_bool *)data) {
                Py_INCREF(Py_True);
                return Py_True;
            } else {
                Py_INCREF(Py_False);
                return Py_False;
            }
        case int8_type_id:
#if PY_VERSION_HEX >= 0x03000000
            return PyLong_FromLong(*(const int8_t *)data);
#else
            return PyInt_FromLong(*(const int8_t *)data);
#endif
        case int16_type_id:
#if PY_VERSION_HEX >= 0x03000000
            return PyLong_FromLong(*(const int16_t *)data);
#else
            return PyInt_FromLong(*(const int16_t *)data);
#endif
        case int32_type_id:
#if PY_VERSION_HEX >= 0x03000000
            return PyLong_FromLong(*(const int32_t *)data);
#else
            return PyInt_FromLong(*(const int32_t *)data);
#endif
        case int64_type_id:
            return PyLong_FromLongLong(*(const int64_t *)data);
        case uint8_type_id:
#if PY_VERSION_HEX >= 0x03000000
            return PyLong_FromLong(*(const uint8_t *)data);
#else
            return PyInt_FromLong(*(const uint8_t *)data);
#endif
        case uint16_type_id:
#if PY_VERSION_HEX >= 0x03000000
            return PyLong_FromLong(*(const uint16_t *)data);
#else
            return PyInt_FromLong(*(const uint16_t *)data);
#endif
        case uint32_type_id:
            return PyLong_FromUnsignedLong(*(const uint32_t *)data);
        case uint64_type_id:
            return PyLong_FromUnsignedLongLong(*(const uint64_t *)data);
        case float32_type_id:
            return PyFloat_FromDouble(*(const float *)data);
        case float64_type_id:
            return PyFloat_FromDouble(*(const double *)data);
        case complex_float32_type_id:
            return PyComplex_FromDoubles(*(const float *)data, *((const float *)data + 1));
        case complex_float64_type_id:
            return PyComplex_FromDoubles(*(const double *)data, *((const double *)data + 1));
        case fixedbytes_type_id:
            return PyBytes_FromStringAndSize(data, d.get_data_size());
        case bytes_type_id: {
            const bytes_dtype_data *d = reinterpret_cast<const bytes_dtype_data *>(data);
            return PyBytes_FromStringAndSize(d->begin, d->end - d->begin);
        }
        case fixedstring_type_id:
        case string_type_id:
        case json_type_id: {
            const char *begin = NULL, *end = NULL;
            const base_string_dtype *esd = static_cast<const base_string_dtype *>(d.extended());
            esd->get_string_range(&begin, &end, metadata, data);
            switch (esd->get_encoding()) {
                case string_encoding_ascii:
                    return PyUnicode_DecodeASCII(begin, end - begin, NULL);
                case string_encoding_utf_8:
                    return PyUnicode_DecodeUTF8(begin, end - begin, NULL);
                case string_encoding_ucs_2:
                case string_encoding_utf_16:
                    return PyUnicode_DecodeUTF16(begin, end - begin, NULL, NULL);
                case string_encoding_utf_32:
                    return PyUnicode_DecodeUTF32(begin, end - begin, NULL, NULL);
                default:
                    throw runtime_error("Unrecognized dynd array string encoding");
            }
        }
        case date_type_id: {
            const date_dtype *dd = static_cast<const date_dtype *>(d.extended());
            int32_t year, month, day;
            dd->get_ymd(metadata, data, year, month, day);
            return PyDate_FromDate(year, month, day);
        }
        case datetime_type_id: {
            const datetime_dtype *dd = static_cast<const datetime_dtype *>(d.extended());
            int32_t year, month, day, hour, minute, second, nsecond;
            dd->get_cal(metadata, data, year, month, day, hour, minute, second, nsecond);
            int32_t usecond = nsecond / 1000;
            if (usecond * 1000 != nsecond) {
                stringstream ss;
                ss << "cannot convert dynd value of type " << d;
                ss << " with value ";
                dd->print_data(ss, metadata, data);
                ss << " to python without precision loss";
                throw runtime_error(ss.str());
            }
            return PyDateTime_FromDateAndTime(year, month, day, hour, minute, second, usecond);
        }
        case dtype_type_id: {
            ndt::type dt(reinterpret_cast<const dtype_dtype_data *>(data)->dt, true);
            return wrap_dtype(DYND_MOVE(dt));
        }
        default: {
            stringstream ss;
            ss << "Cannot convert dynd array with dtype " << d << " into python object";
            throw runtime_error(ss.str());
        }
    }
}

namespace {
    struct array_as_py_data {
        pyobject_ownref result;
        int index;
    };
} // anonymous namespace

static void nested_array_as_py(const ndt::type& d, char *data, const char *metadata, void *result);

static void nested_struct_as_py(const ndt::type& d, char *data, const char *metadata, void *result)
{
    array_as_py_data *r = reinterpret_cast<array_as_py_data *>(result);

    const base_struct_dtype *bsd = static_cast<const base_struct_dtype *>(d.extended());
    size_t field_count = bsd->get_field_count();
    const string *field_names = bsd->get_field_names();
    const ndt::type *field_types = bsd->get_field_types();
    const size_t *field_metadata_offsets = bsd->get_metadata_offsets();
    const size_t *field_data_offsets = bsd->get_data_offsets(metadata);

    r->result.reset(PyDict_New());
    for (size_t i = 0; i != field_count; ++i) {
        const string& fname = field_names[i];
        pyobject_ownref key(PyUnicode_DecodeUTF8(fname.data(), fname.size(), NULL));
        array_as_py_data temp_el;
        nested_array_as_py(field_types[i], data + field_data_offsets[i],
                        metadata + field_metadata_offsets[i], &temp_el);
        if (PyDict_SetItem(r->result.get(), key.get(), temp_el.result.get()) < 0) {
            throw runtime_error("propagating dict setitem error");
        }
    }
}

static void nested_array_as_py(const ndt::type& d, char *data, const char *metadata, void *result)
{
    array_as_py_data *r = reinterpret_cast<array_as_py_data *>(result);

    array_as_py_data el;
    if (d.is_scalar()) {
        el.result.reset(element_as_pyobject(d, data, metadata));
    } else if (d.get_kind() == struct_kind) {
        nested_struct_as_py(d, data, metadata, &el);
    } else {
        intptr_t size = d.get_dim_size(metadata, data);
        el.result.reset(PyList_New(size));
        el.index = 0;

        d.extended()->foreach_leading(data, metadata, &nested_array_as_py, &el);
    }

    if (r->result) {
        PyList_SET_ITEM(r->result.get(), r->index++, el.result.release());
    } else {
        r->result.reset(el.result.release());
    }
}

PyObject* pydynd::array_as_py(const dynd::nd::array& n)
{
    // Evaluate the nd::array
    nd::array nvals = n.eval();
    array_as_py_data result;

    nested_array_as_py(nvals.get_dtype(), nvals.get_ndo()->m_data_pointer, nvals.get_ndo_meta(), &result);
    return result.result.release();
}

<commit_msg>Linux build fixes<commit_after>//
// Copyright (C) 2011-13 Mark Wiebe, DyND Developers
// BSD 2-Clause License, see LICENSE.txt
//

#include <Python.h>
#include <datetime.h>

#include "array_as_py.hpp"
#include "array_functions.hpp"
#include "dtype_functions.hpp"
#include "utility_functions.hpp"

#include <dynd/dtypes/strided_dim_dtype.hpp>
#include <dynd/dtypes/base_struct_dtype.hpp>
#include <dynd/dtypes/date_dtype.hpp>
#include <dynd/dtypes/datetime_dtype.hpp>
#include <dynd/dtypes/bytes_dtype.hpp>
#include <dynd/dtypes/dtype_dtype.hpp>

using namespace std;
using namespace dynd;
using namespace pydynd;

// Initialize the pydatetime API
namespace {
struct init_pydatetime {
    init_pydatetime() {
        PyDateTime_IMPORT;
    }
};
init_pydatetime pdt;
} // anonymous namespace

static PyObject* element_as_pyobject(const ndt::type& d, const char *data, const char *metadata)
{
    switch (d.get_type_id()) {
        case bool_type_id:
            if (*(const dynd_bool *)data) {
                Py_INCREF(Py_True);
                return Py_True;
            } else {
                Py_INCREF(Py_False);
                return Py_False;
            }
        case int8_type_id:
#if PY_VERSION_HEX >= 0x03000000
            return PyLong_FromLong(*(const int8_t *)data);
#else
            return PyInt_FromLong(*(const int8_t *)data);
#endif
        case int16_type_id:
#if PY_VERSION_HEX >= 0x03000000
            return PyLong_FromLong(*(const int16_t *)data);
#else
            return PyInt_FromLong(*(const int16_t *)data);
#endif
        case int32_type_id:
#if PY_VERSION_HEX >= 0x03000000
            return PyLong_FromLong(*(const int32_t *)data);
#else
            return PyInt_FromLong(*(const int32_t *)data);
#endif
        case int64_type_id:
            return PyLong_FromLongLong(*(const int64_t *)data);
        case uint8_type_id:
#if PY_VERSION_HEX >= 0x03000000
            return PyLong_FromLong(*(const uint8_t *)data);
#else
            return PyInt_FromLong(*(const uint8_t *)data);
#endif
        case uint16_type_id:
#if PY_VERSION_HEX >= 0x03000000
            return PyLong_FromLong(*(const uint16_t *)data);
#else
            return PyInt_FromLong(*(const uint16_t *)data);
#endif
        case uint32_type_id:
            return PyLong_FromUnsignedLong(*(const uint32_t *)data);
        case uint64_type_id:
            return PyLong_FromUnsignedLongLong(*(const uint64_t *)data);
        case float32_type_id:
            return PyFloat_FromDouble(*(const float *)data);
        case float64_type_id:
            return PyFloat_FromDouble(*(const double *)data);
        case complex_float32_type_id:
            return PyComplex_FromDoubles(*(const float *)data, *((const float *)data + 1));
        case complex_float64_type_id:
            return PyComplex_FromDoubles(*(const double *)data, *((const double *)data + 1));
        case fixedbytes_type_id:
            return PyBytes_FromStringAndSize(data, d.get_data_size());
        case bytes_type_id: {
            const bytes_dtype_data *d = reinterpret_cast<const bytes_dtype_data *>(data);
            return PyBytes_FromStringAndSize(d->begin, d->end - d->begin);
        }
        case fixedstring_type_id:
        case string_type_id:
        case json_type_id: {
            const char *begin = NULL, *end = NULL;
            const base_string_dtype *esd = static_cast<const base_string_dtype *>(d.extended());
            esd->get_string_range(&begin, &end, metadata, data);
            switch (esd->get_encoding()) {
                case string_encoding_ascii:
                    return PyUnicode_DecodeASCII(begin, end - begin, NULL);
                case string_encoding_utf_8:
                    return PyUnicode_DecodeUTF8(begin, end - begin, NULL);
                case string_encoding_ucs_2:
                case string_encoding_utf_16:
                    return PyUnicode_DecodeUTF16(begin, end - begin, NULL, NULL);
                case string_encoding_utf_32:
                    return PyUnicode_DecodeUTF32(begin, end - begin, NULL, NULL);
                default:
                    throw runtime_error("Unrecognized dynd array string encoding");
            }
        }
        case date_type_id: {
            const date_dtype *dd = static_cast<const date_dtype *>(d.extended());
            int32_t year, month, day;
            dd->get_ymd(metadata, data, year, month, day);
            return PyDate_FromDate(year, month, day);
        }
        case datetime_type_id: {
            const datetime_dtype *dd = static_cast<const datetime_dtype *>(d.extended());
            int32_t year, month, day, hour, minute, second, nsecond;
            dd->get_cal(metadata, data, year, month, day, hour, minute, second, nsecond);
            int32_t usecond = nsecond / 1000;
            if (usecond * 1000 != nsecond) {
                stringstream ss;
                ss << "cannot convert dynd value of type " << d;
                ss << " with value ";
                dd->print_data(ss, metadata, data);
                ss << " to python without precision loss";
                throw runtime_error(ss.str());
            }
            return PyDateTime_FromDateAndTime(year, month, day, hour, minute, second, usecond);
        }
        case dtype_type_id: {
            ndt::type dt(reinterpret_cast<const dtype_dtype_data *>(data)->dt, true);
            return wrap_ndt_type(DYND_MOVE(dt));
        }
        default: {
            stringstream ss;
            ss << "Cannot convert dynd array with dtype " << d << " into python object";
            throw runtime_error(ss.str());
        }
    }
}

namespace {
    struct array_as_py_data {
        pyobject_ownref result;
        int index;
    };
} // anonymous namespace

static void nested_array_as_py(const ndt::type& d, char *data, const char *metadata, void *result);

static void nested_struct_as_py(const ndt::type& d, char *data, const char *metadata, void *result)
{
    array_as_py_data *r = reinterpret_cast<array_as_py_data *>(result);

    const base_struct_dtype *bsd = static_cast<const base_struct_dtype *>(d.extended());
    size_t field_count = bsd->get_field_count();
    const string *field_names = bsd->get_field_names();
    const ndt::type *field_types = bsd->get_field_types();
    const size_t *field_metadata_offsets = bsd->get_metadata_offsets();
    const size_t *field_data_offsets = bsd->get_data_offsets(metadata);

    r->result.reset(PyDict_New());
    for (size_t i = 0; i != field_count; ++i) {
        const string& fname = field_names[i];
        pyobject_ownref key(PyUnicode_DecodeUTF8(fname.data(), fname.size(), NULL));
        array_as_py_data temp_el;
        nested_array_as_py(field_types[i], data + field_data_offsets[i],
                        metadata + field_metadata_offsets[i], &temp_el);
        if (PyDict_SetItem(r->result.get(), key.get(), temp_el.result.get()) < 0) {
            throw runtime_error("propagating dict setitem error");
        }
    }
}

static void nested_array_as_py(const ndt::type& d, char *data, const char *metadata, void *result)
{
    array_as_py_data *r = reinterpret_cast<array_as_py_data *>(result);

    array_as_py_data el;
    if (d.is_scalar()) {
        el.result.reset(element_as_pyobject(d, data, metadata));
    } else if (d.get_kind() == struct_kind) {
        nested_struct_as_py(d, data, metadata, &el);
    } else {
        intptr_t size = d.get_dim_size(metadata, data);
        el.result.reset(PyList_New(size));
        el.index = 0;

        d.extended()->foreach_leading(data, metadata, &nested_array_as_py, &el);
    }

    if (r->result) {
        PyList_SET_ITEM(r->result.get(), r->index++, el.result.release());
    } else {
        r->result.reset(el.result.release());
    }
}

PyObject* pydynd::array_as_py(const dynd::nd::array& n)
{
    // Evaluate the nd::array
    nd::array nvals = n.eval();
    array_as_py_data result;

    nested_array_as_py(nvals.get_dtype(), nvals.get_ndo()->m_data_pointer, nvals.get_ndo_meta(), &result);
    return result.result.release();
}

<|endoftext|>