<commit_before>#include "schandler.h"

SCHandler::SCHandler(QObject *parent)
{
    raw_results = QJsonArray();
}

SCHandler::~SCHandler()
{

}

//category: artist, title, user,
int SCHandler::query(QString key, QString value){

    if(value == NULL)
        return -1;
    if(key == NULL)
        return -1;
    //check to prevent same query twice? nah don't be dumb

    // create custom temporary event loop on stack
    QEventLoop eventLoop;
    QUrl url(SC_TRACKS_URL);
    QUrlQuery query;
    query.addQueryItem("downloadable", "true");
    query.addQueryItem(key, value);

    query.addQueryItem("client_id", SC_CLIENT_ID);

    url.setQuery(query.query());
    qDebug() << url;

    // "quit()" the event-loop, when the network request "finished()"
    QNetworkAccessManager mgr;
    QObject::connect(&mgr, SIGNAL(finished(QNetworkReply*)), &eventLoop, SLOT(quit()));

    // the HTTP request
    QNetworkRequest req(url);
    QNetworkReply *reply = mgr.get(req);
    eventLoop.exec(); // blocks stack until "finished()" has been called

    if (reply->error() == QNetworkReply::NoError) {
        QJsonParseError err;
        QJsonDocument jsondoc = QJsonDocument(QJsonDocument::fromJson(QString(reply->readAll()).toUtf8(), &err)); //raw string to qtstring to bytecode to jsondoc fucking shit
        QJsonArray arr = jsondoc.array();
        qDebug() << QJsonDocument(arr).toJson();
        raw_results = arr; //take the pile of responses and make them an array so you can fucking do something with the
//        qDebug() << raw_results;

    return raw_results.size();

    }
    else {
        //failure
        qDebug() << "Failed query: " <<reply->errorString();
        delete reply;
        return -1;
    }
}

QJsonValue SCHandler::format(QJsonValue initial){
    QJsonObject jobj = initial.toObject();
    QString length;
    if (jobj["duration"].toInt() > 0){
        QString minutes;
        QString seconds;
        int duration = jobj["duration"].toInt()/1000; //ain't nobody got time for accuracy
        minutes = QString::number(duration/60);
        seconds = QString::number(duration%60);
        if(duration/60 < 10)
            minutes = QString("0"+minutes);
        if(duration%60 < 10)
            seconds = QString("0"+seconds);

        length = QString(minutes+":"+seconds);
    }

    QJsonObject media{
        {"hash", jobj["download_url"].toString()},
        {"order",""},
    };

    QJsonObject meta{
        {"title", jobj["title"].toString()},
        {"album",""}, //nope because soundcloud
        {"artist", jobj["user"].toObject()["username"].toString()},
        {"track_number", 0},
        {"length", length}, //get from fucking duration
        {"genre", jobj["genre"].toString()}
    };
    //add meta to media
    media["metadata"] = meta;

    return QJsonValue(media);
}

QJsonArray SCHandler::search(QString value, QString key){
    QJsonArray results = QJsonArray();
    QJsonObject jobj;
    QString result;
    int num_queried = query(key, value);
    for(int i=0; i<num_queried; i++){
        jobj = raw_results[i].toObject();
        result = jobj["download_url"].toString();
//        qDebug() << result.compare(QString(""));
        if(result.compare(QString("")) != 0)
            results.append(format(raw_results[i]));
    }

    emit onSearchComplete(&results);
    return results;
}

QJsonArray SCHandler::search(int count, QString value, QString key){
    QJsonArray results = QJsonArray();
    int num_queried = query(key, value);
    if(count > num_queried)
        count = num_queried;
    for(int i=0; i<40; i++){

        results.append(format(raw_results[i]));
    }
    emit onSearchComplete(&results);
    return results;
}

QByteArray SCHandler::request_song(QString download_url){
    // create custom temporary event loop on stack
    QNetworkRequest request;
    request.setRawHeader("User-Agent", USER_AGENT);
    QEventLoop eventLoop;
    QString req_url = download_url;
    QUrl url(req_url);
    QUrlQuery query;

    query.addQueryItem("client_id", SC_CLIENT_ID);

    url.setQuery(query.query());

    // "quit()" the event-loop, when the network request "finished()"
    QNetworkAccessManager mgr;
    QObject::connect(&mgr, SIGNAL(finished(QNetworkReply*)), &eventLoop, SLOT(quit()));

    // the HTTP request
    QNetworkRequest req(url);

    //req.setRawHeader();
    QNetworkReply *reply = mgr.get(req);
    eventLoop.exec(); // blocks stack until "finished()" has been called

    if (reply->error() == QNetworkReply::NoError) {
        //get temp download url as json

        QJsonDocument jsondoc = QJsonDocument(QJsonDocument::fromJson(QString(reply->readAll()).toUtf8()));
        QJsonObject jobj = jsondoc.object();
        QString download_url = jobj["location"].toString();

        //download
        if (reply->error() == QNetworkReply::NoError) {
            req_url = download_url;
            QUrl url(req_url);
            QNetworkRequest req(url);
            req.setRawHeader("User-Agent",USER_AGENT);
            QNetworkReply *reply = mgr.get(req);
            eventLoop.exec();

            return reply->readAll();
        }
        else{
            qDebug() << "Failure on download request" <<reply->errorString();
            delete reply;
            return NULL;
        }

    }
    else {
        //failure
        qDebug() << "Failure on initial request" <<reply->errorString();
        delete reply;
        return NULL;
    }
}

<commit_msg>Removed unneeded debug<commit_after>#include "schandler.h"

SCHandler::SCHandler(QObject *parent)
{
    raw_results = QJsonArray();
}

SCHandler::~SCHandler()
{

}

//category: artist, title, user,
int SCHandler::query(QString key, QString value){

    if(value == NULL)
        return -1;
    if(key == NULL)
        return -1;
    //check to prevent same query twice? nah don't be dumb

    // create custom temporary event loop on stack
    QEventLoop eventLoop;
    QUrl url(SC_TRACKS_URL);
    QUrlQuery query;
    query.addQueryItem("downloadable", "true");
    query.addQueryItem(key, value);

    query.addQueryItem("client_id", SC_CLIENT_ID);

    url.setQuery(query.query());
    qDebug() << url;

    // "quit()" the event-loop, when the network request "finished()"
    QNetworkAccessManager mgr;
    QObject::connect(&mgr, SIGNAL(finished(QNetworkReply*)), &eventLoop, SLOT(quit()));

    // the HTTP request
    QNetworkRequest req(url);
    QNetworkReply *reply = mgr.get(req);
    eventLoop.exec(); // blocks stack until "finished()" has been called

    if (reply->error() == QNetworkReply::NoError) {
        QJsonParseError err;
        QJsonDocument jsondoc = QJsonDocument(QJsonDocument::fromJson(QString(reply->readAll()).toUtf8(), &err)); //raw string to qtstring to bytecode to jsondoc fucking shit
        QJsonArray arr = jsondoc.array();
//        qDebug() << QJsonDocument(arr).toJson();
        raw_results = arr; //take the pile of responses and make them an array so you can fucking do something with the
//        qDebug() << raw_results;

    return raw_results.size();

    }
    else {
        //failure
        qDebug() << "Failed query: " <<reply->errorString();
        delete reply;
        return -1;
    }
}

QJsonValue SCHandler::format(QJsonValue initial){
    QJsonObject jobj = initial.toObject();
    QString length;
    if (jobj["duration"].toInt() > 0){
        QString minutes;
        QString seconds;
        int duration = jobj["duration"].toInt()/1000; //ain't nobody got time for accuracy
        minutes = QString::number(duration/60);
        seconds = QString::number(duration%60);
        if(duration/60 < 10)
            minutes = QString("0"+minutes);
        if(duration%60 < 10)
            seconds = QString("0"+seconds);

        length = QString(minutes+":"+seconds);
    }

    QJsonObject media{
        {"hash", jobj["download_url"].toString()},
        {"order",""},
    };

    QJsonObject meta{
        {"title", jobj["title"].toString()},
        {"album",""}, //nope because soundcloud
        {"artist", jobj["user"].toObject()["username"].toString()},
        {"track_number", 0},
        {"length", length}, //get from fucking duration
        {"genre", jobj["genre"].toString()}
    };
    //add meta to media
    media["metadata"] = meta;

    return QJsonValue(media);
}

QJsonArray SCHandler::search(QString value, QString key){
    QJsonArray results = QJsonArray();
    QJsonObject jobj;
    QString result;
    int num_queried = query(key, value);
    for(int i=0; i<num_queried; i++){
        jobj = raw_results[i].toObject();
        result = jobj["download_url"].toString();
//        qDebug() << result.compare(QString(""));
        if(result.compare(QString("")) != 0)
            results.append(format(raw_results[i]));
    }

    emit onSearchComplete(&results);
    return results;
}

QJsonArray SCHandler::search(int count, QString value, QString key){
    QJsonArray results = QJsonArray();
    int num_queried = query(key, value);
    if(count > num_queried)
        count = num_queried;
    for(int i=0; i<40; i++){

        results.append(format(raw_results[i]));
    }
    emit onSearchComplete(&results);
    return results;
}

QByteArray SCHandler::request_song(QString download_url){
    // create custom temporary event loop on stack
    QNetworkRequest request;
    request.setRawHeader("User-Agent", USER_AGENT);
    QEventLoop eventLoop;
    QString req_url = download_url;
    QUrl url(req_url);
    QUrlQuery query;

    query.addQueryItem("client_id", SC_CLIENT_ID);

    url.setQuery(query.query());

    // "quit()" the event-loop, when the network request "finished()"
    QNetworkAccessManager mgr;
    QObject::connect(&mgr, SIGNAL(finished(QNetworkReply*)), &eventLoop, SLOT(quit()));

    // the HTTP request
    QNetworkRequest req(url);

    //req.setRawHeader();
    QNetworkReply *reply = mgr.get(req);
    eventLoop.exec(); // blocks stack until "finished()" has been called

    if (reply->error() == QNetworkReply::NoError) {
        //get temp download url as json

        QJsonDocument jsondoc = QJsonDocument(QJsonDocument::fromJson(QString(reply->readAll()).toUtf8()));
        QJsonObject jobj = jsondoc.object();
        QString download_url = jobj["location"].toString();

        //download
        if (reply->error() == QNetworkReply::NoError) {
            req_url = download_url;
            QUrl url(req_url);
            QNetworkRequest req(url);
            req.setRawHeader("User-Agent",USER_AGENT);
            QNetworkReply *reply = mgr.get(req);
            eventLoop.exec();

            return reply->readAll();
        }
        else{
            qDebug() << "Failure on download request" <<reply->errorString();
            delete reply;
            return NULL;
        }

    }
    else {
        //failure
        qDebug() << "Failure on initial request" <<reply->errorString();
        delete reply;
        return NULL;
    }
}

<|endoftext|>


<commit_before>/*
 * This file is a part of Xpiks - cross platform application for
 * keywording and uploading images for microstocks
 * Copyright (C) 2014 Taras Kushnir <kushnirTV@gmail.com>
 *
 * Xpiks is distributed under the GNU General Public License, version 3.0
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "combinedartworksmodel.h"
#include "../Helpers/indiceshelper.h"

namespace Models {
    void CombinedArtworksModel::initArtworks(const QList<ArtItemInfo *> &artworks)
    {
        int innerLength = m_ArtworksList.length();
        int start = innerLength == 0 ? 0 : innerLength - 1;
        int paramLength = artworks.length();
        if (paramLength > 0) {
            beginInsertRows(QModelIndex(), start, start + paramLength - 1);
            m_ArtworksList.append(artworks);
            endInsertRows();
        }
        m_IsModified = false;
    }

    void CombinedArtworksModel::recombineArtworks()
    {
        bool anyItemsProcessed = false;
        bool descriptionsDiffer = false;
        bool titleDiffer = false;
        bool authorDiffer = false;
        QString description;
        QString title;
        QString author;
        QSet<QString> commonKeywords;

        int artworksCount = m_ArtworksList.length();
        for (int i = 0; i < artworksCount; ++i) {
            ArtItemInfo *info = m_ArtworksList[i];
            ArtworkMetadata *metadata = info->getOrigin();

            if (!anyItemsProcessed) {
                description = metadata->getDescription();
                title = metadata->getTitle();
                author = metadata->getAuthor();
                commonKeywords.unite(metadata->getKeywordsSet());
                anyItemsProcessed = true;
                continue;
            }

            const QString &currDescription = metadata->getDescription();
            const QString &currTitle = metadata->getTitle();
            const QString &currAuthor = metadata->getAuthor();
            descriptionsDiffer = descriptionsDiffer || description != currDescription;
            titleDiffer = titleDiffer || title != currTitle;
            authorDiffer = authorDiffer || author != currAuthor;
            commonKeywords.intersect(metadata->getKeywordsSet());
        }

        if (artworksCount > 0) {
            if (descriptionsDiffer) {
                description = "";
            }

            if (titleDiffer) {
                title = "";
            }

            if (authorDiffer) {
                author = "";
            }

            initDescription(description);
            initTitle(title);
            initAuthor(author);

            if (!m_IsModified) {
                initKeywords(commonKeywords.toList());
            }
        }
    }

    void CombinedArtworksModel::resetModelData()
    {
        beginResetModel();
        qDeleteAll(m_ArtworksList);
        m_ArtworksList.clear();
        endResetModel();

        setDescription("");
        setAuthor("");
        setTitle("");
        setKeywords(QStringList());
        m_CommonKeywordsSet.clear();
    }

    void CombinedArtworksModel::removeKeywordAt(int keywordIndex)
    {
        QString keyword;
        if (m_CommonKeywordsModel.removeKeyword(keywordIndex, keyword)) {
            m_CommonKeywordsSet.remove(keyword);
            emit keywordsCountChanged();
            m_IsModified = true;
        }
    }

    void CombinedArtworksModel::removeLastKeyword()
    {
        QString keyword;
        if (m_CommonKeywordsModel.removeLastKeyword(keyword)) {
            m_CommonKeywordsSet.remove(keyword);
            emit keywordsCountChanged();
            m_IsModified = true;
        }
    }

    void CombinedArtworksModel::appendKeyword(const QString &word)
    {
        QString keyword = word.simplified();
        if (!m_CommonKeywordsSet.contains(keyword)) {
            m_CommonKeywordsModel.appendKeyword(keyword);
            m_CommonKeywordsSet.insert(keyword);
            emit keywordsCountChanged();
            m_IsModified = true;
        }
    }

    void CombinedArtworksModel::selectArtwork(int index)
    {
        if (index < 0 || index >= m_ArtworksList.length()) {
            return;
        }

        m_ArtworksList[index]->select();
        QModelIndex qIndex = this->index(index);
        emit dataChanged(qIndex, qIndex, QVector<int>() << IsSelectedRole);
        emit selectedArtworksCountChanged();
    }

    void CombinedArtworksModel::deselectArtwork(int index)
    {
        if (index < 0 || index >= m_ArtworksList.length()) {
            return;
        }

        m_ArtworksList[index]->deselect();
        QModelIndex qIndex = this->index(index);
        emit dataChanged(qIndex, qIndex, QVector<int>() << IsSelectedRole);
        emit selectedArtworksCountChanged();
    }

    void CombinedArtworksModel::removeSelectedArtworks()
    {
        int count = m_ArtworksList.length();
        QList<int> indicesToRemove;
        for (int i = 0; i < count; ++i) {
            ArtItemInfo *item = m_ArtworksList[i];
            if (item->isSelected()) {
                indicesToRemove.append(i);
            }
        }

        QList<QPair<int, int> > rangesToRemove;
        Helpers::indicesToRanges(indicesToRemove, rangesToRemove);
        removeItemsAtIndices(rangesToRemove);

        recombineArtworks();
    }

    int CombinedArtworksModel::getSelectedArtworksCount() const
    {
        int selectedCount = 0;
        int count = m_ArtworksList.length();
        for (int i = 0; i < count; ++i) {
            ArtItemInfo *item = m_ArtworksList[i];
            if (item->isSelected()) {
                selectedCount++;
            }
        }

        return selectedCount;
    }

    void CombinedArtworksModel::saveSetKeywords()
    {
        foreach (ArtItemInfo* info, m_ArtworksList) {
            ArtworkMetadata *metadata = info->getOrigin();
            metadata->setKeywords(m_CommonKeywordsModel.getKeywords());
            metadata->setDescription(m_ArtworkDescription);
            metadata->setTitle(m_ArtworkTitle);
            metadata->setAuthor(m_ArtworkAuthor);
            metadata->saveBackup();
        }
    }

    void CombinedArtworksModel::saveAddKeywords()
    {
        foreach (ArtItemInfo* info, m_ArtworksList) {
            ArtworkMetadata *metadata = info->getOrigin();
            metadata->appendKeywords(m_CommonKeywordsModel.getKeywords());

            if (!m_ArtworkDescription.isEmpty()) {
                metadata->setDescription(m_ArtworkDescription);
            }

            if (!m_ArtworkTitle.isEmpty()) {
                metadata->setTitle(m_ArtworkTitle);
            }

            if (!m_ArtworkAuthor.isEmpty()) {
                metadata->setAuthor(m_ArtworkAuthor);
            }

            metadata->saveBackup();
        }
    }

    int CombinedArtworksModel::rowCount(const QModelIndex &parent) const
    {
        Q_UNUSED(parent);
        return m_ArtworksList.count();
    }

    QVariant CombinedArtworksModel::data(const QModelIndex &index, int role) const
    {
        if (index.row() < 0 || index.row() >= m_ArtworksList.count())
            return QVariant();

        ArtItemInfo *artItemInfo = m_ArtworksList.at(index.row());

        switch (role) {
        case PathRole:
            return artItemInfo->getOrigin()->getFilepath();
        case IsSelectedRole:
            return artItemInfo->isSelected();
        default:
            return QVariant();
        }
    }

    QHash<int, QByteArray> CombinedArtworksModel::roleNames() const
    {
        QHash<int, QByteArray> roles;
        roles[PathRole] = "path";
        roles[IsSelectedRole] = "isselected";
        return roles;
    }

    void CombinedArtworksModel::removeInnerItem(int row)
    {
        ArtItemInfo *info = m_ArtworksList[row];
        delete info;
        m_ArtworksList.removeAt(row);
    }
}
<commit_msg>Fix for Save and Append button. related #62<commit_after>/*
 * This file is a part of Xpiks - cross platform application for
 * keywording and uploading images for microstocks
 * Copyright (C) 2014 Taras Kushnir <kushnirTV@gmail.com>
 *
 * Xpiks is distributed under the GNU General Public License, version 3.0
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "combinedartworksmodel.h"
#include "../Helpers/indiceshelper.h"

namespace Models {
    void CombinedArtworksModel::initArtworks(const QList<ArtItemInfo *> &artworks)
    {
        int innerLength = m_ArtworksList.length();
        int start = innerLength == 0 ? 0 : innerLength - 1;
        int paramLength = artworks.length();
        if (paramLength > 0) {
            beginInsertRows(QModelIndex(), start, start + paramLength - 1);
            m_ArtworksList.append(artworks);
            endInsertRows();
        }
        m_IsModified = false;
    }

    void CombinedArtworksModel::recombineArtworks()
    {
        bool anyItemsProcessed = false;
        bool descriptionsDiffer = false;
        bool titleDiffer = false;
        bool authorDiffer = false;
        QString description;
        QString title;
        QString author;
        QSet<QString> commonKeywords;

        int artworksCount = m_ArtworksList.length();
        for (int i = 0; i < artworksCount; ++i) {
            ArtItemInfo *info = m_ArtworksList[i];
            ArtworkMetadata *metadata = info->getOrigin();

            if (!anyItemsProcessed) {
                description = metadata->getDescription();
                title = metadata->getTitle();
                author = metadata->getAuthor();
                commonKeywords.unite(metadata->getKeywordsSet());
                anyItemsProcessed = true;
                continue;
            }

            const QString &currDescription = metadata->getDescription();
            const QString &currTitle = metadata->getTitle();
            const QString &currAuthor = metadata->getAuthor();
            descriptionsDiffer = descriptionsDiffer || description != currDescription;
            titleDiffer = titleDiffer || title != currTitle;
            authorDiffer = authorDiffer || author != currAuthor;
            commonKeywords.intersect(metadata->getKeywordsSet());
        }

        if (artworksCount > 0) {
            if (descriptionsDiffer) {
                description = "";
            }

            if (titleDiffer) {
                title = "";
            }

            if (authorDiffer) {
                author = "";
            }

            initDescription(description);
            initTitle(title);
            initAuthor(author);

            if (!m_IsModified) {
                initKeywords(commonKeywords.toList());
            }
        }
    }

    void CombinedArtworksModel::resetModelData()
    {
        beginResetModel();
        qDeleteAll(m_ArtworksList);
        m_ArtworksList.clear();
        endResetModel();

        setDescription("");
        setAuthor("");
        setTitle("");
        setKeywords(QStringList());
        m_CommonKeywordsSet.clear();
    }

    void CombinedArtworksModel::removeKeywordAt(int keywordIndex)
    {
        QString keyword;
        if (m_CommonKeywordsModel.removeKeyword(keywordIndex, keyword)) {
            m_CommonKeywordsSet.remove(keyword);
            emit keywordsCountChanged();
            m_IsModified = true;
        }
    }

    void CombinedArtworksModel::removeLastKeyword()
    {
        QString keyword;
        if (m_CommonKeywordsModel.removeLastKeyword(keyword)) {
            m_CommonKeywordsSet.remove(keyword);
            emit keywordsCountChanged();
            m_IsModified = true;
        }
    }

    void CombinedArtworksModel::appendKeyword(const QString &word)
    {
        QString keyword = word.simplified();
        if (!m_CommonKeywordsSet.contains(keyword)) {
            m_CommonKeywordsModel.appendKeyword(keyword);
            m_CommonKeywordsSet.insert(keyword);
            emit keywordsCountChanged();
            m_IsModified = true;
        }
    }

    void CombinedArtworksModel::selectArtwork(int index)
    {
        if (index < 0 || index >= m_ArtworksList.length()) {
            return;
        }

        m_ArtworksList[index]->select();
        QModelIndex qIndex = this->index(index);
        emit dataChanged(qIndex, qIndex, QVector<int>() << IsSelectedRole);
        emit selectedArtworksCountChanged();
    }

    void CombinedArtworksModel::deselectArtwork(int index)
    {
        if (index < 0 || index >= m_ArtworksList.length()) {
            return;
        }

        m_ArtworksList[index]->deselect();
        QModelIndex qIndex = this->index(index);
        emit dataChanged(qIndex, qIndex, QVector<int>() << IsSelectedRole);
        emit selectedArtworksCountChanged();
    }

    void CombinedArtworksModel::removeSelectedArtworks()
    {
        int count = m_ArtworksList.length();
        QList<int> indicesToRemove;
        for (int i = 0; i < count; ++i) {
            ArtItemInfo *item = m_ArtworksList[i];
            if (item->isSelected()) {
                indicesToRemove.append(i);
            }
        }

        QList<QPair<int, int> > rangesToRemove;
        Helpers::indicesToRanges(indicesToRemove, rangesToRemove);
        removeItemsAtIndices(rangesToRemove);

        recombineArtworks();
    }

    int CombinedArtworksModel::getSelectedArtworksCount() const
    {
        int selectedCount = 0;
        int count = m_ArtworksList.length();
        for (int i = 0; i < count; ++i) {
            ArtItemInfo *item = m_ArtworksList[i];
            if (item->isSelected()) {
                selectedCount++;
            }
        }

        return selectedCount;
    }

    void CombinedArtworksModel::saveSetKeywords()
    {
        foreach (ArtItemInfo* info, m_ArtworksList) {
            ArtworkMetadata *metadata = info->getOrigin();
            metadata->setKeywords(m_CommonKeywordsModel.getKeywords());
            metadata->setDescription(m_ArtworkDescription);
            metadata->setTitle(m_ArtworkTitle);
            metadata->setAuthor(m_ArtworkAuthor);
            metadata->saveBackup();
        }
    }

    void CombinedArtworksModel::saveAddKeywords()
    {
        foreach (ArtItemInfo* info, m_ArtworksList) {
            ArtworkMetadata *metadata = info->getOrigin();
            metadata->appendKeywords(m_CommonKeywordsModel.getKeywords());

            if (!m_ArtworkDescription.isEmpty() && metadata->getDescription().isEmpty()) {
                metadata->setDescription(m_ArtworkDescription);
            }

            if (!m_ArtworkTitle.isEmpty() && metadata->getTitle().isEmpty()) {
                metadata->setTitle(m_ArtworkTitle);
            }

            if (!m_ArtworkAuthor.isEmpty() && metadata->getAuthor().isEmpty()) {
                metadata->setAuthor(m_ArtworkAuthor);
            }

            metadata->saveBackup();
        }
    }

    int CombinedArtworksModel::rowCount(const QModelIndex &parent) const
    {
        Q_UNUSED(parent);
        return m_ArtworksList.count();
    }

    QVariant CombinedArtworksModel::data(const QModelIndex &index, int role) const
    {
        if (index.row() < 0 || index.row() >= m_ArtworksList.count())
            return QVariant();

        ArtItemInfo *artItemInfo = m_ArtworksList.at(index.row());

        switch (role) {
        case PathRole:
            return artItemInfo->getOrigin()->getFilepath();
        case IsSelectedRole:
            return artItemInfo->isSelected();
        default:
            return QVariant();
        }
    }

    QHash<int, QByteArray> CombinedArtworksModel::roleNames() const
    {
        QHash<int, QByteArray> roles;
        roles[PathRole] = "path";
        roles[IsSelectedRole] = "isselected";
        return roles;
    }

    void CombinedArtworksModel::removeInnerItem(int row)
    {
        ArtItemInfo *info = m_ArtworksList[row];
        delete info;
        m_ArtworksList.removeAt(row);
    }
}
<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_MAT_FUN_CHOLESKY_DECOMPOSE_HPP
#define STAN_MATH_PRIM_MAT_FUN_CHOLESKY_DECOMPOSE_HPP

#include <stan/math/prim/mat/fun/Eigen.hpp>
#include <stan/math/prim/mat/err/check_pos_definite.hpp>
#include <stan/math/prim/mat/err/check_square.hpp>
#include <stan/math/prim/mat/err/check_symmetric.hpp>
#ifdef STAN_OPENCL
#include <stan/math/gpu/cholesky_decompose.hpp>
#include <algorithm>
#endif

namespace stan {
namespace math {

/**
 * Return the lower-triangular Cholesky factor (i.e., matrix
 * square root) of the specified square, symmetric matrix.  The return
 * value \f$L\f$ will be a lower-traingular matrix such that the
 * original matrix \f$A\f$ is given by
 * <p>\f$A = L \times L^T\f$.
 * @param m Symmetrix matrix.
 * @return Square root of matrix.
 * @throw std::domain_error if m is not a symmetric matrix or
 *   if m is not positive definite (if m has more than 0 elements)
 */
template <typename T>
Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> cholesky_decompose(
    const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& m) {
#ifdef STAN_OPENCL
  matrix_gpu m_gpu(m);
  Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> m_chol(m.rows(), m.cols());
  cholesky_decompose(m_gpu);
  copy(m_chol, m_gpu);
  return m_chol;
#else
  check_square("cholesky_decompose", "m", m);
  check_symmetric("cholesky_decompose", "m", m);
  Eigen::LLT<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> > llt(m.rows());
  llt.compute(m);
  check_pos_definite("cholesky_decompose", "m", llt);
  return llt.matrixL();
#endif
}

}  // namespace math
}  // namespace stan
#endif
<commit_msg>move check for square and symmetric to top of cholesky decompose prim<commit_after>#ifndef STAN_MATH_PRIM_MAT_FUN_CHOLESKY_DECOMPOSE_HPP
#define STAN_MATH_PRIM_MAT_FUN_CHOLESKY_DECOMPOSE_HPP

#include <stan/math/prim/mat/fun/Eigen.hpp>
#include <stan/math/prim/mat/err/check_pos_definite.hpp>
#include <stan/math/prim/mat/err/check_square.hpp>
#include <stan/math/prim/mat/err/check_symmetric.hpp>
#ifdef STAN_OPENCL
#include <stan/math/gpu/cholesky_decompose.hpp>
#include <algorithm>
#endif

namespace stan {
namespace math {

/**
 * Return the lower-triangular Cholesky factor (i.e., matrix
 * square root) of the specified square, symmetric matrix.  The return
 * value \f$L\f$ will be a lower-traingular matrix such that the
 * original matrix \f$A\f$ is given by
 * <p>\f$A = L \times L^T\f$.
 * @param m Symmetrix matrix.
 * @return Square root of matrix.
 * @throw std::domain_error if m is not a symmetric matrix or
 *   if m is not positive definite (if m has more than 0 elements)
 */
template <typename T>
Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> cholesky_decompose(
    const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& m) {
check_square("cholesky_decompose", "m", m);
check_symmetric("cholesky_decompose", "m", m);
#ifdef STAN_OPENCL
  matrix_gpu m_gpu(m);
  Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> m_chol(m.rows(), m.cols());
  cholesky_decompose(m_gpu);
  copy(m_chol, m_gpu);
  return m_chol;
#else
  Eigen::LLT<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> > llt(m.rows());
  llt.compute(m);
  check_pos_definite("cholesky_decompose", "m", llt);
  return llt.matrixL();
#endif
}

}  // namespace math
}  // namespace stan
#endif
<|endoftext|>


<commit_before>/*
The OpenTRV project licenses this file to you
under the Apache Licence, Version 2.0 (the "Licence");
you may not use this file except in compliance
with the Licence. You may obtain a copy of the Licence at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the Licence is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the Licence for the
specific language governing permissions and limitations
under the Licence.

Author(s) / Copyright (s): Damon Hart-Davis 2013--2016
                           Gary Gladman 2015
                           Mike Stirling 2013
*/

/*
 Wireless transceiver module support.
 */

#include "Radio.h"

#include "V0p2_Board_IO_Config.h" // I/O pin allocation: include ahead of I/O module headers.

#ifdef ENABLE_RADIO_SIM900
//For EEPROM:
//- Set the first field of SIM900LinkConfig to true.
//- The configs are stored as \0 terminated strings starting at 0x300.
//- You can program the eeprom using ./OTRadioLink/dev/utils/sim900eepromWrite.ino
//  static const void *SIM900_PIN      = (void *)0x0300; // TODO confirm this address
//  static const void *SIM900_APN      = (void *)0x0305;
//  static const void *SIM900_UDP_ADDR = (void *)0x031B;
//  static const void *SIM900_UDP_PORT = (void *)0x0329;
//  const OTSIM900Link::OTSIM900LinkConfig_t SIM900Config(
//                                                  true,
//                                                  SIM900_PIN,
//                                                  SIM900_APN,
//                                                  SIM900_UDP_ADDR,
//                                                  SIM900_UDP_PORT);
//For Flash:
//- Set the first field of SIM900LinkConfig to false.
//- The configs are stored as \0 terminated strings.
// - APNs - concirrus:  "internet.cxn"
//        - id:         "id"
  static const char SIM900_PIN[5] PROGMEM       = "1111";
  static const char SIM900_APN[] PROGMEM      = "\"everywhere\",\"eesecure\",\"secure\"";
  static const char SIM900_UDP_ADDR[14] PROGMEM = "46.101.64.191";
  static const char SIM900_UDP_PORT[5] PROGMEM = "9999";
  const OTSIM900Link::OTSIM900LinkConfig_t SIM900Config(
                                                  false,
                                                  SIM900_PIN,
                                                  SIM900_APN,
                                                  SIM900_UDP_ADDR,
                                                  SIM900_UDP_PORT);
#endif // ENABLE_RADIO_SIM900

#if defined(ENABLE_RADIO_NULL)
OTRadioLink::OTNullRadioLink NullRadio;
#endif

// Brings in necessary radio libs
#ifdef ENABLE_RADIO_RFM23B
#ifdef PIN_RFM_NIRQ
OTRFM23BLink::OTRFM23BLink<PIN_SPI_nSS, PIN_RFM_NIRQ> RFM23B;
#else
OTRFM23BLink::OTRFM23BLink<PIN_SPI_nSS, -1> RFM23B;
#endif
#endif // ENABLE_RADIO_RFM23B
#ifdef ENABLE_RADIO_SIM900
OTSIM900Link::OTSIM900Link SIM900(A3, A2, 8, 5);
#endif

// Assigns radio to PrimaryRadio alias
#if defined(RADIO_PRIMARY_RFM23B)
OTRadioLink::OTRadioLink &PrimaryRadio = RFM23B;
#elif defined(RADIO_PRIMARY_SIM900)
OTRadioLink::OTRadioLink &PrimaryRadio = SIM900;
#else
OTRadioLink::OTRadioLink &PrimaryRadio = NullRadio;
#endif // RADIO_PRIMARY_RFM23B

// Assign radio to SecondaryRadio alias.
#ifdef ENABLE_RADIO_SECONDARY_MODULE
#if defined(RADIO_SECONDARY_RFM23B)
OTRadioLink::OTRadioLink &SecondaryRadio = RFM23B;
#elif defined(RADIO_SECONDARY_SIM900)
OTRadioLink::OTRadioLink &SecondaryRadio = SIM900;
#else
OTRadioLink::OTRadioLink &SecondaryRadio = NullRadio;
#endif // RADIO_SECONDARY_RFM23B
#endif // ENABLE_RADIO_SECONDARY_MODULE

// RFM22 is apparently SPI mode 0 for Arduino library pov.

// Send the underlying stats binary/text 'whitened' message.
// This must be terminated with an 0xff (which is not sent),
// and no longer than STATS_MSG_MAX_LEN bytes long in total (excluding the terminating 0xff).
// This must not contain any 0xff and should not contain long runs of 0x00 bytes.
// The message to be sent must be written at an offset of STATS_MSG_START_OFFSET from the start of the buffer.
// This routine will alter the content of the buffer for transmission,
// and the buffer should not be re-used as is.
//   * doubleTX  double TX to increase chance of successful reception
//   * RFM23BfriendlyPremable  if true then add an extra preamble
//     to allow RFM23B-based receiver to RX this
// This will use whichever transmission medium/carrier/etc is available.
//#define STATS_MSG_START_OFFSET (RFM22_PREAMBLE_BYTES + RFM22_SYNC_MIN_BYTES)
//#define STATS_MSG_MAX_LEN (64 - STATS_MSG_START_OFFSET)
void RFM22RawStatsTXFFTerminated(uint8_t * const buf, const bool doubleTX, bool RFM23BFramed)
  {
  if(RFM23BFramed) RFM22RXPreambleAdd(buf);	// Only needed for RFM23B. This should be made more clear when refactoring
  const uint8_t buflen = OTRadioLink::frameLenFFTerminated(buf);
#if 0 && defined(DEBUG)
    DEBUG_SERIAL_PRINT_FLASHSTRING("buflen=");
    DEBUG_SERIAL_PRINT(buflen);
    DEBUG_SERIAL_PRINTLN();
#endif // DEBUG
  if(!PrimaryRadio.queueToSend(buf, buflen, 0, (doubleTX ? OTRadioLink::OTRadioLink::TXmax : OTRadioLink::OTRadioLink::TXnormal)))
    {
#if 0 && defined(DEBUG)
    DEBUG_SERIAL_PRINTLN_FLASHSTRING("!TX failed");
#endif
    } // DEBUG
  //DEBUG_SERIAL_PRINTLN_FLASHSTRING("RS");
  }

#ifdef ALLOW_CC1_SUPPORT_RELAY
#include <OTProtocolCC.h>
#include <OTRadValve.h>
#include "V0p2_Sensors.h"
// Send a CC1 Alert message with this unit's house code via the RFM23B.
bool sendCC1AlertByRFM23B()
  {
  OTProtocolCC::CC1Alert a = OTProtocolCC::CC1Alert::make(FHT8VGetHC1(), FHT8VGetHC2());
  if(a.isValid()) // Might be invalid if house codes are, eg if house codes not set.
    {
    uint8_t txbuf[STATS_MSG_START_OFFSET + OTProtocolCC::CC1Alert::primary_frame_bytes+1]; // More than large enough for preamble + sync + alert message.
    uint8_t *const bptr = RFM22RXPreambleAdd(txbuf);
    const uint8_t bodylen = a.encodeSimple(bptr, sizeof(txbuf) - STATS_MSG_START_OFFSET, true);
    const uint8_t buflen = STATS_MSG_START_OFFSET + bodylen;
#if 0 && defined(DEBUG)
OTRadioLink::printRXMsg(p, txbuf, buflen);
#endif
    // Send loud since the hub may be relatively far away,
    // there is no 'ACK', and these messages should not be sent very often.
    // Should be consistent with automatically-generated alerts to help with diagnosis.
    return(PrimaryRadio.sendRaw(txbuf, buflen, 0, OTRadioLink::OTRadioLink::TXmax));
    }
  return(false); // Failed.
  }
#endif
<commit_msg>Changed GSM to send to ORS server<commit_after>/*
The OpenTRV project licenses this file to you
under the Apache Licence, Version 2.0 (the "Licence");
you may not use this file except in compliance
with the Licence. You may obtain a copy of the Licence at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the Licence is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the Licence for the
specific language governing permissions and limitations
under the Licence.

Author(s) / Copyright (s): Damon Hart-Davis 2013--2016
                           Gary Gladman 2015
                           Mike Stirling 2013
*/

/*
 Wireless transceiver module support.
 */

#include "Radio.h"

#include "V0p2_Board_IO_Config.h" // I/O pin allocation: include ahead of I/O module headers.

#ifdef ENABLE_RADIO_SIM900
//For EEPROM:
//- Set the first field of SIM900LinkConfig to true.
//- The configs are stored as \0 terminated strings starting at 0x300.
//- You can program the eeprom using ./OTRadioLink/dev/utils/sim900eepromWrite.ino
//  static const void *SIM900_PIN      = (void *)0x0300; // TODO confirm this address
//  static const void *SIM900_APN      = (void *)0x0305;
//  static const void *SIM900_UDP_ADDR = (void *)0x031B;
//  static const void *SIM900_UDP_PORT = (void *)0x0329;
//  const OTSIM900Link::OTSIM900LinkConfig_t SIM900Config(
//                                                  true,
//                                                  SIM900_PIN,
//                                                  SIM900_APN,
//                                                  SIM900_UDP_ADDR,
//                                                  SIM900_UDP_PORT);
//For Flash:
//- Set the first field of SIM900LinkConfig to false.
//- The configs are stored as \0 terminated strings.
// - APNs - concirrus:  "internet.cxn"
//        - id:         "id"
  static const char SIM900_PIN[5] PROGMEM       = "1111";
  static const char SIM900_APN[] PROGMEM      = "\"everywhere\",\"eesecure\",\"secure\"";
  static const char SIM900_UDP_ADDR[14] PROGMEM = "46.101.52.242"; // ORS server
  static const char SIM900_UDP_PORT[5] PROGMEM = "9999";
  const OTSIM900Link::OTSIM900LinkConfig_t SIM900Config(
                                                  false,
                                                  SIM900_PIN,
                                                  SIM900_APN,
                                                  SIM900_UDP_ADDR,
                                                  SIM900_UDP_PORT);
#endif // ENABLE_RADIO_SIM900

#if defined(ENABLE_RADIO_NULL)
OTRadioLink::OTNullRadioLink NullRadio;
#endif

// Brings in necessary radio libs
#ifdef ENABLE_RADIO_RFM23B
#ifdef PIN_RFM_NIRQ
OTRFM23BLink::OTRFM23BLink<PIN_SPI_nSS, PIN_RFM_NIRQ> RFM23B;
#else
OTRFM23BLink::OTRFM23BLink<PIN_SPI_nSS, -1> RFM23B;
#endif
#endif // ENABLE_RADIO_RFM23B
#ifdef ENABLE_RADIO_SIM900
OTSIM900Link::OTSIM900Link SIM900(A3, A2, 8, 5);
#endif

// Assigns radio to PrimaryRadio alias
#if defined(RADIO_PRIMARY_RFM23B)
OTRadioLink::OTRadioLink &PrimaryRadio = RFM23B;
#elif defined(RADIO_PRIMARY_SIM900)
OTRadioLink::OTRadioLink &PrimaryRadio = SIM900;
#else
OTRadioLink::OTRadioLink &PrimaryRadio = NullRadio;
#endif // RADIO_PRIMARY_RFM23B

// Assign radio to SecondaryRadio alias.
#ifdef ENABLE_RADIO_SECONDARY_MODULE
#if defined(RADIO_SECONDARY_RFM23B)
OTRadioLink::OTRadioLink &SecondaryRadio = RFM23B;
#elif defined(RADIO_SECONDARY_SIM900)
OTRadioLink::OTRadioLink &SecondaryRadio = SIM900;
#else
OTRadioLink::OTRadioLink &SecondaryRadio = NullRadio;
#endif // RADIO_SECONDARY_RFM23B
#endif // ENABLE_RADIO_SECONDARY_MODULE

// RFM22 is apparently SPI mode 0 for Arduino library pov.

// Send the underlying stats binary/text 'whitened' message.
// This must be terminated with an 0xff (which is not sent),
// and no longer than STATS_MSG_MAX_LEN bytes long in total (excluding the terminating 0xff).
// This must not contain any 0xff and should not contain long runs of 0x00 bytes.
// The message to be sent must be written at an offset of STATS_MSG_START_OFFSET from the start of the buffer.
// This routine will alter the content of the buffer for transmission,
// and the buffer should not be re-used as is.
//   * doubleTX  double TX to increase chance of successful reception
//   * RFM23BfriendlyPremable  if true then add an extra preamble
//     to allow RFM23B-based receiver to RX this
// This will use whichever transmission medium/carrier/etc is available.
//#define STATS_MSG_START_OFFSET (RFM22_PREAMBLE_BYTES + RFM22_SYNC_MIN_BYTES)
//#define STATS_MSG_MAX_LEN (64 - STATS_MSG_START_OFFSET)
void RFM22RawStatsTXFFTerminated(uint8_t * const buf, const bool doubleTX, bool RFM23BFramed)
  {
  if(RFM23BFramed) RFM22RXPreambleAdd(buf);	// Only needed for RFM23B. This should be made more clear when refactoring
  const uint8_t buflen = OTRadioLink::frameLenFFTerminated(buf);
#if 0 && defined(DEBUG)
    DEBUG_SERIAL_PRINT_FLASHSTRING("buflen=");
    DEBUG_SERIAL_PRINT(buflen);
    DEBUG_SERIAL_PRINTLN();
#endif // DEBUG
  if(!PrimaryRadio.queueToSend(buf, buflen, 0, (doubleTX ? OTRadioLink::OTRadioLink::TXmax : OTRadioLink::OTRadioLink::TXnormal)))
    {
#if 0 && defined(DEBUG)
    DEBUG_SERIAL_PRINTLN_FLASHSTRING("!TX failed");
#endif
    } // DEBUG
  //DEBUG_SERIAL_PRINTLN_FLASHSTRING("RS");
  }

#ifdef ALLOW_CC1_SUPPORT_RELAY
#include <OTProtocolCC.h>
#include <OTRadValve.h>
#include "V0p2_Sensors.h"
// Send a CC1 Alert message with this unit's house code via the RFM23B.
bool sendCC1AlertByRFM23B()
  {
  OTProtocolCC::CC1Alert a = OTProtocolCC::CC1Alert::make(FHT8VGetHC1(), FHT8VGetHC2());
  if(a.isValid()) // Might be invalid if house codes are, eg if house codes not set.
    {
    uint8_t txbuf[STATS_MSG_START_OFFSET + OTProtocolCC::CC1Alert::primary_frame_bytes+1]; // More than large enough for preamble + sync + alert message.
    uint8_t *const bptr = RFM22RXPreambleAdd(txbuf);
    const uint8_t bodylen = a.encodeSimple(bptr, sizeof(txbuf) - STATS_MSG_START_OFFSET, true);
    const uint8_t buflen = STATS_MSG_START_OFFSET + bodylen;
#if 0 && defined(DEBUG)
OTRadioLink::printRXMsg(p, txbuf, buflen);
#endif
    // Send loud since the hub may be relatively far away,
    // there is no 'ACK', and these messages should not be sent very often.
    // Should be consistent with automatically-generated alerts to help with diagnosis.
    return(PrimaryRadio.sendRaw(txbuf, buflen, 0, OTRadioLink::OTRadioLink::TXmax));
    }
  return(false); // Failed.
  }
#endif
<|endoftext|>


<commit_before>#include <string>
#include <iostream>
#include "../stringtools.h"
#include "../urbackupcommon/os_functions.h"
#include <stdlib.h>
#ifndef _WIN32
#include <unistd.h>
#endif

#define DEF_Server
#include "../Server.h"

const std::string btrfs_cmd="/sbin/btrfs";

CServer *Server;

#ifdef _WIN32
#include <Windows.h>

bool CopyFolder(std::wstring src, std::wstring dst)
{
	if(!os_create_dir(dst))
		return false;

	std::vector<SFile> curr_files=getFiles(src);
	for(size_t i=0;i<curr_files.size();++i)
	{
		if(curr_files[i].isdir)
		{
			bool b=CopyFolder(src+os_file_sep()+curr_files[i].name, dst+os_file_sep()+curr_files[i].name);
			if(!b)
				return false;
		}
		else
		{
			if(!os_create_hardlink(dst+os_file_sep()+curr_files[i].name, src+os_file_sep()+curr_files[i].name, false) )
			{
				BOOL b=CopyFileW( (src+os_file_sep()+curr_files[i].name).c_str(), (dst+os_file_sep()+curr_files[i].name).c_str(), FALSE);
				if(!b)
				{
					return false;
				}
			}
		}
	}

	return true;
}
#endif

std::string getBackupfolderPath(void)
{
	std::string fn;
#ifdef _WIN32
	fn=trim(getFile("backupfolder"));
#else
	fn=trim(getFile("/etc/urbackup/backupfolder"));
#endif
	if(fn.find("\n")!=std::string::npos)
		fn=getuntil("\n", fn);
	if(fn.find("\r")!=std::string::npos)
		fn=getuntil("\r", fn);

	return fn;
}

std::string handleFilename(std::string fn)
{
	fn=conv_filename(fn);
	if(fn=="..")
	{
		return "";
	}
	return fn;
}

bool create_subvolume(std::string subvolume_folder)
{
#ifdef _WIN32
	return os_create_dir(subvolume_folder);
#else
	int rc=system((btrfs_cmd+" subvolume create \""+subvolume_folder+"\"").c_str());
	system(("chown urbackup:urbackup \""+subvolume_folder+"\"").c_str());
	return rc==0;
#endif
}

bool create_snapshot(std::string snapshot_src, std::string snapshot_dst)
{
#ifdef _WIN32
	return CopyFolder(widen(snapshot_src), widen(snapshot_dst));
#else
	int rc=system((btrfs_cmd+" subvolume snapshot \""+snapshot_src+"\" \""+snapshot_dst+"\"").c_str());
	system(("chown urbackup:urbackup \""+snapshot_dst+"\"").c_str());
	return rc==0;
#endif
}

bool remove_subvolume(std::string subvolume_folder)
{
#ifdef _WIN32
	return os_remove_nonempty_dir(widen(subvolume_folder));
#else
	int rc=system((btrfs_cmd+" subvolume delete \""+subvolume_folder+"\"").c_str());
	return rc==0;
#endif
}

bool is_subvolume(std::string subvolume_folder)
{
#ifdef _WIN32
	return true;
#else
	int rc=system((btrfs_cmd+" subvolume list \""+subvolume_folder+"\"").c_str());
	return rc==0;
#endif
}

int main(int argc, char *argv[])
{
	if(argc<2)
	{
		std::cout << "Not enough parameters" << std::endl;
		return 1;
	}

	std::string cmd=argv[1];

	std::string backupfolder=getBackupfolderPath();

	if(backupfolder.empty())
	{
		std::cout << "Backupfolder not set" << std::endl;
		return 1;
	}

#ifndef _WIN32
	if(seteuid(0)!=0)
	{
		std::cout << "Cannot become root user" << std::endl;
		return 1;
	}
#endif

	if(cmd=="create")
	{
		if(argc<4)
		{
			std::cout << "Not enough parameters for create" << std::endl;
			return 1;
		}

		std::string clientname=handleFilename(argv[2]);
		std::string name=handleFilename(argv[3]);

		std::string subvolume_folder=backupfolder+os_file_sepn()+clientname+os_file_sepn()+name;

		return create_subvolume(subvolume_folder)?0:1;
	}
	else if(cmd=="snapshot")
	{
		if(argc<5)
		{
			std::cout << "Not enough parameters for snapshot" << std::endl;
			return 1;
		}

		std::string clientname=handleFilename(argv[2]);
		std::string src_name=handleFilename(argv[3]);
		std::string dst_name=handleFilename(argv[4]);

		std::string subvolume_src_folder=backupfolder+os_file_sepn()+clientname+os_file_sepn()+src_name;
		std::string subvolume_dst_folder=backupfolder+os_file_sepn()+clientname+os_file_sepn()+dst_name;

		return create_snapshot(subvolume_src_folder, subvolume_dst_folder)?0:1;
	}
	else if(cmd=="remove")
	{
		if(argc<4)
		{
			std::cout << "Not enough parameters for remove" << std::endl;
			return 1;
		}

		std::string clientname=handleFilename(argv[2]);
		std::string name=handleFilename(argv[3]);

		std::string subvolume_folder=backupfolder+os_file_sepn()+clientname+os_file_sepn()+name;

		return remove_subvolume(subvolume_folder)?0:1;
	}
	else if(cmd=="test")
	{
		std::string clientdir=backupfolder+os_file_sepn()+"testA54hj5luZtlorr494";
		if(os_create_dir(clientdir))
		{

			if(!create_subvolume(clientdir+os_file_sepn()+"A") )
			{
				std::cout << "Creating test subvolume failed" << std::endl;
				os_remove_dir(clientdir);
				return 1;
			}

			bool suc=true;

			if(!create_snapshot(clientdir+os_file_sepn()+"A", clientdir+os_file_sepn()+"B") )
			{
				std::cout << "Creating test snapshot failed" << std::endl;
				suc=false;
			}

			if(suc)
			{
				writestring("test", clientdir+os_file_sepn()+"A"+os_file_sepn()+"test");

				if(!os_create_hardlink(clientdir+os_file_sepn()+"B"+os_file_sepn()+"test", clientdir+os_file_sepn()+"A"+os_file_sepn()+"test", true))
				{
					std::cout << "Cross subvolume reflink failed" << std::endl;
					suc=false;
				}

				if(getFile(clientdir+os_file_sepn()+"B"+os_file_sepn()+"test")!="test")
				{
					std::cout << "Cannot read reflinked file" << std::endl;
					suc=false;
				}
			}

			if(!remove_subvolume(clientdir+os_file_sepn()+"A") )
			{
				std::cout << "Removing subvolume A failed" << std::endl;
				suc=false;
			}

			if(!remove_subvolume(clientdir+os_file_sepn()+"B") )
			{
				std::cout << "Removing subvolume B failed" << std::endl;
				suc=false;
			}

			if(!os_remove_dir(clientdir))
			{
				std::cout << "Removing test clientdir failed" << std::endl;
				return 1;
			}

			if(!suc)
			{
				return 1;
			}
		}
		else
		{
			std::cout << "Creating test clientdir \"" << clientdir << "\" failed" << std::endl;
			return 1;
		}
		return 0;
	}
	else if(cmd=="issubvolume")
	{
		if(argc<4)
		{
			std::cout << "Not enough parameters for issubvolume" << std::endl;
			return 1;
		}

		std::string clientname=handleFilename(argv[2]);
		std::string name=handleFilename(argv[3]);

		std::string subvolume_folder=backupfolder+os_file_sepn()+clientname+os_file_sepn()+name;

		return is_subvolume(subvolume_folder)?0:1;
	}
	else
	{
		std::cout << "Command not found" << std::endl;
		return 1;
	}
}

<commit_msg>Fixed Linux build issue (cherry picked from commit eee5f7683d8f58dc997e00b684a7d0f3d2ff5e69)<commit_after>#include <string>
#include <iostream>
#include "../stringtools.h"
#include "../urbackupcommon/os_functions.h"
#include <stdlib.h>
#ifndef _WIN32
#include <unistd.h>
#endif

#define DEF_Server
#include "../Server.h"

const std::string btrfs_cmd="/sbin/btrfs";

CServer *Server;

#ifdef _WIN32
#include <Windows.h>

bool CopyFolder(std::wstring src, std::wstring dst)
{
	if(!os_create_dir(dst))
		return false;

	std::vector<SFile> curr_files=getFiles(src);
	for(size_t i=0;i<curr_files.size();++i)
	{
		if(curr_files[i].isdir)
		{
			bool b=CopyFolder(src+os_file_sep()+curr_files[i].name, dst+os_file_sep()+curr_files[i].name);
			if(!b)
				return false;
		}
		else
		{
			if(!os_create_hardlink(dst+os_file_sep()+curr_files[i].name, src+os_file_sep()+curr_files[i].name, false, NULL) )
			{
				BOOL b=CopyFileW( (src+os_file_sep()+curr_files[i].name).c_str(), (dst+os_file_sep()+curr_files[i].name).c_str(), FALSE);
				if(!b)
				{
					return false;
				}
			}
		}
	}

	return true;
}
#endif

std::string getBackupfolderPath(void)
{
	std::string fn;
#ifdef _WIN32
	fn=trim(getFile("backupfolder"));
#else
	fn=trim(getFile("/etc/urbackup/backupfolder"));
#endif
	if(fn.find("\n")!=std::string::npos)
		fn=getuntil("\n", fn);
	if(fn.find("\r")!=std::string::npos)
		fn=getuntil("\r", fn);

	return fn;
}

std::string handleFilename(std::string fn)
{
	fn=conv_filename(fn);
	if(fn=="..")
	{
		return "";
	}
	return fn;
}

bool create_subvolume(std::string subvolume_folder)
{
#ifdef _WIN32
	return os_create_dir(subvolume_folder);
#else
	int rc=system((btrfs_cmd+" subvolume create \""+subvolume_folder+"\"").c_str());
	system(("chown urbackup:urbackup \""+subvolume_folder+"\"").c_str());
	return rc==0;
#endif
}

bool create_snapshot(std::string snapshot_src, std::string snapshot_dst)
{
#ifdef _WIN32
	return CopyFolder(widen(snapshot_src), widen(snapshot_dst));
#else
	int rc=system((btrfs_cmd+" subvolume snapshot \""+snapshot_src+"\" \""+snapshot_dst+"\"").c_str());
	system(("chown urbackup:urbackup \""+snapshot_dst+"\"").c_str());
	return rc==0;
#endif
}

bool remove_subvolume(std::string subvolume_folder)
{
#ifdef _WIN32
	return os_remove_nonempty_dir(widen(subvolume_folder));
#else
	int rc=system((btrfs_cmd+" subvolume delete \""+subvolume_folder+"\"").c_str());
	return rc==0;
#endif
}

bool is_subvolume(std::string subvolume_folder)
{
#ifdef _WIN32
	return true;
#else
	int rc=system((btrfs_cmd+" subvolume list \""+subvolume_folder+"\"").c_str());
	return rc==0;
#endif
}

int main(int argc, char *argv[])
{
	if(argc<2)
	{
		std::cout << "Not enough parameters" << std::endl;
		return 1;
	}

	std::string cmd=argv[1];

	std::string backupfolder=getBackupfolderPath();

	if(backupfolder.empty())
	{
		std::cout << "Backupfolder not set" << std::endl;
		return 1;
	}

#ifndef _WIN32
	if(seteuid(0)!=0)
	{
		std::cout << "Cannot become root user" << std::endl;
		return 1;
	}
#endif

	if(cmd=="create")
	{
		if(argc<4)
		{
			std::cout << "Not enough parameters for create" << std::endl;
			return 1;
		}

		std::string clientname=handleFilename(argv[2]);
		std::string name=handleFilename(argv[3]);

		std::string subvolume_folder=backupfolder+os_file_sepn()+clientname+os_file_sepn()+name;

		return create_subvolume(subvolume_folder)?0:1;
	}
	else if(cmd=="snapshot")
	{
		if(argc<5)
		{
			std::cout << "Not enough parameters for snapshot" << std::endl;
			return 1;
		}

		std::string clientname=handleFilename(argv[2]);
		std::string src_name=handleFilename(argv[3]);
		std::string dst_name=handleFilename(argv[4]);

		std::string subvolume_src_folder=backupfolder+os_file_sepn()+clientname+os_file_sepn()+src_name;
		std::string subvolume_dst_folder=backupfolder+os_file_sepn()+clientname+os_file_sepn()+dst_name;

		return create_snapshot(subvolume_src_folder, subvolume_dst_folder)?0:1;
	}
	else if(cmd=="remove")
	{
		if(argc<4)
		{
			std::cout << "Not enough parameters for remove" << std::endl;
			return 1;
		}

		std::string clientname=handleFilename(argv[2]);
		std::string name=handleFilename(argv[3]);

		std::string subvolume_folder=backupfolder+os_file_sepn()+clientname+os_file_sepn()+name;

		return remove_subvolume(subvolume_folder)?0:1;
	}
	else if(cmd=="test")
	{
		std::string clientdir=backupfolder+os_file_sepn()+"testA54hj5luZtlorr494";
		if(os_create_dir(clientdir))
		{

			if(!create_subvolume(clientdir+os_file_sepn()+"A") )
			{
				std::cout << "Creating test subvolume failed" << std::endl;
				os_remove_dir(clientdir);
				return 1;
			}

			bool suc=true;

			if(!create_snapshot(clientdir+os_file_sepn()+"A", clientdir+os_file_sepn()+"B") )
			{
				std::cout << "Creating test snapshot failed" << std::endl;
				suc=false;
			}

			if(suc)
			{
				writestring("test", clientdir+os_file_sepn()+"A"+os_file_sepn()+"test");

				if(!os_create_hardlink(clientdir+os_file_sepn()+"B"+os_file_sepn()+"test", clientdir+os_file_sepn()+"A"+os_file_sepn()+"test", true, NULL))
				{
					std::cout << "Cross subvolume reflink failed" << std::endl;
					suc=false;
				}

				if(getFile(clientdir+os_file_sepn()+"B"+os_file_sepn()+"test")!="test")
				{
					std::cout << "Cannot read reflinked file" << std::endl;
					suc=false;
				}
			}

			if(!remove_subvolume(clientdir+os_file_sepn()+"A") )
			{
				std::cout << "Removing subvolume A failed" << std::endl;
				suc=false;
			}

			if(!remove_subvolume(clientdir+os_file_sepn()+"B") )
			{
				std::cout << "Removing subvolume B failed" << std::endl;
				suc=false;
			}

			if(!os_remove_dir(clientdir))
			{
				std::cout << "Removing test clientdir failed" << std::endl;
				return 1;
			}

			if(!suc)
			{
				return 1;
			}
		}
		else
		{
			std::cout << "Creating test clientdir \"" << clientdir << "\" failed" << std::endl;
			return 1;
		}
		return 0;
	}
	else if(cmd=="issubvolume")
	{
		if(argc<4)
		{
			std::cout << "Not enough parameters for issubvolume" << std::endl;
			return 1;
		}

		std::string clientname=handleFilename(argv[2]);
		std::string name=handleFilename(argv[3]);

		std::string subvolume_folder=backupfolder+os_file_sepn()+clientname+os_file_sepn()+name;

		return is_subvolume(subvolume_folder)?0:1;
	}
	else
	{
		std::cout << "Command not found" << std::endl;
		return 1;
	}
}

<|endoftext|>


<commit_before>// Copyright (c) 2018 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#pragma once

#include <cstdint>
#include <memory>
#include <sstream>
#include <string>
#include <string_view>

#if !defined(_MEVO_UNUSED)
# define _MEVO_UNUSED(x) ((void)x)
#endif

#if !defined(_MEVO_CHECK)
# include <cstdlib>
# define _MEVO_CHECK(condition, message) do {\
    if (!(condition)) {\
        std::fprintf(stderr,\
            "[%s:%d] CHECKING FAILED `%s()` - `%s` - %s\n",\
            __FILE__,\
            __LINE__,\
            __func__,\
            #condition,\
            (message));\
        std::fflush(stderr);\
        std::abort();\
    }\
  } while (0)
#endif

#if !defined(_MEVO_COUNTOF)
# define _MEVO_COUNTOF(array) sizeof(_mevo::__countof_impl(array).elements)
#endif

namespace _mevo {

using nil_t   = std::nullptr_t;
using byte_t  = std::uint8_t;
using i8_t    = std::int8_t;
using u8_t    = std::uint8_t;
using i16_t   = std::int16_t;
using u16_t   = std::uint16_t;
using i32_t   = std::int32_t;
using u32_t   = std::uint32_t;
using i64_t   = std::int64_t;
using u64_t   = std::uint64_t;
using sz_t    = std::size_t;
using str_t   = std::string;
using strv_t  = std::string_view;
using ss_t    = std::stringstream;

template <std::ptrdiff_t N> struct Sizer { char elements[N]; };
template <typename T, std::ptrdiff_t N> Sizer<N> __countof_impl(T (&array)[N]);

template <typename T> struct Identity { typedef T type; };
template <typename T>
inline T implicit_cast(typename Identity<T>::type x) noexcept {
  return x;
}

template <typename T, typename S> inline T as_type(S x) noexcept {
  return static_cast<T>(x);
}

template <typename T, typename S> inline T* down(S* x) noexcept {
  return dynamic_cast<T*>(x);
}

template <typename T>
inline T* get_raw_pointer(const std::unique_ptr<T>& p) noexcept {
  return p.get();
}

template <typename T>
inline T* get_raw_pointer(const std::shared_ptr<T>& p) noexcept {
  return p.get();
}

}
<commit_msg>:construction: chore(utils): add util function about converting numeric to string<commit_after>// Copyright (c) 2018 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#pragma once

#include <cstdint>
#include <iomanip>
#include <memory>
#include <sstream>
#include <string>
#include <string_view>

#if !defined(_MEVO_UNUSED)
# define _MEVO_UNUSED(x) ((void)x)
#endif

#if !defined(_MEVO_CHECK)
# include <cstdlib>
# define _MEVO_CHECK(condition, message) do {\
    if (!(condition)) {\
        std::fprintf(stderr,\
            "[%s:%d] CHECKING FAILED `%s()` - `%s` - %s\n",\
            __FILE__,\
            __LINE__,\
            __func__,\
            #condition,\
            (message));\
        std::fflush(stderr);\
        std::abort();\
    }\
  } while (0)
#endif

#if !defined(_MEVO_COUNTOF)
# define _MEVO_COUNTOF(array) sizeof(_mevo::__countof_impl(array).elements)
#endif

namespace _mevo {

using nil_t   = std::nullptr_t;
using byte_t  = std::uint8_t;
using i8_t    = std::int8_t;
using u8_t    = std::uint8_t;
using i16_t   = std::int16_t;
using u16_t   = std::uint16_t;
using i32_t   = std::int32_t;
using u32_t   = std::uint32_t;
using i64_t   = std::int64_t;
using u64_t   = std::uint64_t;
using sz_t    = std::size_t;
using str_t   = std::string;
using strv_t  = std::string_view;
using ss_t    = std::stringstream;

template <std::ptrdiff_t N> struct Sizer { char elements[N]; };
template <typename T, std::ptrdiff_t N> Sizer<N> __countof_impl(T (&array)[N]);

template <typename T> struct Identity { typedef T type; };
template <typename T>
inline T implicit_cast(typename Identity<T>::type x) noexcept {
  return x;
}

template <typename T, typename S> inline T as_type(S x) noexcept {
  return static_cast<T>(x);
}

template <typename T, typename S> inline T* down(S* x) noexcept {
  return dynamic_cast<T*>(x);
}

template <typename T>
inline T* get_raw_pointer(const std::unique_ptr<T>& p) noexcept {
  return p.get();
}

template <typename T>
inline T* get_raw_pointer(const std::shared_ptr<T>& p) noexcept {
  return p.get();
}

inline str_t convert_to_string(double d) noexcept {
  ss_t ss;
  ss << std::setprecision(std::numeric_limits<double>::max_digits10) << d;
  return ss.str();
}

}
<|endoftext|>


<commit_before>/*
  Copyright (c) DataStax, Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

#include "connection_pool_manager.hpp"

#include "config.hpp"
#include "memory.hpp"
#include "scoped_lock.hpp"
#include "utils.hpp"

namespace cass {

class NopConnectionPoolManagerListener : public ConnectionPoolManagerListener {
public:
  virtual void on_pool_up(const Address& address) { }

  virtual void on_pool_down(const Address& address) { }

  virtual void on_pool_critical_error(const Address& address,
                                 Connector::ConnectionError code,
                                 const String& message) { }

  virtual void on_close(ConnectionPoolManager* manager) { }
};

static NopConnectionPoolManagerListener nop_connection_pool_manager_listener__;

ConnectionPoolManagerSettings::ConnectionPoolManagerSettings()
  : num_connections_per_host(CASS_DEFAULT_NUM_CONNECTIONS_PER_HOST)
  , reconnect_wait_time_ms(CASS_DEFAULT_RECONNECT_WAIT_TIME_MS) { }

ConnectionPoolManagerSettings::ConnectionPoolManagerSettings(const Config& config)
  : connection_settings(config)
  , num_connections_per_host(config.core_connections_per_host())
  , reconnect_wait_time_ms(config.reconnect_wait_time_ms()) { }

ConnectionPoolManager::ConnectionPoolManager(uv_loop_t* loop,
                                             int protocol_version,
                                             const String& keyspace,
                                             ConnectionPoolManagerListener* listener,
                                             Metrics* metrics,
                                             const ConnectionPoolManagerSettings& settings)
  : loop_(loop)
  , protocol_version_(protocol_version)
  , settings_(settings)
  , close_state_(CLOSE_STATE_OPEN)
  , keyspace_(keyspace)
  , metrics_(metrics)
#ifdef CASS_INTERNAL_DIAGNOSTICS
  , flush_bytes_("flushed")
#endif
{
  inc_ref(); // Reference for the lifetime of the connection pools
  uv_mutex_init(&keyspace_mutex_);
  set_pointer_keys(to_flush_);
  set_listener(listener);
}

ConnectionPoolManager::~ConnectionPoolManager() {
  uv_mutex_destroy(&keyspace_mutex_);
}

PooledConnection::Ptr ConnectionPoolManager::find_least_busy(const Address& address) const {
  ConnectionPool::Map::const_iterator it = pools_.find(address);
  if (it == pools_.end()) {
    return PooledConnection::Ptr();
  }
  return it->second->find_least_busy();
}

void ConnectionPoolManager::flush() {
  for (DenseHashSet<ConnectionPool*>::const_iterator it = to_flush_.begin(),
       end = to_flush_.end(); it != end; ++it) {
    (*it)->flush();
  }
  to_flush_.clear();

}

AddressVec ConnectionPoolManager::available() const {
  AddressVec result;
  result.reserve(pools_.size());
  for (ConnectionPool::Map::const_iterator it = pools_.begin(),
       end = pools_.end(); it != end; ++it) {
    result.push_back(it->first);
  }
  return result;
}

void ConnectionPoolManager::add(const Address& address) {
  ConnectionPool::Map::iterator it = pools_.find(address);
  if (it != pools_.end()) return;

  for (ConnectionPoolConnector::Vec::iterator it = pending_pools_.begin(),
       end = pending_pools_.end(); it != end; ++it) {
    if ((*it)->address() == address) return;
  }

  ConnectionPoolConnector::Ptr connector(
        Memory::allocate<ConnectionPoolConnector>(this,
                                                  address,
                                                  bind_callback(&ConnectionPoolManager::on_connect, this)));
  pending_pools_.push_back(connector);
  connector->connect();
}

void ConnectionPoolManager::remove(const Address& address) {
  ConnectionPool::Map::iterator it = pools_.find(address);
  if (it == pools_.end()) return;
  // The connection pool will remove itself from the manager when all of its
  // connections are closed.
  it->second->close();
}

void ConnectionPoolManager::close() {
  if (close_state_ == CLOSE_STATE_OPEN) {
    close_state_ = CLOSE_STATE_CLOSING;
    if (maybe_closed()) {
      return;
    }

    // Make copies of pool/connector data structures to prevent iterator
    // invalidation.

    ConnectionPool::Map pools(pools_);
    for (ConnectionPool::Map::iterator it = pools.begin(),
         end = pools.end(); it != end; ++it) {
      it->second->close();
    }

    ConnectionPoolConnector::Vec pending_pools(pending_pools_);
    for (ConnectionPoolConnector::Vec::iterator it = pending_pools.begin(),
         end = pending_pools.end(); it != end; ++it) {
      (*it)->cancel();
    }
  }
}

void ConnectionPoolManager::set_listener(ConnectionPoolManagerListener* listener) {
  listener_ = listener ? listener : &nop_connection_pool_manager_listener__;
}

String ConnectionPoolManager::keyspace() const {
  ScopedMutex l(&keyspace_mutex_);
  return keyspace_;
}

void ConnectionPoolManager::set_keyspace(const String& keyspace) {
  ScopedMutex l(&keyspace_mutex_);
  keyspace_ = keyspace;
}

void ConnectionPoolManager::add_pool(const ConnectionPool::Ptr& pool, Protected) {
  internal_add_pool(pool);
}

void ConnectionPoolManager::notify_closed(ConnectionPool* pool, bool should_notify_down, Protected) {
  pools_.erase(pool->address());
  to_flush_.erase(pool);
  if (should_notify_down) {
    listener_->on_pool_down(pool->address());
  }
  maybe_closed();
}

void ConnectionPoolManager::notify_up(ConnectionPool* pool, Protected) {
  listener_->on_pool_up(pool->address());
}

void ConnectionPoolManager::notify_down(ConnectionPool* pool, Protected) {
  listener_->on_pool_down(pool->address());
}

void ConnectionPoolManager::notify_critical_error(ConnectionPool* pool,
                                                  Connector::ConnectionError code,
                                                  const String& message,
                                                  Protected) {
  listener_->on_pool_critical_error(pool->address(), code, message);
}

void ConnectionPoolManager::requires_flush(ConnectionPool* pool, ConnectionPoolManager::Protected) {
  to_flush_.insert(pool);
}

void ConnectionPoolManager::internal_add_pool(const ConnectionPool::Ptr& pool) {
  LOG_DEBUG("Adding pool for host %s", pool->address().to_string().c_str());
  pools_[pool->address()] = pool;
}

// This must be the last call in a function because it can potentially
// deallocate the manager.
bool ConnectionPoolManager::maybe_closed() {
  if (close_state_ == CLOSE_STATE_CLOSING && pools_.empty()) {
    close_state_ = CLOSE_STATE_CLOSED;
    listener_->on_close(this);
    dec_ref();
    return true;
  }
  return false;
}

void ConnectionPoolManager::on_connect(ConnectionPoolConnector* pool_connector) {
  pending_pools_.erase(std::remove(pending_pools_.begin(), pending_pools_.end(), pool_connector),
                       pending_pools_.end());
  if (pool_connector->is_ok()) {
    internal_add_pool(pool_connector->release_pool());
  } else {
    listener_->on_pool_critical_error(pool_connector->address(),
                                      pool_connector->error_code(),
                                      pool_connector->error_message());
  }
}

} // namespace cass
<commit_msg>CPP-620 - Close the pool manager only after pending pools are finished<commit_after>/*
  Copyright (c) DataStax, Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

#include "connection_pool_manager.hpp"

#include "config.hpp"
#include "memory.hpp"
#include "scoped_lock.hpp"
#include "utils.hpp"

namespace cass {

class NopConnectionPoolManagerListener : public ConnectionPoolManagerListener {
public:
  virtual void on_pool_up(const Address& address) { }

  virtual void on_pool_down(const Address& address) { }

  virtual void on_pool_critical_error(const Address& address,
                                 Connector::ConnectionError code,
                                 const String& message) { }

  virtual void on_close(ConnectionPoolManager* manager) { }
};

static NopConnectionPoolManagerListener nop_connection_pool_manager_listener__;

ConnectionPoolManagerSettings::ConnectionPoolManagerSettings()
  : num_connections_per_host(CASS_DEFAULT_NUM_CONNECTIONS_PER_HOST)
  , reconnect_wait_time_ms(CASS_DEFAULT_RECONNECT_WAIT_TIME_MS) { }

ConnectionPoolManagerSettings::ConnectionPoolManagerSettings(const Config& config)
  : connection_settings(config)
  , num_connections_per_host(config.core_connections_per_host())
  , reconnect_wait_time_ms(config.reconnect_wait_time_ms()) { }

ConnectionPoolManager::ConnectionPoolManager(uv_loop_t* loop,
                                             int protocol_version,
                                             const String& keyspace,
                                             ConnectionPoolManagerListener* listener,
                                             Metrics* metrics,
                                             const ConnectionPoolManagerSettings& settings)
  : loop_(loop)
  , protocol_version_(protocol_version)
  , settings_(settings)
  , close_state_(CLOSE_STATE_OPEN)
  , keyspace_(keyspace)
  , metrics_(metrics)
#ifdef CASS_INTERNAL_DIAGNOSTICS
  , flush_bytes_("flushed")
#endif
{
  inc_ref(); // Reference for the lifetime of the connection pools
  uv_mutex_init(&keyspace_mutex_);
  set_pointer_keys(to_flush_);
  set_listener(listener);
}

ConnectionPoolManager::~ConnectionPoolManager() {
  uv_mutex_destroy(&keyspace_mutex_);
}

PooledConnection::Ptr ConnectionPoolManager::find_least_busy(const Address& address) const {
  ConnectionPool::Map::const_iterator it = pools_.find(address);
  if (it == pools_.end()) {
    return PooledConnection::Ptr();
  }
  return it->second->find_least_busy();
}

void ConnectionPoolManager::flush() {
  for (DenseHashSet<ConnectionPool*>::const_iterator it = to_flush_.begin(),
       end = to_flush_.end(); it != end; ++it) {
    (*it)->flush();
  }
  to_flush_.clear();

}

AddressVec ConnectionPoolManager::available() const {
  AddressVec result;
  result.reserve(pools_.size());
  for (ConnectionPool::Map::const_iterator it = pools_.begin(),
       end = pools_.end(); it != end; ++it) {
    result.push_back(it->first);
  }
  return result;
}

void ConnectionPoolManager::add(const Address& address) {
  ConnectionPool::Map::iterator it = pools_.find(address);
  if (it != pools_.end()) return;

  for (ConnectionPoolConnector::Vec::iterator it = pending_pools_.begin(),
       end = pending_pools_.end(); it != end; ++it) {
    if ((*it)->address() == address) return;
  }

  ConnectionPoolConnector::Ptr connector(
        Memory::allocate<ConnectionPoolConnector>(this,
                                                  address,
                                                  bind_callback(&ConnectionPoolManager::on_connect, this)));
  pending_pools_.push_back(connector);
  connector->connect();
}

void ConnectionPoolManager::remove(const Address& address) {
  ConnectionPool::Map::iterator it = pools_.find(address);
  if (it == pools_.end()) return;
  // The connection pool will remove itself from the manager when all of its
  // connections are closed.
  it->second->close();
}

void ConnectionPoolManager::close() {
  if (close_state_ == CLOSE_STATE_OPEN) {
    close_state_ = CLOSE_STATE_CLOSING;
    if (maybe_closed()) {
      return;
    }

    // Make copies of pool/connector data structures to prevent iterator
    // invalidation.

    ConnectionPool::Map pools(pools_);
    for (ConnectionPool::Map::iterator it = pools.begin(),
         end = pools.end(); it != end; ++it) {
      it->second->close();
    }

    ConnectionPoolConnector::Vec pending_pools(pending_pools_);
    for (ConnectionPoolConnector::Vec::iterator it = pending_pools.begin(),
         end = pending_pools.end(); it != end; ++it) {
      (*it)->cancel();
    }
  }
}

void ConnectionPoolManager::set_listener(ConnectionPoolManagerListener* listener) {
  listener_ = listener ? listener : &nop_connection_pool_manager_listener__;
}

String ConnectionPoolManager::keyspace() const {
  ScopedMutex l(&keyspace_mutex_);
  return keyspace_;
}

void ConnectionPoolManager::set_keyspace(const String& keyspace) {
  ScopedMutex l(&keyspace_mutex_);
  keyspace_ = keyspace;
}

void ConnectionPoolManager::add_pool(const ConnectionPool::Ptr& pool, Protected) {
  internal_add_pool(pool);
}

void ConnectionPoolManager::notify_closed(ConnectionPool* pool, bool should_notify_down, Protected) {
  pools_.erase(pool->address());
  to_flush_.erase(pool);
  if (should_notify_down) {
    listener_->on_pool_down(pool->address());
  }
  maybe_closed();
}

void ConnectionPoolManager::notify_up(ConnectionPool* pool, Protected) {
  listener_->on_pool_up(pool->address());
}

void ConnectionPoolManager::notify_down(ConnectionPool* pool, Protected) {
  listener_->on_pool_down(pool->address());
}

void ConnectionPoolManager::notify_critical_error(ConnectionPool* pool,
                                                  Connector::ConnectionError code,
                                                  const String& message,
                                                  Protected) {
  listener_->on_pool_critical_error(pool->address(), code, message);
}

void ConnectionPoolManager::requires_flush(ConnectionPool* pool, ConnectionPoolManager::Protected) {
  to_flush_.insert(pool);
}

void ConnectionPoolManager::internal_add_pool(const ConnectionPool::Ptr& pool) {
  LOG_DEBUG("Adding pool for host %s", pool->address().to_string().c_str());
  pools_[pool->address()] = pool;
}

// This must be the last call in a function because it can potentially
// deallocate the manager.
bool ConnectionPoolManager::maybe_closed() {
  // Close the manager once all current and pending pools are terminated.
  if (close_state_ == CLOSE_STATE_CLOSING && pools_.empty() && pending_pools_.empty()) {
    close_state_ = CLOSE_STATE_CLOSED;
    listener_->on_close(this);
    dec_ref();
    return true;
  }
  return false;
}

void ConnectionPoolManager::on_connect(ConnectionPoolConnector* pool_connector) {
  pending_pools_.erase(std::remove(pending_pools_.begin(), pending_pools_.end(), pool_connector),
                       pending_pools_.end());

  if (close_state_ != CLOSE_STATE_OPEN) {
    maybe_closed();
    return;
  }

  if (pool_connector->is_ok()) {
    internal_add_pool(pool_connector->release_pool());
  } else {
    listener_->on_pool_critical_error(pool_connector->address(),
                                      pool_connector->error_code(),
                                      pool_connector->error_message());
  }
}

} // namespace cass
<|endoftext|>