<commit_before>/** @file
    @brief Implementation

    @date 2015

    @author
    Sensics, Inc.
    <http://sensics.com/osvr>
*/

// Copyright 2015 Sensics, 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.

// Internal Includes
#include "ImageSources/ImageSourceFactories.h"
#include "ImageSources/ImageSource.h"

// Library/third-party includes
#include <opencv2/highgui/highgui.hpp>

// Standard includes
#include <memory>
#include <iostream>
#include <chrono>
#include <sstream>

/// @brief OpenCV's simple highgui module refers to windows by their name, so we
/// make this global for a simpler demo.
static const std::string windowNameAndInstructions(
    "OSVR tracking camera preview | q or esc to quit");

static const auto FPS_MEASUREMENT_PERIOD = std::chrono::seconds(3);
class FrameCounter {
  public:
    FrameCounter() { reset(); }
    void gotFrame() {
        ++m_frames;
        auto now = clock::now();
        if (now >= m_end) {
            auto duration =
                std::chrono::duration_cast<std::chrono::duration<double>>(
                    now - m_begin);
            std::cout << m_frames / duration.count() << " FPS read from camera"
                      << std::endl;
            reset();
        }
    }

    void reset() {
        m_begin = clock::now();
        m_end = m_begin + FPS_MEASUREMENT_PERIOD;
        m_frames = 0;
    }

  private:
    using clock = std::chrono::system_clock;
    using time_point = std::chrono::time_point<clock>;
    time_point m_begin;
    time_point m_end;
    std::size_t m_frames = 0;
};

int main(int argc, char *argv[]) {

#ifdef _WIN32
    auto cam = osvr::vbtracker::openHDKCameraDirectShow();
#else
    std::cerr << "Warning: Just using OpenCV to open Camera #0, which may not "
                 "be the tracker camera."
              << std::endl;
    auto cam = osvr::vbtracker::openOpenCVCamera(0);
#endif
    if (!cam || !cam->ok()) {
        std::cerr << "Couldn't find, open, or read from the OSVR HDK tracking "
                     "camera.\n"
                  << "Press enter to exit." << std::endl;
        std::cin.ignore();
        return -1;
    }
    auto FRAME_DISPLAY_STRIDE = 3u;
    if (argc > 1) {
        std::stringstream ss;
        ss << argv[1];
        if (ss >> FRAME_DISPLAY_STRIDE) {
            std::cout << "Custom display stride passed: "
                      << FRAME_DISPLAY_STRIDE << std::endl;
        } else {
            std::cout << "Could not parse first command-line argument as a "
                         "display stride : '"
                      << argv[1] << "' (will use default)" << std::endl;
        }
    }

    cam->grab();

    std::cout << "Will display 1 out of every " << FRAME_DISPLAY_STRIDE
              << " frames captured." << std::endl;
    std::cout << "\nPress q or esc to quit, c to capture a frame to file.\n"
              << std::endl;

    auto frame = cv::Mat{};
    auto grayFrame = cv::Mat{};

    auto savedFrame = false;
    static const auto FILENAME = "capture.png";
    static const auto FILENAME_STEM = "image";
    static const auto EXTENSION = ".png";
    auto captures = std::size_t{0};
    FrameCounter counter;

    cv::namedWindow(windowNameAndInstructions);
    auto frameCount = std::size_t{0};
    do {
        cam->retrieve(frame, grayFrame);
        counter.gotFrame();
        ++frameCount;
        if (frameCount % FRAME_DISPLAY_STRIDE == 0) {
            frameCount = 0;
            cv::imshow(windowNameAndInstructions, frame);
            if (!savedFrame) {
                savedFrame = true;
                cv::imwrite(FILENAME, frame);
                std::cout << "Wrote a captured frame to " << FILENAME
                          << std::endl;
            }
            char key = static_cast<char>(cv::waitKey(1)); // wait 1 ms for a key
            if ('q' == key || 'Q' == key || 27 /*esc*/ == key) {
                break;
            } else if ('c' == key) {
                // capture
                std::ostringstream os;
                os << FILENAME_STEM << captures << EXTENSION;
                cv::imwrite(os.str(), frame);
                std::cout << "Captured frame to " << os.str() << std::endl;
                captures++;
            }
        }
    } while (cam->grab());
    return 0;
}
<commit_msg>Add video recording support to view tracking camera for debugging.<commit_after>/** @file
    @brief Implementation

    @date 2015

    @author
    Sensics, Inc.
    <http://sensics.com/osvr>
*/

// Copyright 2015 Sensics, 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.

// Internal Includes
#include "ImageSources/ImageSource.h"
#include "ImageSources/ImageSourceFactories.h"

// Library/third-party includes
#include <opencv2/highgui/highgui.hpp>

// Standard includes
#include <chrono>
#include <iostream>
#include <memory>
#include <sstream>

#undef OSVR_ENABLE_RECORDING

/// @brief OpenCV's simple highgui module refers to windows by their name, so we
/// make this global for a simpler demo.
static const std::string windowNameAndInstructions(
    "OSVR tracking camera preview | q or esc to quit");

static const auto VIDEO_FILENAME = "capture.avi";

static const auto FPS_MEASUREMENT_PERIOD = std::chrono::seconds(3);
class FrameCounter {
  public:
    FrameCounter() { reset(); }
    void gotFrame() {
        ++m_frames;
        auto now = clock::now();
        if (now >= m_end) {
            auto duration =
                std::chrono::duration_cast<std::chrono::duration<double>>(
                    now - m_begin);
            std::cout << m_frames / duration.count() << " FPS read from camera"
                      << std::endl;
            reset();
        }
    }

    void reset() {
        m_begin = clock::now();
        m_end = m_begin + FPS_MEASUREMENT_PERIOD;
        m_frames = 0;
    }

  private:
    using clock = std::chrono::system_clock;
    using time_point = std::chrono::time_point<clock>;
    time_point m_begin;
    time_point m_end;
    std::size_t m_frames = 0;
};

int main(int argc, char *argv[]) {

#ifdef _WIN32
    auto cam = osvr::vbtracker::openHDKCameraDirectShow();
#else
    std::cerr << "Warning: Just using OpenCV to open Camera #0, which may not "
                 "be the tracker camera."
              << std::endl;
    auto cam = osvr::vbtracker::openOpenCVCamera(0);
#endif
    if (!cam || !cam->ok()) {
        std::cerr << "Couldn't find, open, or read from the OSVR HDK tracking "
                     "camera.\n"
                  << "Press enter to exit." << std::endl;
        std::cin.ignore();
        return -1;
    }
    auto FRAME_DISPLAY_STRIDE = 3u;
    if (argc > 1) {
        std::stringstream ss;
        ss << argv[1];
        if (ss >> FRAME_DISPLAY_STRIDE) {
            std::cout << "Custom display stride passed: "
                      << FRAME_DISPLAY_STRIDE << std::endl;
        } else {
            std::cout << "Could not parse first command-line argument as a "
                         "display stride : '"
                      << argv[1] << "' (will use default)" << std::endl;
        }
    }

    cam->grab();

    std::cout << "Will display 1 out of every " << FRAME_DISPLAY_STRIDE
              << " frames captured." << std::endl;
    std::cout << "\nPress q or esc to quit, c to capture a frame to file.\n"
              << std::endl;

    auto frame = cv::Mat{};
    auto grayFrame = cv::Mat{};

    auto savedFrame = false;
    static const auto FILENAME = "capture.png";
    static const auto FILENAME_STEM = "image";
    static const auto EXTENSION = ".png";
    auto captures = std::size_t{0};
    FrameCounter counter;

#ifdef OSVR_ENABLE_RECORDING
    std::cout << "\nThis build is also video capture enabled: continuously "
                 "recording to "
              << VIDEO_FILENAME << std::endl;
    cv::VideoWriter outputVideo{"capture.avi",
                                CV_FOURCC_MACRO('M', 'J', 'P', 'G'), 100,
                                cv::Size(640, 480), true};
    if (!outputVideo.isOpened()) {
        std::cerr << "Could not open the output video for writing!"
                  << std::endl;
        return -1;
    }
#endif

    cv::namedWindow(windowNameAndInstructions);
    auto frameCount = std::size_t{0};
    do {
        cam->retrieve(frame, grayFrame);

#ifdef OSVR_ENABLE_RECORDING
        outputVideo.write(frame);
#endif

        counter.gotFrame();
        ++frameCount;
        if (frameCount % FRAME_DISPLAY_STRIDE == 0) {
            frameCount = 0;
            cv::imshow(windowNameAndInstructions, frame);
            if (!savedFrame) {
                savedFrame = true;
                cv::imwrite(FILENAME, frame);
                std::cout << "Wrote a captured frame to " << FILENAME
                          << std::endl;
            }
            char key = static_cast<char>(cv::waitKey(1)); // wait 1 ms for a key
            if ('q' == key || 'Q' == key || 27 /*esc*/ == key) {
                break;
            } else if ('c' == key) {
                // capture
                std::ostringstream os;
                os << FILENAME_STEM << captures << EXTENSION;
                cv::imwrite(os.str(), frame);
                std::cout << "Captured frame to " << os.str() << std::endl;
                captures++;
            }
        }
    } while (cam->grab());
    return 0;
}
<|endoftext|>


<commit_before>/**************************************************************************
**
** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
**
** Contact: BlackBerry (qt@blackberry.com)
** Contact: KDAB (info@kdab.com)
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "qnxdeviceprocesssignaloperation.h"

using namespace Qnx;
using namespace Qnx::Internal;

QnxDeviceProcessSignalOperation::QnxDeviceProcessSignalOperation(
        const QSsh::SshConnectionParameters sshParameters)
    : RemoteLinux::RemoteLinuxSignalOperation(sshParameters)
{
}

static QString signalProcessByNameBlackBerryCommandLine(const QString &filePath, int sig)
{
    QString executable = filePath;
    return QString::fromLatin1("for PID in $(pidin -F \"%a %A\" | grep \"%1\" | awk '/%1/ {print $1}'); "
        "do "
            "kill -%2 $PID; "
        "done").arg(executable.replace(QLatin1String("/"), QLatin1String("\\/"))).arg(sig);
}

QString QnxDeviceProcessSignalOperation::killProcessByNameCommandLine(
        const QString &filePath) const
{
    return QString::fromLatin1("%1; %2").arg(signalProcessByNameBlackBerryCommandLine(filePath, 15),
                                           signalProcessByNameBlackBerryCommandLine(filePath, 9));
}

QString QnxDeviceProcessSignalOperation::interruptProcessByNameCommandLine(
        const QString &filePath) const
{
    return signalProcessByNameBlackBerryCommandLine(filePath, 2);
}

BlackBerryDeviceProcessSignalOperation::BlackBerryDeviceProcessSignalOperation(
        const QSsh::SshConnectionParameters sshParameters)
    : RemoteLinux::RemoteLinuxSignalOperation(sshParameters)
{
}

static QString signalProcessByNameQnxCommandLine(const QString &filePath, int sig)
{
    QString executable = filePath;
    return QString::fromLatin1("for PID in $(ps -f -o pid,comm | grep %1 | awk '/%1/ {print $1}'); "
        "do "
            "kill -%2 $PID; "
        "done").arg(executable.replace(QLatin1String("/"), QLatin1String("\\/"))).arg(sig);
}

QString BlackBerryDeviceProcessSignalOperation::killProcessByNameCommandLine(const QString &filePath) const
{
    return QString::fromLatin1("%1; %2").arg(signalProcessByNameQnxCommandLine(filePath, 15),
                                           signalProcessByNameQnxCommandLine(filePath, 9));
}

QString BlackBerryDeviceProcessSignalOperation::interruptProcessByNameCommandLine(const QString &filePath) const
{
    return signalProcessByNameQnxCommandLine(filePath, 2);
}
<commit_msg>QNX: Fixed killing processes on QNX and BlackBerry<commit_after>/**************************************************************************
**
** Copyright (C) 2013 BlackBerry Limited. All rights reserved.
**
** Contact: BlackBerry (qt@blackberry.com)
** Contact: KDAB (info@kdab.com)
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "qnxdeviceprocesssignaloperation.h"

using namespace Qnx;
using namespace Qnx::Internal;

QnxDeviceProcessSignalOperation::QnxDeviceProcessSignalOperation(
        const QSsh::SshConnectionParameters sshParameters)
    : RemoteLinux::RemoteLinuxSignalOperation(sshParameters)
{
}

static QString signalProcessByNameQnxCommandLine(const QString &filePath, int sig)
{
    QString executable = filePath;
    return QString::fromLatin1("for PID in $(ps -f -o pid,comm | grep %1 | awk '/%1/ {print $1}'); "
        "do "
            "kill -%2 $PID; "
        "done").arg(executable.replace(QLatin1String("/"), QLatin1String("\\/"))).arg(sig);
}

QString QnxDeviceProcessSignalOperation::killProcessByNameCommandLine(
        const QString &filePath) const
{
    return QString::fromLatin1("%1; %2").arg(signalProcessByNameQnxCommandLine(filePath, 15),
                                           signalProcessByNameQnxCommandLine(filePath, 9));
}

QString QnxDeviceProcessSignalOperation::interruptProcessByNameCommandLine(
        const QString &filePath) const
{
    return signalProcessByNameQnxCommandLine(filePath, 2);
}

BlackBerryDeviceProcessSignalOperation::BlackBerryDeviceProcessSignalOperation(
        const QSsh::SshConnectionParameters sshParameters)
    : RemoteLinux::RemoteLinuxSignalOperation(sshParameters)
{
}

static QString signalProcessByNameBlackBerryCommandLine(const QString &filePath, int sig)
{
    QString executable = filePath;
    return QString::fromLatin1("for PID in $(pidin -F \"%a %A\" | grep \"%1\" | awk '/%1/ {print $1}'); "
        "do "
            "kill -%2 $PID; "
        "done").arg(executable.replace(QLatin1String("/"), QLatin1String("\\/"))).arg(sig);
}

QString BlackBerryDeviceProcessSignalOperation::killProcessByNameCommandLine(const QString &filePath) const
{
    return QString::fromLatin1("%1; %2").arg(signalProcessByNameBlackBerryCommandLine(filePath, 15),
                                                             signalProcessByNameBlackBerryCommandLine(filePath, 9));
}

QString BlackBerryDeviceProcessSignalOperation::interruptProcessByNameCommandLine(const QString &filePath) const
{
    return signalProcessByNameBlackBerryCommandLine(filePath, 2);
}
<|endoftext|>


<commit_before>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2010      Dennis Nienhüser <earthwings@gentoo.org>
//

#include "OsmNominatimRunner.h"

#include "MarbleAbstractRunner.h"
#include "MarbleDebug.h"
#include "MarbleLocale.h"
#include "GeoDataDocument.h"
#include "GeoDataPlacemark.h"
#include "GeoDataExtendedData.h"
#include "TinyWebBrowser.h"

#include <QtCore/QString>
#include <QtCore/QVector>
#include <QtCore/QUrl>
#include <QtCore/QTimer>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include <QtXml/QDomDocument>

namespace Marble
{

OsmNominatimRunner::OsmNominatimRunner( QObject *parent ) :
    MarbleAbstractRunner( parent ), m_manager( new QNetworkAccessManager (this ) )
{
    connect(m_manager, SIGNAL(finished(QNetworkReply*)),
            this, SLOT(handleResult(QNetworkReply*)));
}

OsmNominatimRunner::~OsmNominatimRunner()
{
    // nothing to do
}

GeoDataFeature::GeoDataVisualCategory OsmNominatimRunner::category() const
{
    return GeoDataFeature::OsmSite;
}

void OsmNominatimRunner::returnNoResults()
{
    emit searchFinished( QVector<GeoDataPlacemark*>() );
}

void OsmNominatimRunner::returnNoReverseGeocodingResult()
{
    emit reverseGeocodingFinished( m_coordinates, GeoDataPlacemark() );
}

void OsmNominatimRunner::search( const QString &searchTerm )
{
    QString base = "http://nominatim.openstreetmap.org/search?q=%1&format=xml";
    // @todo: Alternative URI with addressdetails=1 could be used for shorther placemark name
    QString query = "q=%1&format=xml&addressdetails=0&accept-language=%2";
    QString url = QString(base + query).arg(searchTerm).arg(MarbleLocale::languageCode());

    m_searchRequest.setUrl(QUrl(url));
    m_searchRequest.setRawHeader("User-Agent", TinyWebBrowser::userAgent("Browser", "OsmNominatimRunner") );

    // @todo FIXME Must currently be done in the main thread, see bug 257376
    QTimer::singleShot( 0, this, SLOT( startSearch() ) );
}

void OsmNominatimRunner::reverseGeocoding( const GeoDataCoordinates &coordinates )
{
    m_coordinates = coordinates;
    QString base = "http://nominatim.openstreetmap.org/reverse?format=xml&addressdetails=1";
    // @todo: Alternative URI with addressdetails=1 could be used for shorther placemark name
    QString query = "&lon=%1&lat=%2&accept-language=%3";
    double lon = coordinates.longitude( GeoDataCoordinates::Degree );
    double lat = coordinates.latitude( GeoDataCoordinates::Degree );
    QString url = QString( base + query ).arg( lon ).arg( lat ).arg( MarbleLocale::languageCode() );

    m_reverseGeocodingRequest.setUrl(QUrl(url));
    m_reverseGeocodingRequest.setRawHeader("User-Agent", TinyWebBrowser::userAgent("Browser", "OsmNominatimRunner") );

    // @todo FIXME Must currently be done in the main thread, see bug 257376
    QTimer::singleShot( 0, this, SLOT( startReverseGeocoding() ) );
}

void OsmNominatimRunner::startSearch()
{
    QNetworkReply *reply = m_manager->get(m_searchRequest);
    connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
            this, SLOT(returnNoResults()));
}

void OsmNominatimRunner::startReverseGeocoding()
{
    QNetworkReply *reply = m_manager->get( m_reverseGeocodingRequest );
    connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
            this, SLOT(returnNoReverseGeocodingResult()));
}

void OsmNominatimRunner::handleResult( QNetworkReply* reply )
{
    bool const isSearch = reply->url().path().endsWith( "search" );
    if ( isSearch ) {
        handleSearchResult( reply );
    } else {
        handleReverseGeocodingResult( reply );
    }
}

void OsmNominatimRunner::handleSearchResult( QNetworkReply* reply )
{
    QDomDocument xml;
    if (!xml.setContent(reply->readAll())) {
        qWarning() << "Cannot parse osm nominatim result";
        returnNoResults();
        return;
    }

    QVector<GeoDataPlacemark*> placemarks;
    QDomElement root = xml.documentElement();
    QDomNodeList places = root.elementsByTagName("place");
    for (int i=0; i<places.size(); ++i) {
        QDomNamedNodeMap attributes = places.at(i).attributes();
        QString lon = attributes.namedItem("lon").nodeValue();
        QString lat = attributes.namedItem("lat").nodeValue();
        QString desc = attributes.namedItem("display_name").nodeValue();

        if (!lon.isEmpty() && !lat.isEmpty() && !desc.isEmpty()) {
            GeoDataPlacemark* placemark = new GeoDataPlacemark;
            placemark->setName(desc);
            placemark->setDescription(desc);
            placemark->setCoordinate(lon.toDouble() * DEG2RAD, lat.toDouble() * DEG2RAD);
            placemark->setVisualCategory( category() );
            placemarks << placemark;
        }
    }

    emit searchFinished( placemarks );
}

void OsmNominatimRunner::handleReverseGeocodingResult( QNetworkReply* reply )
{
    if ( !reply->bytesAvailable() ) {
        return;
    }

    QDomDocument xml;
    if ( !xml.setContent( reply->readAll() ) ) {
        mDebug() << "Cannot parse osm nominatim result " << xml.toString();
        return;
    }

    QDomElement root = xml.documentElement();
    QDomNodeList places = root.elementsByTagName( "result" );
    if ( places.size() == 1 ) {
        QString address = places.item( 0 ).toElement().text();
        GeoDataPlacemark placemark;
        placemark.setAddress( address );
        placemark.setCoordinate( GeoDataPoint( m_coordinates ) );

        QDomNodeList details = root.elementsByTagName( "addressparts" );
        if ( details.size() == 1 ) {
            GeoDataExtendedData extendedData;
            addData( details, "road", &extendedData );
            addData( details, "house_number", &extendedData );
            addData( details, "village", &extendedData );
            addData( details, "city", &extendedData );
            addData( details, "county", &extendedData );
            addData( details, "state", &extendedData );
            addData( details, "postcode", &extendedData );
            addData( details, "country", &extendedData );
            placemark.setExtendedData( extendedData );
        }

        emit reverseGeocodingFinished( m_coordinates, placemark );
    }
}

void OsmNominatimRunner::addData( const QDomNodeList &node, const QString &key, GeoDataExtendedData *extendedData )
{
    QDomNodeList child = node.item( 0 ).toElement().elementsByTagName( key );
    if ( child.size() > 0 ) {
        QString text = child.item( 0 ).toElement().text();
        extendedData->addValue( GeoDataData( key, text ) );
    }
}

} // namespace Marble

#include "OsmNominatimRunner.moc"
<commit_msg>Strip garbage from the uri.<commit_after>//
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2010      Dennis Nienhüser <earthwings@gentoo.org>
//

#include "OsmNominatimRunner.h"

#include "MarbleAbstractRunner.h"
#include "MarbleDebug.h"
#include "MarbleLocale.h"
#include "GeoDataDocument.h"
#include "GeoDataPlacemark.h"
#include "GeoDataExtendedData.h"
#include "TinyWebBrowser.h"

#include <QtCore/QString>
#include <QtCore/QVector>
#include <QtCore/QUrl>
#include <QtCore/QTimer>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include <QtXml/QDomDocument>

namespace Marble
{

OsmNominatimRunner::OsmNominatimRunner( QObject *parent ) :
    MarbleAbstractRunner( parent ), m_manager( new QNetworkAccessManager (this ) )
{
    connect(m_manager, SIGNAL(finished(QNetworkReply*)),
            this, SLOT(handleResult(QNetworkReply*)));
}

OsmNominatimRunner::~OsmNominatimRunner()
{
    // nothing to do
}

GeoDataFeature::GeoDataVisualCategory OsmNominatimRunner::category() const
{
    return GeoDataFeature::OsmSite;
}

void OsmNominatimRunner::returnNoResults()
{
    emit searchFinished( QVector<GeoDataPlacemark*>() );
}

void OsmNominatimRunner::returnNoReverseGeocodingResult()
{
    emit reverseGeocodingFinished( m_coordinates, GeoDataPlacemark() );
}

void OsmNominatimRunner::search( const QString &searchTerm )
{
    QString base = "http://nominatim.openstreetmap.org/search?";
    // @todo: Alternative URI with addressdetails=1 could be used for shorther placemark name
    QString query = "q=%1&format=xml&addressdetails=0&accept-language=%2";
    QString url = QString(base + query).arg(searchTerm).arg(MarbleLocale::languageCode());

    m_searchRequest.setUrl(QUrl(url));
    m_searchRequest.setRawHeader("User-Agent", TinyWebBrowser::userAgent("Browser", "OsmNominatimRunner") );

    // @todo FIXME Must currently be done in the main thread, see bug 257376
    QTimer::singleShot( 0, this, SLOT( startSearch() ) );
}

void OsmNominatimRunner::reverseGeocoding( const GeoDataCoordinates &coordinates )
{
    m_coordinates = coordinates;
    QString base = "http://nominatim.openstreetmap.org/reverse?format=xml&addressdetails=1";
    // @todo: Alternative URI with addressdetails=1 could be used for shorther placemark name
    QString query = "&lon=%1&lat=%2&accept-language=%3";
    double lon = coordinates.longitude( GeoDataCoordinates::Degree );
    double lat = coordinates.latitude( GeoDataCoordinates::Degree );
    QString url = QString( base + query ).arg( lon ).arg( lat ).arg( MarbleLocale::languageCode() );

    m_reverseGeocodingRequest.setUrl(QUrl(url));
    m_reverseGeocodingRequest.setRawHeader("User-Agent", TinyWebBrowser::userAgent("Browser", "OsmNominatimRunner") );

    // @todo FIXME Must currently be done in the main thread, see bug 257376
    QTimer::singleShot( 0, this, SLOT( startReverseGeocoding() ) );
}

void OsmNominatimRunner::startSearch()
{
    QNetworkReply *reply = m_manager->get(m_searchRequest);
    connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
            this, SLOT(returnNoResults()));
}

void OsmNominatimRunner::startReverseGeocoding()
{
    QNetworkReply *reply = m_manager->get( m_reverseGeocodingRequest );
    connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
            this, SLOT(returnNoReverseGeocodingResult()));
}

void OsmNominatimRunner::handleResult( QNetworkReply* reply )
{
    bool const isSearch = reply->url().path().endsWith( "search" );
    if ( isSearch ) {
        handleSearchResult( reply );
    } else {
        handleReverseGeocodingResult( reply );
    }
}

void OsmNominatimRunner::handleSearchResult( QNetworkReply* reply )
{
    QDomDocument xml;
    if (!xml.setContent(reply->readAll())) {
        qWarning() << "Cannot parse osm nominatim result";
        returnNoResults();
        return;
    }

    QVector<GeoDataPlacemark*> placemarks;
    QDomElement root = xml.documentElement();
    QDomNodeList places = root.elementsByTagName("place");
    for (int i=0; i<places.size(); ++i) {
        QDomNamedNodeMap attributes = places.at(i).attributes();
        QString lon = attributes.namedItem("lon").nodeValue();
        QString lat = attributes.namedItem("lat").nodeValue();
        QString desc = attributes.namedItem("display_name").nodeValue();

        if (!lon.isEmpty() && !lat.isEmpty() && !desc.isEmpty()) {
            GeoDataPlacemark* placemark = new GeoDataPlacemark;
            placemark->setName(desc);
            placemark->setDescription(desc);
            placemark->setCoordinate(lon.toDouble() * DEG2RAD, lat.toDouble() * DEG2RAD);
            placemark->setVisualCategory( category() );
            placemarks << placemark;
        }
    }

    emit searchFinished( placemarks );
}

void OsmNominatimRunner::handleReverseGeocodingResult( QNetworkReply* reply )
{
    if ( !reply->bytesAvailable() ) {
        return;
    }

    QDomDocument xml;
    if ( !xml.setContent( reply->readAll() ) ) {
        mDebug() << "Cannot parse osm nominatim result " << xml.toString();
        return;
    }

    QDomElement root = xml.documentElement();
    QDomNodeList places = root.elementsByTagName( "result" );
    if ( places.size() == 1 ) {
        QString address = places.item( 0 ).toElement().text();
        GeoDataPlacemark placemark;
        placemark.setAddress( address );
        placemark.setCoordinate( GeoDataPoint( m_coordinates ) );

        QDomNodeList details = root.elementsByTagName( "addressparts" );
        if ( details.size() == 1 ) {
            GeoDataExtendedData extendedData;
            addData( details, "road", &extendedData );
            addData( details, "house_number", &extendedData );
            addData( details, "village", &extendedData );
            addData( details, "city", &extendedData );
            addData( details, "county", &extendedData );
            addData( details, "state", &extendedData );
            addData( details, "postcode", &extendedData );
            addData( details, "country", &extendedData );
            placemark.setExtendedData( extendedData );
        }

        emit reverseGeocodingFinished( m_coordinates, placemark );
    }
}

void OsmNominatimRunner::addData( const QDomNodeList &node, const QString &key, GeoDataExtendedData *extendedData )
{
    QDomNodeList child = node.item( 0 ).toElement().elementsByTagName( key );
    if ( child.size() > 0 ) {
        QString text = child.item( 0 ).toElement().text();
        extendedData->addValue( GeoDataData( key, text ) );
    }
}

} // namespace Marble

#include "OsmNominatimRunner.moc"
<|endoftext|>


<commit_before>/*************************************************************************
 * Copyright (c) 2016 Fran�ois Trudel
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
*************************************************************************/
#include "projects/lit_particles/lit_particles_project.hh"
//C system files
//C++ system files
#include <memory>
//Other libraries' .h files
#include "utils/imgui/imgui_glfw.h"
//Your project's .h files
#include "projects/project_dictionary.hh"
#include "utils/timer.hh"
#include "utils/shader_module.hh"
#include "utils/shader_factory.hh"
#include "utils/texture_module.hh"
#include "utils/camera.hh"
#include "utils/imgui/imgui_log.h"
#include "utils/imgui/imgui_property_editor.h"
#include "utils/light_module.hh"
#include "utils/graphic_contexts/opengl_context.hh"
#include "core/particle_module.hh"

// Specific project particle blueprints
#include "projects/lit_particles/lit_particles_event_handler.hh"
#include "projects/lit_particles/lit_particles_blueprint.hh"
#include "projects/lit_particles/lit_particles_scene.hh"

namespace gem { namespace particle {
namespace lit_particles_project {
namespace {
// A pointer to interface, to enable flexibility over
// window management system or 3D API (GLFW/Windows
// & OpenGL/Direct3D)
std::shared_ptr<GraphicContext> graphic_context;
}

REGISTER_STD_PROJECT(lit_particles);

void Init() {
  // OpenGL setup
  graphic_context = std::make_shared<OpenGLContext>();
  graphic_context->Init();

  // ImGui initialization
  ImGui_ImplGlfw_InitForOpenGL(static_cast<GLFWwindow*>(graphic_context->GetWindowHandle()), true);
  ImGui::StyleColorsClassic();

  shader::module::Init();
  shader::factory::SetShadersFolderBasePath("src/projects/lit_particles/shaders/");
  texture::module::Init();

  // Camera initialization
  camera::Init();
  camera::LookAt(
    glm::vec3(0, 10, 10),   // Camera is at (4,4,4), in World Space
    glm::vec3(0.0f, 0.0f, -1.5f),   // and looks at the origin
    glm::vec3(0, 1, 0));  // Head is up (set to 0,-1,0 to look upside-down)
  camera::SetPerspectiveProjection(
    glm::radians(45.0f),
    4.0f, 3.0f, // TODO: This fits the hardcoded 640/480 in the opengl_context.cc file, change this accordingly to changes made in the other file
    0.1f, 100.0f);

  // Light module initialization
  light::module::Init();

  // Scene initialization
  scene::Init();
  scene::SetDebugOption(true);

  // Particle system initialization
  particle_module::Init();
  blueprint::lit_particles_system_builder::SetParticleSystemName("Amazing lit particles system");
  blueprint::lit_particles_system_builder::SetTexture("textures/welding_sparkle.png");
  blueprint::lit_particles_system_builder::SetParticleCount(5001u);
  blueprint::lit_particles_system_builder::Create();

  // Event handler initialization
  event_handler::Init(graphic_context);
}

void Run() {
  glfwSetWindowTitle(static_cast<GLFWwindow*>(
    graphic_context->GetWindowHandle()), "GemParticles");
  while (!graphic_context->PollWindowClosedEvent()) {
    const double dt = timer::Chrono::GetInstance().GetTimeElapsedInSeconds();
    ImGui_ImplGlfw_NewFrame();

    ImGui::Begin("Stats");
    ImGui::Text("Application average %.3f ms / frame(%.1f FPS)\n", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
    ImGui::Text("Total active particles = %d\n", particle_module::GetActiveParticlesCount());
    ImGui::End();

    scene::Render();
    particle_module::Update(dt);
    event_handler::Update(); // Has to be placed before before clearing depth buffer bit
    light::module::FlushDataToGPU();

    ImGuiPropertyEditor::GetInstance().Draw("Property editor");
    ImGuiLog::GetInstance().Draw("Debugging logs");
    ImGui::Render();

    graphic_context->Update();
    timer::Chrono::GetInstance().Update();
  }
}

void Terminate() {
  // App destruction
  particle_module::Terminate();
  light::module::Terminate();
  scene::Terminate();
  event_handler::Terminate();
  texture::module::Terminate();
  shader::module::Terminate();
  ImGui_ImplGlfw_Shutdown();
  graphic_context->Terminate();
}
} /* namespace lit particles_project */
} /* namespace particle */
} /* namespace gem */

<commit_msg>Fixed imgui for lit_particles ... either revert to previous and dont use conan imgui or fix shader compilation error spam at shutdown (NOTE:have to fix other projects as well like that)<commit_after>/*************************************************************************
 * Copyright (c) 2016 Fran�ois Trudel
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
*************************************************************************/
#include "projects/lit_particles/lit_particles_project.hh"
//C system files
//C++ system files
#include <memory>
//Other libraries' .h files
#include "utils/imgui/imgui_glfw.h"
#include "utils/imgui/imgui_impl_opengl3.h"
//Your project's .h files
#include "projects/project_dictionary.hh"
#include "utils/timer.hh"
#include "utils/shader_module.hh"
#include "utils/shader_factory.hh"
#include "utils/texture_module.hh"
#include "utils/camera.hh"
#include "utils/imgui/imgui_log.h"
#include "utils/imgui/imgui_property_editor.h"
#include "utils/light_module.hh"
#include "utils/graphic_contexts/opengl_context.hh"
#include "core/particle_module.hh"

// Specific project particle blueprints
#include "projects/lit_particles/lit_particles_event_handler.hh"
#include "projects/lit_particles/lit_particles_blueprint.hh"
#include "projects/lit_particles/lit_particles_scene.hh"

namespace gem { namespace particle {
namespace lit_particles_project {
namespace {
// A pointer to interface, to enable flexibility over
// window management system or 3D API (GLFW/Windows
// & OpenGL/Direct3D)
std::shared_ptr<GraphicContext> graphic_context;
}

REGISTER_STD_PROJECT(lit_particles);

void Init() {
  // OpenGL setup
  graphic_context = std::make_shared<OpenGLContext>();
  graphic_context->Init();

  // ImGui initialization
  ImGui::CreateContext();
  ImGuiIO& io = ImGui::GetIO(); (void)io;
  ImGui_ImplGlfw_InitForOpenGL(static_cast<GLFWwindow*>(graphic_context->GetWindowHandle()), true);
  ImGui_ImplOpenGL3_Init();
  ImGui::StyleColorsClassic();

  shader::module::Init();
  shader::factory::SetShadersFolderBasePath("src/projects/lit_particles/shaders/");
  texture::module::Init();

  // Camera initialization
  camera::Init();
  camera::LookAt(
    glm::vec3(0, 10, 10),   // Camera is at (4,4,4), in World Space
    glm::vec3(0.0f, 0.0f, -1.5f),   // and looks at the origin
    glm::vec3(0, 1, 0));  // Head is up (set to 0,-1,0 to look upside-down)
  camera::SetPerspectiveProjection(
    glm::radians(45.0f),
    4.0f, 3.0f, // TODO: This fits the hardcoded 640/480 in the opengl_context.cc file, change this accordingly to changes made in the other file
    0.1f, 100.0f);

  // Light module initialization
  light::module::Init();

  // Scene initialization
  scene::Init();
  scene::SetDebugOption(true);

  // Particle system initialization
  particle_module::Init();
  blueprint::lit_particles_system_builder::SetParticleSystemName("Amazing lit particles system");
  blueprint::lit_particles_system_builder::SetTexture("textures/welding_sparkle.png");
  blueprint::lit_particles_system_builder::SetParticleCount(5001u);
  blueprint::lit_particles_system_builder::Create();

  // Event handler initialization
  event_handler::Init(graphic_context);
}

void Run() {
  glfwSetWindowTitle(static_cast<GLFWwindow*>(
    graphic_context->GetWindowHandle()), "GemParticles");
  while (!graphic_context->PollWindowClosedEvent()) {
    const double dt = timer::Chrono::GetInstance().GetTimeElapsedInSeconds();

    // Start the Dear ImGui frame
    ImGui_ImplOpenGL3_NewFrame();
    ImGui_ImplGlfw_NewFrame();
    ImGui::NewFrame();

    ImGui::Begin("Stats");
    ImGui::Text("Application average %.3f ms / frame(%.1f FPS)\n", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
    ImGui::Text("Total active particles = %d\n", particle_module::GetActiveParticlesCount());
    ImGui::End();

    scene::Render();
    particle_module::Update(dt);
    event_handler::Update(); // Has to be placed before before clearing depth buffer bit
    light::module::FlushDataToGPU();

    ImGuiPropertyEditor::GetInstance().Draw("Property editor");
    ImGuiLog::GetInstance().Draw("Debugging logs");
    ImGui::Render();
    ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

    graphic_context->Update();
    timer::Chrono::GetInstance().Update();
  }
}

void Terminate() {
  // App destruction
  particle_module::Terminate();
  light::module::Terminate();
  scene::Terminate();
  event_handler::Terminate();
  texture::module::Terminate();
  shader::module::Terminate();
  ImGui_ImplOpenGL3_Shutdown();
  ImGui_ImplGlfw_Shutdown();
  ImGui::DestroyContext();
  graphic_context->Terminate();
}
} /* namespace lit particles_project */
} /* namespace particle */
} /* namespace gem */

<|endoftext|>


<commit_before>//#include "mvcc.h"
#include "txn.h"
#include "row.h"
#include "manager.h"
#include "row_mvcc.h"
#include "mem_alloc.h"

void Row_mvcc::init(row_t * row) {
	_row = row;
	uint64_t part_id = row->get_part_id();
	readreq_mvcc = NULL;
	prereq_mvcc = NULL;
	readhis = NULL;
	writehis = NULL;
	readhistail = NULL;
	writehistail = NULL;
	blatch = false;
	latch = (pthread_mutex_t *)
		mem_allocator.alloc(sizeof(pthread_mutex_t), part_id);
	pthread_mutex_init(latch, NULL);
	whis_len = 0;
	rhis_len = 0;
	rreq_len = 0;
	preq_len = 0;
}

row_t * Row_mvcc::clear_history(TsType type, ts_t ts) {
	MVHisEntry ** queue;
	MVHisEntry ** tail;
    switch (type) {
    case R_REQ : queue = &readhis; tail = &readhistail; break;
    case W_REQ : queue = &writehis; tail = &writehistail; break;
	default: assert(false);
    }
	MVHisEntry * his = *tail;
	MVHisEntry * prev = NULL;
	row_t * row = NULL;
	while (his && his->prev && his->prev->ts < ts) {
		prev = his->prev;
		assert(prev->ts >= his->ts);
		if (row != NULL) {
			row->free_row();
			mem_allocator.free(row, sizeof(row_t));
		}
		row = his->row;
		his->row = NULL;
		return_his_entry(his);
		his = prev;
		if (type == R_REQ) rhis_len --;
		else whis_len --;
	}
	*tail = his;
	if (*tail)
		(*tail)->next = NULL;
	if (his == NULL)
		*queue = NULL;
	return row;
}

MVReqEntry * Row_mvcc::get_req_entry() {
	uint64_t part_id = get_part_id(_row);
	return (MVReqEntry *) mem_allocator.alloc(sizeof(MVReqEntry), part_id);
}

void Row_mvcc::return_req_entry(MVReqEntry * entry) {
	mem_allocator.free(entry, sizeof(MVReqEntry));
}

MVHisEntry * Row_mvcc::get_his_entry() {
	uint64_t part_id = _row->get_part_id();
	return (MVHisEntry *) mem_allocator.alloc(sizeof(MVHisEntry), part_id);
}

void Row_mvcc::return_his_entry(MVHisEntry * entry) {
	if (entry->row != NULL) {
		entry->row->free_row();
		mem_allocator.free(entry->row, sizeof(row_t));
	}
	mem_allocator.free(entry, sizeof(MVHisEntry));
}

void Row_mvcc::buffer_req(TsType type, txn_man * txn)
{
	MVReqEntry * req_entry = get_req_entry();
	assert(req_entry != NULL);
	req_entry->txn = txn;
	req_entry->ts = txn->get_ts();
	if (type == R_REQ) {
		rreq_len ++;
		STACK_PUSH(readreq_mvcc, req_entry);
	} else if (type == P_REQ) {
		preq_len ++;
		STACK_PUSH(prereq_mvcc, req_entry);
	}
}

// for type == R_REQ
//	 debuffer all non-conflicting requests
// for type == P_REQ
//   debuffer the request with matching txn.
MVReqEntry * Row_mvcc::debuffer_req( TsType type, txn_man * txn) {
	MVReqEntry ** queue;
	MVReqEntry * return_queue = NULL;
	switch (type) {
	case R_REQ : queue = &readreq_mvcc; break;
	case P_REQ : queue = &prereq_mvcc; break;
	default: assert(false);
	}

	MVReqEntry * req = *queue;
	MVReqEntry * prev_req = NULL;
	if (txn != NULL) {
		assert(type == P_REQ);
		while (req != NULL && req->txn != txn) {
			prev_req = req;
			req = req->next;
		}
		assert(req != NULL);
		if (prev_req != NULL)
			prev_req->next = req->next;
		else {
			assert( req == *queue );
			*queue = req->next;
		}
		preq_len --;
		req->next = return_queue;
		return_queue = req;
	} else {
		assert(type == R_REQ);
		// should return all non-conflicting read requests
		// TODO The following code makes the assumption that each write op
		// must read the row first. i.e., there is no write-only operation.
		uint64_t min_pts = UINT64_MAX;
		//uint64_t min_pts = (1UL << 32);
		for (MVReqEntry * preq = prereq_mvcc; preq != NULL; preq = preq->next)
			if (preq->ts < min_pts)
				min_pts = preq->ts;
		while (req != NULL) {
			if (req->ts <= min_pts) {
				if (prev_req == NULL) {
					assert(req == *queue);
					*queue = (*queue)->next;
				} else
					prev_req->next = req->next;
				rreq_len --;
				req->next = return_queue;
				return_queue = req;
				req = (prev_req == NULL)? *queue : prev_req->next;
			} else {
				prev_req = req;
				req = req->next;
			}
		}
	}

	return return_queue;
}

void Row_mvcc::insert_history( ts_t ts, row_t * row)
{
	MVHisEntry * new_entry = get_his_entry();
	new_entry->ts = ts;
	new_entry->row = row;
	if (row != NULL)
		whis_len ++;
	else rhis_len ++;
	MVHisEntry ** queue = (row == NULL)?
		&(readhis) : &(writehis);
	MVHisEntry ** tail = (row == NULL)?
		&(readhistail) : &(writehistail);
	MVHisEntry * his = *queue;
	while (his != NULL && ts < his->ts) {
		his = his->next;
	}

	if (his) {
		LIST_INSERT_BEFORE(his, new_entry);
		if (his == *queue)
			*queue = new_entry;
	} else
		LIST_PUT_TAIL((*queue), (*tail), new_entry);
}

bool Row_mvcc::conflict(TsType type, ts_t ts) {
	// find the unique prewrite-read couple (prewrite before read)
	// if no such couple found, no conflict.
	// else
	// 	 if exists writehis between them, NO conflict!!!!
	// 	 else, CONFLICT!!!
	ts_t rts;
	ts_t pts;
	if (type == R_REQ) {
		rts = ts;
		pts = 0;
		MVReqEntry * req = prereq_mvcc;
		while (req != NULL) {
			if (req->ts < ts && req->ts > pts) {
				pts = req->ts;
			}
			req = req->next;
		}
		if (pts == 0) // no such couple exists
			return false;
	} else if (type == P_REQ) {
		rts = 0;
		pts = ts;
		MVHisEntry * his = readhis;
		while (his != NULL) {
			if (his->ts > ts) {
				rts = his->ts;
			} else
				break;
			his = his->next;
		}
		if (rts == 0) // no couple exists
			return false;
		assert(rts > pts);
	}
	MVHisEntry * whis = writehis;
    while (whis != NULL && whis->ts > pts) {
		if (whis->ts < rts)
			return false;
		whis = whis->next;
	}
	return true;
}

RC Row_mvcc::access(txn_man * txn, TsType type, row_t * row) {
	RC rc = RCOK;
	ts_t ts = txn->get_ts();

	if (g_central_man)
		glob_manager.lock_row(_row);
	else
		pthread_mutex_lock( latch );
  if (type == R_REQ) {
		// figure out if ts is in interval(prewrite(x))
		bool conf = conflict(type, ts);
		if ( conf && rreq_len < MAX_READ_REQ) {
			rc = WAIT;
			buffer_req(R_REQ, txn);
			txn->ts_ready = false;
		} else if (conf) {
			rc = Abort;
			printf("\nshould never happen. rreq_len=%ld", rreq_len);
		} else {
			// return results immediately.
			rc = RCOK;
			MVHisEntry * whis = writehis;
			while (whis != NULL && whis->ts > ts)
				whis = whis->next;
			row_t * ret = (whis == NULL)?
				_row : whis->row;
			txn->cur_row = ret;
			insert_history(ts, NULL);
			assert(strstr(_row->get_table_name(), ret->get_table_name()));
		}
	} else if (type == P_REQ) {
		if ( conflict(type, ts) ) {
			rc = Abort;
		} else if (preq_len < MAX_PRE_REQ){
			buffer_req(P_REQ, txn);
			rc = RCOK;
		} else  {
			rc = Abort;
		}
	} else if (type == W_REQ) {
		rc = RCOK;
		// the corresponding prewrite request is debuffered.
		insert_history(ts, row);
		MVReqEntry * req = debuffer_req(P_REQ, txn);
		assert(req != NULL);
		return_req_entry(req);
		update_buffer(txn);
	} else if (type == XP_REQ) {
		MVReqEntry * req = debuffer_req(P_REQ, txn);
		assert (req != NULL);
		return_req_entry(req);
		update_buffer(txn);
	} else
		assert(false);

	if (rc == RCOK) {
		if (whis_len > HIS_RECYCLE_LEN || rhis_len > HIS_RECYCLE_LEN) {
			ts_t t_th = glob_manager.get_min_ts(txn->get_thd_id());
			if (readhistail && readhistail->ts < t_th)
				clear_history(R_REQ, t_th);
			// TODO. Here is a tricky bug. The oldest transaction might be
			// reading an even older version whose timestamp < t_th.
			// But we cannot recycle that version because it is still being used.
			// So the HACK here is to make sure that the first version older than
			// t_th not be recycled.
			if (whis_len > 1 &&
				writehistail->prev->ts < t_th) {
				row_t * latest_row = clear_history(W_REQ, t_th);
				if (latest_row != NULL) {
					assert(_row != latest_row);
					_row->copy(latest_row);
				}
			}
		}
	}

	if (g_central_man)
		glob_manager.release_row(_row);
	else
		pthread_mutex_unlock( latch );

	return rc;
}

void Row_mvcc::update_buffer(txn_man * txn) {
	MVReqEntry * ready_read = debuffer_req(R_REQ, NULL);
	MVReqEntry * req = ready_read;
	MVReqEntry * tofree = NULL;

	while (req != NULL) {
		// find the version for the request
		MVHisEntry * whis = writehis;
		while (whis != NULL && whis->ts > req->ts)
			whis = whis->next;
		row_t * row = (whis == NULL)?
			_row : whis->row;
		req->txn->cur_row = row;
		insert_history(req->ts, NULL);
		assert(row->get_data() != NULL);
		assert(row->get_table() != NULL);
		assert(row->get_schema() == _row->get_schema());

    // TODO: add req->txn to work queue
		req->txn->ts_ready = true;
		tofree = req;
		req = req->next;
		// free ready_read
		return_req_entry(tofree);
	}
}
<commit_msg>Added support for MVCC<commit_after>//#include "mvcc.h"
#include "txn.h"
#include "row.h"
#include "manager.h"
#include "row_mvcc.h"
#include "mem_alloc.h"

void Row_mvcc::init(row_t * row) {
	_row = row;
	uint64_t part_id = row->get_part_id();
	readreq_mvcc = NULL;
	prereq_mvcc = NULL;
	readhis = NULL;
	writehis = NULL;
	readhistail = NULL;
	writehistail = NULL;
	blatch = false;
	latch = (pthread_mutex_t *)
		mem_allocator.alloc(sizeof(pthread_mutex_t), part_id);
	pthread_mutex_init(latch, NULL);
	whis_len = 0;
	rhis_len = 0;
	rreq_len = 0;
	preq_len = 0;
}

row_t * Row_mvcc::clear_history(TsType type, ts_t ts) {
	MVHisEntry ** queue;
	MVHisEntry ** tail;
    switch (type) {
    case R_REQ : queue = &readhis; tail = &readhistail; break;
    case W_REQ : queue = &writehis; tail = &writehistail; break;
	default: assert(false);
    }
	MVHisEntry * his = *tail;
	MVHisEntry * prev = NULL;
	row_t * row = NULL;
	while (his && his->prev && his->prev->ts < ts) {
		prev = his->prev;
		assert(prev->ts >= his->ts);
		if (row != NULL) {
			row->free_row();
			mem_allocator.free(row, sizeof(row_t));
		}
		row = his->row;
		his->row = NULL;
		return_his_entry(his);
		his = prev;
		if (type == R_REQ) rhis_len --;
		else whis_len --;
	}
	*tail = his;
	if (*tail)
		(*tail)->next = NULL;
	if (his == NULL)
		*queue = NULL;
	return row;
}

MVReqEntry * Row_mvcc::get_req_entry() {
	uint64_t part_id = get_part_id(_row);
	return (MVReqEntry *) mem_allocator.alloc(sizeof(MVReqEntry), part_id);
}

void Row_mvcc::return_req_entry(MVReqEntry * entry) {
	mem_allocator.free(entry, sizeof(MVReqEntry));
}

MVHisEntry * Row_mvcc::get_his_entry() {
	uint64_t part_id = _row->get_part_id();
	return (MVHisEntry *) mem_allocator.alloc(sizeof(MVHisEntry), part_id);
}

void Row_mvcc::return_his_entry(MVHisEntry * entry) {
	if (entry->row != NULL) {
		entry->row->free_row();
		mem_allocator.free(entry->row, sizeof(row_t));
	}
	mem_allocator.free(entry, sizeof(MVHisEntry));
}

void Row_mvcc::buffer_req(TsType type, txn_man * txn)
{
	MVReqEntry * req_entry = get_req_entry();
	assert(req_entry != NULL);
	req_entry->txn = txn;
	req_entry->ts = txn->get_ts();
	if (type == R_REQ) {
		rreq_len ++;
		STACK_PUSH(readreq_mvcc, req_entry);
	} else if (type == P_REQ) {
		preq_len ++;
		STACK_PUSH(prereq_mvcc, req_entry);
	}
}

// for type == R_REQ
//	 debuffer all non-conflicting requests
// for type == P_REQ
//   debuffer the request with matching txn.
MVReqEntry * Row_mvcc::debuffer_req( TsType type, txn_man * txn) {
	MVReqEntry ** queue;
	MVReqEntry * return_queue = NULL;
	switch (type) {
	case R_REQ : queue = &readreq_mvcc; break;
	case P_REQ : queue = &prereq_mvcc; break;
	default: assert(false);
	}

	MVReqEntry * req = *queue;
	MVReqEntry * prev_req = NULL;
	if (txn != NULL) {
		assert(type == P_REQ);
		while (req != NULL && req->txn != txn) {
			prev_req = req;
			req = req->next;
		}
		assert(req != NULL);
		if (prev_req != NULL)
			prev_req->next = req->next;
		else {
			assert( req == *queue );
			*queue = req->next;
		}
		preq_len --;
		req->next = return_queue;
		return_queue = req;
	} else {
		assert(type == R_REQ);
		// should return all non-conflicting read requests
		// TODO The following code makes the assumption that each write op
		// must read the row first. i.e., there is no write-only operation.
		uint64_t min_pts = UINT64_MAX;
		//uint64_t min_pts = (1UL << 32);
		for (MVReqEntry * preq = prereq_mvcc; preq != NULL; preq = preq->next)
			if (preq->ts < min_pts)
				min_pts = preq->ts;
		while (req != NULL) {
			if (req->ts <= min_pts) {
				if (prev_req == NULL) {
					assert(req == *queue);
					*queue = (*queue)->next;
				} else
					prev_req->next = req->next;
				rreq_len --;
				req->next = return_queue;
				return_queue = req;
				req = (prev_req == NULL)? *queue : prev_req->next;
			} else {
				prev_req = req;
				req = req->next;
			}
		}
	}

	return return_queue;
}

void Row_mvcc::insert_history( ts_t ts, row_t * row)
{
	MVHisEntry * new_entry = get_his_entry();
	new_entry->ts = ts;
	new_entry->row = row;
	if (row != NULL)
		whis_len ++;
	else rhis_len ++;
	MVHisEntry ** queue = (row == NULL)?
		&(readhis) : &(writehis);
	MVHisEntry ** tail = (row == NULL)?
		&(readhistail) : &(writehistail);
	MVHisEntry * his = *queue;
	while (his != NULL && ts < his->ts) {
		his = his->next;
	}

	if (his) {
		LIST_INSERT_BEFORE(his, new_entry);
		if (his == *queue)
			*queue = new_entry;
	} else
		LIST_PUT_TAIL((*queue), (*tail), new_entry);
}

bool Row_mvcc::conflict(TsType type, ts_t ts) {
	// find the unique prewrite-read couple (prewrite before read)
	// if no such couple found, no conflict.
	// else
	// 	 if exists writehis between them, NO conflict!!!!
	// 	 else, CONFLICT!!!
	ts_t rts;
	ts_t pts;
	if (type == R_REQ) {
		rts = ts;
		pts = 0;
		MVReqEntry * req = prereq_mvcc;
		while (req != NULL) {
			if (req->ts < ts && req->ts > pts) {
				pts = req->ts;
			}
			req = req->next;
		}
		if (pts == 0) // no such couple exists
			return false;
	} else if (type == P_REQ) {
		rts = 0;
		pts = ts;
		MVHisEntry * his = readhis;
		while (his != NULL) {
			if (his->ts > ts) {
				rts = his->ts;
			} else
				break;
			his = his->next;
		}
		if (rts == 0) // no couple exists
			return false;
		assert(rts > pts);
	}
	MVHisEntry * whis = writehis;
    while (whis != NULL && whis->ts > pts) {
		if (whis->ts < rts)
			return false;
		whis = whis->next;
	}
	return true;
}

RC Row_mvcc::access(txn_man * txn, TsType type, row_t * row) {
	RC rc = RCOK;
	ts_t ts = txn->get_ts();

	if (g_central_man)
		glob_manager.lock_row(_row);
	else
		pthread_mutex_lock( latch );
  if (type == R_REQ) {
		// figure out if ts is in interval(prewrite(x))
		bool conf = conflict(type, ts);
		if ( conf && rreq_len < MAX_READ_REQ) {
			rc = WAIT;
      txn->rc = rc;
			buffer_req(R_REQ, txn);
			txn->ts_ready = false;
		} else if (conf) {
			rc = Abort;
			printf("\nshould never happen. rreq_len=%ld", rreq_len);
		} else {
			// return results immediately.
			rc = RCOK;
			MVHisEntry * whis = writehis;
			while (whis != NULL && whis->ts > ts)
				whis = whis->next;
			row_t * ret = (whis == NULL)?
				_row : whis->row;
			txn->cur_row = ret;
			insert_history(ts, NULL);
			assert(strstr(_row->get_table_name(), ret->get_table_name()));
		}
	} else if (type == P_REQ) {
		if ( conflict(type, ts) ) {
			rc = Abort;
		} else if (preq_len < MAX_PRE_REQ){
			buffer_req(P_REQ, txn);
			rc = RCOK;
		} else  {
			rc = Abort;
		}
	} else if (type == W_REQ) {
		rc = RCOK;
		// the corresponding prewrite request is debuffered.
		insert_history(ts, row);
		MVReqEntry * req = debuffer_req(P_REQ, txn);
		assert(req != NULL);
		return_req_entry(req);
		update_buffer(txn);
	} else if (type == XP_REQ) {
		MVReqEntry * req = debuffer_req(P_REQ, txn);
		assert (req != NULL);
		return_req_entry(req);
		update_buffer(txn);
	} else
		assert(false);

	if (rc == RCOK) {
		if (whis_len > HIS_RECYCLE_LEN || rhis_len > HIS_RECYCLE_LEN) {
			ts_t t_th = glob_manager.get_min_ts(txn->get_thd_id());
			if (readhistail && readhistail->ts < t_th)
				clear_history(R_REQ, t_th);
			// TODO. Here is a tricky bug. The oldest transaction might be
			// reading an even older version whose timestamp < t_th.
			// But we cannot recycle that version because it is still being used.
			// So the HACK here is to make sure that the first version older than
			// t_th not be recycled.
			if (whis_len > 1 &&
				writehistail->prev->ts < t_th) {
				row_t * latest_row = clear_history(W_REQ, t_th);
				if (latest_row != NULL) {
					assert(_row != latest_row);
					_row->copy(latest_row);
				}
			}
		}
	}

	if (g_central_man)
		glob_manager.release_row(_row);
	else
		pthread_mutex_unlock( latch );

	return rc;
}

void Row_mvcc::update_buffer(txn_man * txn) {
	MVReqEntry * ready_read = debuffer_req(R_REQ, NULL);
	MVReqEntry * req = ready_read;
	MVReqEntry * tofree = NULL;

	while (req != NULL) {
		// find the version for the request
		MVHisEntry * whis = writehis;
		while (whis != NULL && whis->ts > req->ts)
			whis = whis->next;
		row_t * row = (whis == NULL)?
			_row : whis->row;
		req->txn->cur_row = row;
		insert_history(req->ts, NULL);
		assert(row->get_data() != NULL);
		assert(row->get_table() != NULL);
		assert(row->get_schema() == _row->get_schema());

    // TODO: add req->txn to work queue
		req->txn->ts_ready = true;
    txn_pool.restart_txn(req->txn->get_txn_id());
		tofree = req;
		req = req->next;
		// free ready_read
		return_req_entry(tofree);
	}
}
<|endoftext|>


<commit_before>

/*
 *  client.cpp
 *
 *  Handles the client env.
 *
 *  Created by Ryan Faulkner on 2014-06-08
 *  Copyright (c) 2014. All rights reserved.
 */

#include <chrono>
#include <iostream>
#include <string>
#include <redis3m/connection.h>
#include "parse.h"
#include "redis.h"

#define DBY_CMD_QUEUE_PREFIX "dby_command_queue_"

using namespace std;

/**
 * This method handles fetching the next item to be
 *
 * TODO - implement
 */
std::string getNextQueueKey(RedisHandler& rh) {
    return "";
}

int main() {
    std::string line;
    Parser* parser = new Parser();
    RedisHandler* redisHandler = new RedisHandler(REDISHOST, REDISPORT);
    parser->setDebug(true);

    cout << "" << endl;

    // Read the input
    while (1) {

        // TODO - implement locking function

        // 1. Fetch next command off the queue
        this->redisHandler->connect();
        std::string key = getNextQueueKey(*redisHandler);
        if (this->redisHandler->exists(key))
            line = this->redisHandler->read(key);

        // TODO - 2. LOCK KEY

        // 3. Parse the Command
        parser->parse(line);
        parser->resetState();

        // 4. execute timeout
        this->redisHandler->deleteKey(key)

        // 5. execute timeout
        std::chrono::milliseconds(10)
    }
    return 0;
}

<commit_msg>implement getNextQueueKey to pull commands off of the queue<commit_after>

/*
 *  client.cpp
 *
 *  Handles the client env.
 *
 *  Created by Ryan Faulkner on 2014-06-08
 *  Copyright (c) 2014. All rights reserved.
 */

#include <chrono>
#include <iostream>
#include <string>
#include <redis3m/connection.h>
#include "parse.h"
#include "redis.h"

#define DBY_CMD_QUEUE_PREFIX "dby_command_queue_"

using namespace std;

/**
 * This method handles fetching the next item to be
 *
 * TODO - handle ordering
 */
std::string getNextQueueKey(RedisHandler& rh) {
    std::vector<std::string> keys = rh.keys(std::string(DBY_CMD_QUEUE_PREFIX) + std::string("*"));
    return keys[0];
}

int main() {
    std::string line;
    Parser* parser = new Parser();
    RedisHandler* redisHandler = new RedisHandler(REDISHOST, REDISPORT);
    parser->setDebug(true);

    cout << "" << endl;

    // Read the input
    while (1) {

        // TODO - implement locking function

        // 1. Fetch next command off the queue
        this->redisHandler->connect();
        std::string key = getNextQueueKey(*redisHandler);
        if (this->redisHandler->exists(key))
            line = this->redisHandler->read(key);

        // TODO - 2. LOCK KEY

        // 3. Parse the Command
        parser->parse(line);
        parser->resetState();

        // 4. execute timeout
        this->redisHandler->deleteKey(key)

        // 5. execute timeout
        std::chrono::milliseconds(10)
    }
    return 0;
}

<|endoftext|>


<commit_before>/*
 * daemon.cpp
 *
 *  Created on: Apr 7, 2013
 *      Author: nikita.karnauhov@gmail.com
 */

#include <string>
#include <stdexcept>
#include <memory>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <fstream>
#include <list>
#include <set>
#include <thread>
#include <mutex>
#include <algorithm>

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netdb.h>
#include <poll.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
#include <getopt.h>

#include <alsa/asoundlib.h>

#include <unap.pb.h>
#include "log.h"
#include "alsa_wrapper.h"
#include "player.h"
#include "settings.h"

static
void _print_usage(std::ostream &_os) {
    _os << "UNAPd, network audio receiver.\n" <<
            "Usage: unapd [OPTION]...\n\n" <<
            "  -h, --help              Print this message and exit.\n" <<
            "  -v, --version           Display the version and exit.\n" <<
            "  -c, --config-path       Set configuration file location.\n" <<
            "  -l, --log-path          Set log file location.\n" <<
            "  -L, --log-level         Set log verbosity level (0 to 4, use 0 to disable logging).\n" <<
            "  -d, --daemon            Run as a daemon.\n" <<
            "  -n, --no-daemon         Don't run as a daemon, display log messages (default).\n" <<
            "  -p, --pid-path          PID file location.\n" <<
            "" << std::flush;
}

static
void _print_version() {
    std::cout << "UNAPd, network audio receiver.\n" <<
            "Version 0.1" << std::endl;
}

static
void _parse_options(int _nArgs, char *const _pArgs[]) {
    static struct option options[] = {
            {"help", 0, 0, 'h'},
            {"version", 0, 0, 'v'},
            {"config-path", required_argument, 0, 'c'},

            // These options have equivalents in settings file.
            {"log-path", required_argument, 0, 'l'},
            {"log-level", required_argument, 0, 'L'},
            {"daemon", 0, 0, 'd'},
            {"no-daemon", 0, 0, 'n'},
            {"pid-path", 0, 0, 'p'},
            {0, 0, 0, 0}
    };

    const char *strOptions = "hvc:l:L:dnp:";
    int nOption = 0;
    SettingsParser sp;
    std::map<std::string, std::string> kvs;

    // Handle --help, --version and --config-path options.
    while (true) {
        const int c = getopt_long(_nArgs, _pArgs, strOptions, options, &nOption);

        if (c == -1) {
            if (optind < _nArgs)
                throw RuntimeError("Redundant argument: %s", _pArgs[optind]);
            break;
        }

        switch (c) {
            case 'h':
                _print_usage(std::cout);
                exit(EXIT_SUCCESS);

            case 'v':
                _print_version();
                exit(EXIT_SUCCESS);

            case 'c':
                sp.parse_file(optarg);
                break;

            case '?':
                _print_usage(std::cerr);
                exit(EXIT_FAILURE);

            default:
                kvs[std::find_if(std::begin(options), std::end(options),
                        [c](struct option &_opt) {return _opt.val == c;})->name] = optarg;
                break;
        }
    }

    for (auto &kv : kvs)
        sp.parse_option(kv.first, kv.second);

    g_settings = sp.get();
}

static
void _main(Log &_log) {
    std::string strHost("127.0.0.1");
    std::string strPort("26751");

//    int m_nSocket = socket(PF_INET, SOCK_DGRAM, 0);
//
//    if (m_nSocket < 0)
//        throw std::runtime_error(strerror(errno));
//
//    struct sockaddr_in name;
//
//    name.sin_family = AF_INET;
//    name.sin_port = htons(nPort);
//
//    struct hostent *pHost = gethostbyname(strHost.c_str());
//
//    if (!pHost)
//        throw std::runtime_error(strerror(errno));
//
//    name.sin_addr = *(struct in_addr *)pHost->h_addr;

    struct addrinfo hints;
    struct addrinfo *serverinfo;

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_DGRAM;
    hints.ai_flags = AI_PASSIVE;

    if (getaddrinfo(NULL, strPort.c_str(), &hints, &serverinfo) < 0)
        throw SystemError("getaddrinfo()");

    const int nSocket = socket(serverinfo->ai_family, serverinfo->ai_socktype, serverinfo->ai_protocol);

    if (bind(nSocket, serverinfo->ai_addr, serverinfo->ai_addrlen) < 0)
        throw SystemError("bind()");

    freeaddrinfo(serverinfo);

    struct pollfd fd{nSocket, POLLIN, 0};
    size_t cBufferSize = 1024*100; // Should be enough, right?
    auto pBuf = std::unique_ptr<char[]>(new char[cBufferSize]);
    std::list<unap::Packet> packets;
//    unap::Packet p;
//
//    player.init(p);
//    player.play(p);
//
//    return EXIT_SUCCESS;

    while (true) {
        if (poll(&fd, 1, 1000) < 0)
            throw SystemError("poll()");

        if (fd.revents & POLLIN) {
            struct sockaddr sender;
            socklen_t sendsize = sizeof(sender);
            bzero(&sender, sizeof(sender));
            const int nPacketSize = recvfrom(fd.fd, pBuf.get(), cBufferSize, 0, &sender, &sendsize);
            char strSender[128];

            if (nPacketSize < 0)
                throw SystemError("recvfrom()");

            inet_ntop(sender.sa_family, &((struct sockaddr_in &)sender).sin_addr,
                    strSender, sizeof(strSender));

            unap::Packet &packet = *packets.emplace(packets.end());

            if (!packet.ParseFromArray(pBuf.get(), nPacketSize)) {
                std::cerr << "Broken packet." << std::endl;
                continue;
            }

            Player *pPlayer = Player::get(packet, _log);

            if (!pPlayer->is_prepared()) {
                pPlayer->init(packet);
                pPlayer->run();
            }

            pPlayer->play(packet);
        }
    }

static
bool _write_pid(Log &_log) {
    // Specify empty PID path to disable writing PID.
    if (g_settings.strPIDPath.empty())
        return false;

    std::ofstream os(g_settings.strPIDPath);

    if (!os.good())
        throw RuntimeError("Cannot write PID file: %s", g_settings.strPIDPath.c_str());

    os << getpid() << std::endl;
    _log.info("PID file written to %s", g_settings.strPIDPath.c_str());

    return true;
}
}

int main(int _nArgs, char *const _pArgs[]) {
    Log log("");
    bool bPIDWritten = false;

    try {
        _parse_options(_nArgs, _pArgs);

        if (!g_settings.strLogPath.empty()) {
            log.open(g_settings.strLogPath);
            log.info("Logging to %s", g_settings.strLogPath.c_str());
        }

        if (g_settings.bDaemon) {
            log.close("");

            if (daemon(true, false) != 0)
                throw SystemError("daemon()");
        }

        bPIDWritten = _write_pid(log);
        _main(log);
    } catch (std::exception &e) {
        log.log(llError, e.what());
        return EXIT_FAILURE;
    }

    if (bPIDWritten)
        unlink(g_settings.strPIDPath.c_str());

    return EXIT_SUCCESS;
}
<commit_msg>Handle terminating signals.<commit_after>/*
 * daemon.cpp
 *
 *  Created on: Apr 7, 2013
 *      Author: nikita.karnauhov@gmail.com
 */

#include <string>
#include <stdexcept>
#include <memory>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <fstream>
#include <list>
#include <set>
#include <thread>
#include <mutex>
#include <algorithm>

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netdb.h>
#include <poll.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
#include <getopt.h>
#include <signal.h>

#include <alsa/asoundlib.h>

#include <unap.pb.h>
#include "log.h"
#include "alsa_wrapper.h"
#include "player.h"
#include "settings.h"

// Signal flags.
static int g_nExitSignal = 0;

static
void _print_usage(std::ostream &_os) {
    _os << "UNAPd, network audio receiver.\n" <<
            "Usage: unapd [OPTION]...\n\n" <<
            "  -h, --help              Print this message and exit.\n" <<
            "  -v, --version           Display the version and exit.\n" <<
            "  -c, --config-path       Set configuration file location.\n" <<
            "  -l, --log-path          Set log file location.\n" <<
            "  -L, --log-level         Set log verbosity level (0 to 4, use 0 to disable logging).\n" <<
            "  -d, --daemon            Run as a daemon.\n" <<
            "  -n, --no-daemon         Don't run as a daemon, display log messages (default).\n" <<
            "  -p, --pid-path          PID file location.\n" <<
            "" << std::flush;
}

static
void _print_version() {
    std::cout << "UNAPd, network audio receiver.\n" <<
            "Version 0.1" << std::endl;
}

static
void _parse_options(int _nArgs, char *const _pArgs[]) {
    static struct option options[] = {
            {"help", 0, 0, 'h'},
            {"version", 0, 0, 'v'},
            {"config-path", required_argument, 0, 'c'},

            // These options have equivalents in settings file.
            {"log-path", required_argument, 0, 'l'},
            {"log-level", required_argument, 0, 'L'},
            {"daemon", 0, 0, 'd'},
            {"no-daemon", 0, 0, 'n'},
            {"pid-path", 0, 0, 'p'},
            {0, 0, 0, 0}
    };

    const char *strOptions = "hvc:l:L:dnp:";
    int nOption = 0;
    SettingsParser sp;
    std::map<std::string, std::string> kvs;

    // TODO: build std::map<int, std::string>

    // Handle --help, --version and --config-path options.
    while (true) {
        const int c = getopt_long(_nArgs, _pArgs, strOptions, options, &nOption);

        if (c == -1) {
            if (optind < _nArgs)
                throw RuntimeError("Redundant argument: %s", _pArgs[optind]);
            break;
        }

        switch (c) {
            case 'h':
                _print_usage(std::cout);
                exit(EXIT_SUCCESS);

            case 'v':
                _print_version();
                exit(EXIT_SUCCESS);

            case 'c':
                sp.parse_file(optarg);
                break;

            case '?':
                _print_usage(std::cerr);
                exit(EXIT_FAILURE);

            default:
                kvs[std::find_if(std::begin(options), std::end(options),
                        [c](struct option &_opt) {return _opt.val == c;})->name] = optarg;
                break;
        }
    }

    for (auto &kv : kvs)
        sp.parse_option(kv.first, kv.second);

    g_settings = sp.get();
}

static
void _main(Log &_log) {
    std::string strHost("127.0.0.1");
    std::string strPort("26751");

//    int m_nSocket = socket(PF_INET, SOCK_DGRAM, 0);
//
//    if (m_nSocket < 0)
//        throw std::runtime_error(strerror(errno));
//
//    struct sockaddr_in name;
//
//    name.sin_family = AF_INET;
//    name.sin_port = htons(nPort);
//
//    struct hostent *pHost = gethostbyname(strHost.c_str());
//
//    if (!pHost)
//        throw std::runtime_error(strerror(errno));
//
//    name.sin_addr = *(struct in_addr *)pHost->h_addr;

    struct addrinfo hints;
    struct addrinfo *serverinfo;

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_DGRAM;
    hints.ai_flags = AI_PASSIVE;

    if (getaddrinfo(NULL, strPort.c_str(), &hints, &serverinfo) < 0)
        throw SystemError("getaddrinfo()");

    const int nSocket = socket(serverinfo->ai_family, serverinfo->ai_socktype, serverinfo->ai_protocol);

    if (bind(nSocket, serverinfo->ai_addr, serverinfo->ai_addrlen) < 0)
        throw SystemError("bind()");

    freeaddrinfo(serverinfo);

    struct pollfd fd{nSocket, POLLIN, 0};
    size_t cBufferSize = 1024*100; // Should be enough, right?
    auto pBuf = std::unique_ptr<char[]>(new char[cBufferSize]);
    std::list<unap::Packet> packets;
//    unap::Packet p;
//
//    player.init(p);
//    player.play(p);
//
//    return EXIT_SUCCESS;

    do {
        try {
            if (poll(&fd, 1, 1000) < 0)
                throw SystemError("poll()");

            if (fd.revents & POLLIN) {
                struct sockaddr sender;
                socklen_t sendsize = sizeof(sender);
                bzero(&sender, sizeof(sender));
                const int nPacketSize = recvfrom(fd.fd, pBuf.get(), cBufferSize, 0, &sender, &sendsize);
                char strSender[128];

                if (nPacketSize < 0)
                    throw SystemError("recvfrom()");

                inet_ntop(sender.sa_family, &((struct sockaddr_in &)sender).sin_addr,
                        strSender, sizeof(strSender));

                unap::Packet &packet = *packets.emplace(packets.end());

                if (!packet.ParseFromArray(pBuf.get(), nPacketSize)) {
                    _log.debug("Broken packet.");
                    continue;
                }

                Player *pPlayer = Player::get(packet, _log);

                if (!pPlayer->is_prepared()) {
                    pPlayer->init(packet);
                    pPlayer->run();
                }

                pPlayer->play(packet);
            }
        } catch (SystemError &se) {
            if (se.getError() != EINTR)
                throw;
        }

        if (g_nExitSignal != 0)
            _log.info("Got signal %d, exiting gracefully.", g_nExitSignal);
    } while (g_nExitSignal == 0);
}

static
bool _write_pid(Log &_log) {
    // Specify empty PID path to disable writing PID.
    if (g_settings.strPIDPath.empty())
        return false;

    std::ofstream os(g_settings.strPIDPath);

    if (!os.good())
        throw RuntimeError("Cannot write PID file: %s", g_settings.strPIDPath.c_str());

    os << getpid() << std::endl;
    _log.info("PID file written to %s", g_settings.strPIDPath.c_str());

    return true;
}

static
void _handle_signal(int _nSignal, siginfo_t *_pSigInfo, void *_pContext) {
    g_nExitSignal = _nSignal;
}

static
void _init_signals() {
    struct sigaction action = {};
    const int exitSignals[]{
            SIGTERM, SIGINT, SIGPIPE, SIGALRM, SIGUSR1, SIGUSR2, SIGPOLL,
            SIGPROF, SIGVTALRM
    };

    action.sa_sigaction = &_handle_signal;
    action.sa_flags = SA_SIGINFO;

    for (int nSignal : exitSignals)
        if (sigaction(nSignal, &action, NULL) < 0)
            throw SystemError("sigaction()");

}

int main(int _nArgs, char *const _pArgs[]) {
    Log log("");
    bool bPIDWritten = false;

    try {
        _parse_options(_nArgs, _pArgs);

        if (!g_settings.strLogPath.empty()) {
            log.open(g_settings.strLogPath);
            log.info("Logging to %s", g_settings.strLogPath.c_str());
        }

        if (g_settings.bDaemon) {
            log.close("");

            if (daemon(true, false) != 0)
                throw SystemError("daemon()");
        }

        _init_signals();
        bPIDWritten = _write_pid(log);
        _main(log);
    } catch (std::exception &e) {
        log.log(llError, e.what());
        return EXIT_FAILURE;
    }

    if (bPIDWritten)
        unlink(g_settings.strPIDPath.c_str());

    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/*      _______   __   __   __   ______   __   __   _______   __   __
 *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
 *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
 *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
 *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
 *
 * Copyright (c) 2004 - 2008 Olof Naessn and Per Larsson
 *
 *
 * Per Larsson a.k.a finalman
 * Olof Naessn a.k.a jansem/yakslem
 *
 * Visit: http://guichan.sourceforge.net
 *
 * License: (BSD)
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name of Guichan nor the names of its contributors may
 *    be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * 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
 * OWNER 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.
 */

/*
 * For comments regarding functions please see the header file.
 */

#include "guichan/hge/hgeimagefont.hpp"

#include "guichan/color.hpp"
#include "guichan/graphics.hpp"

namespace gcn
{
    HGEImageFont::HGEImageFont(const std::string& filename)
    {
        mHGEFont = new hgeFont(filename.c_str());
    }

    HGEImageFont::~HGEImageFont()
    {
        delete mHGEFont;
    }

    hgeFont *HGEImageFont::getFont() const
    {
        return mHGEFont;
    }

    int HGEImageFont::getWidth(const std::string &text) const
    {
        return static_cast<int>(mHGEFont->GetStringWidth(text.c_str())) + 1;
    }

    int HGEImageFont::getWidth(char character) const
    {
        char buf[2];

        sprintf(buf, "%c", character);

        return mHGEFont->GetStringWidth(buf);
    }

    int HGEImageFont::getHeight() const
    {
        return  static_cast<int>(mHGEFont->GetHeight());
    }

    int HGEImageFont::getStringIndexAt(const std::string& text, int x)
    {
        unsigned int i;
        int size = 0;

        for (i = 0; i < text.size(); ++i)
        {
            size += getWidth(text.at(i));

            if (size > x)
            {
                return i;
            }
        }

        return text.size();
    }

    void HGEImageFont::drawString(Graphics *graphics, const std::string &text, int x, int y)
    {
        Color color = graphics->getColor();

        mHGEFont->SetColor(ARGB(color.a, color.r, color.g, color.b));

        mHGEFont->Render(x, y, HGETEXT_LEFT, text.c_str());
    }
}
<commit_msg>A bug has been fixed where drawing of text did not use relative coordinates.<commit_after>/*      _______   __   __   __   ______   __   __   _______   __   __
 *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
 *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
 *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
 *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
 *
 * Copyright (c) 2004 - 2008 Olof Naessn and Per Larsson
 *
 *
 * Per Larsson a.k.a finalman
 * Olof Naessn a.k.a jansem/yakslem
 *
 * Visit: http://guichan.sourceforge.net
 *
 * License: (BSD)
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name of Guichan nor the names of its contributors may
 *    be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * 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
 * OWNER 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.
 */

/*
 * For comments regarding functions please see the header file.
 */

#include "guichan/hge/hgeimagefont.hpp"

#include "guichan/color.hpp"
#include "guichan/graphics.hpp"

namespace gcn
{
    HGEImageFont::HGEImageFont(const std::string& filename)
    {
        mHGEFont = new hgeFont(filename.c_str());
    }

    HGEImageFont::~HGEImageFont()
    {
        delete mHGEFont;
    }

    hgeFont *HGEImageFont::getFont() const
    {
        return mHGEFont;
    }

    int HGEImageFont::getWidth(const std::string &text) const
    {
        return static_cast<int>(mHGEFont->GetStringWidth(text.c_str())) + 1;
    }

    int HGEImageFont::getWidth(char character) const
    {
        char buf[2];

        sprintf(buf, "%c", character);

        return mHGEFont->GetStringWidth(buf);
    }

    int HGEImageFont::getHeight() const
    {
        return  static_cast<int>(mHGEFont->GetHeight());
    }

    int HGEImageFont::getStringIndexAt(const std::string& text, int x)
    {
        unsigned int i;
        int size = 0;

        for (i = 0; i < text.size(); ++i)
        {
            size += getWidth(text.at(i));

            if (size > x)
            {
                return i;
            }
        }

        return text.size();
    }

    void HGEImageFont::drawString(Graphics *graphics, const std::string &text, int x, int y)
    {
		ClipRectangle const top = mClipStack.top();

        x += top.xOffset;
        y += top.yOffset;

		Color color = graphics->getColor();

        mHGEFont->SetColor(ARGB(color.a, color.r, color.g, color.b));

        mHGEFont->Render(x, y, HGETEXT_LEFT, text.c_str());
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015 Cryptonomex, Inc., and contributors.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *
 * 1. Any modified source or binaries are used only with the BitShares network.
 *
 * 2. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 *
 * 3. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided 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 <graphene/chain/protocol/authority.hpp>
#include <graphene/db/generic_index.hpp>

namespace graphene { namespace chain {

  /**
   * @class withdraw_permission_object
   * @brief Grants another account authority to withdraw a limited amount of funds per interval
   *
   * The primary purpose of this object is to enable recurring payments on the blockchain. An account which wishes to
   * process a recurring payment may use a @ref withdraw_permission_claim_operation to reference an object of this type
   * and withdraw up to @ref withdrawal_limit from @ref withdraw_from_account. Only @ref authorized_account may do
   * this. Any number of withdrawals may be made so long as the total amount withdrawn per period does not exceed the
   * limit for any given period.
   */
  class withdraw_permission_object : public graphene::db::abstract_object<withdraw_permission_object>
  {
     public:
        static const uint8_t space_id = protocol_ids;
        static const uint8_t type_id  = withdraw_permission_object_type;

        /// The account authorizing @ref authorized_account to withdraw from it
        account_id_type    withdraw_from_account;
        /// The account authorized to make withdrawals from @ref withdraw_from_account
        account_id_type    authorized_account;
        /// The maximum amount which may be withdrawn per period. All withdrawals must be of this asset type
        asset              withdrawal_limit;
        /// The duration of a withdrawal period in seconds
        uint32_t           withdrawal_period_sec = 0;
        /// The beginning of the next withdrawal period
        time_point_sec     period_start_time;
        /// The time at which this withdraw permission expires
        time_point_sec     expiration;

        /// tracks the total amount
        share_type         claimed_this_period;
        /// True if the permission may still be claimed for this period; false if it has already been used
        asset              available_this_period( fc::time_point_sec current_time )const
        {
           if( current_time >= period_start_time + withdrawal_period_sec )
              return withdrawal_limit;
           return asset(
              ( withdrawal_limit.amount > claimed_this_period )
              ? withdrawal_limit.amount - claimed_this_period
              : 0, withdrawal_limit.asset_id );
        }
   };

   struct by_from;
   struct by_authorized;
   struct by_expiration;

   typedef multi_index_container<
      withdraw_permission_object,
      indexed_by<
         ordered_unique< tag<by_id>, member< object, object_id_type, &object::id > >,
         ordered_non_unique< tag<by_from>, member<withdraw_permission_object, account_id_type, &withdraw_permission_object::withdraw_from_account> >,
         ordered_non_unique< tag<by_authorized>, member<withdraw_permission_object, account_id_type, &withdraw_permission_object::authorized_account> >,
         ordered_non_unique< tag<by_expiration>, member<withdraw_permission_object, time_point_sec, &withdraw_permission_object::expiration> >
      >
   > withdraw_permission_object_multi_index_type;

   typedef generic_index<withdraw_permission_object, withdraw_permission_object_multi_index_type> withdraw_permission_index;

} } // graphene::chain

FC_REFLECT_DERIVED( graphene::chain::withdraw_permission_object, (graphene::db::object),
                    (withdraw_from_account)
                    (authorized_account)
                    (withdrawal_limit)
                    (withdrawal_period_sec)
                    (period_start_time)
                    (expiration)
                 )
<commit_msg>Fix withdraw_permission_object.hpp reflection #562<commit_after>/*
 * Copyright (c) 2015 Cryptonomex, Inc., and contributors.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *
 * 1. Any modified source or binaries are used only with the BitShares network.
 *
 * 2. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 *
 * 3. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided 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 <graphene/chain/protocol/authority.hpp>
#include <graphene/db/generic_index.hpp>

namespace graphene { namespace chain {

  /**
   * @class withdraw_permission_object
   * @brief Grants another account authority to withdraw a limited amount of funds per interval
   *
   * The primary purpose of this object is to enable recurring payments on the blockchain. An account which wishes to
   * process a recurring payment may use a @ref withdraw_permission_claim_operation to reference an object of this type
   * and withdraw up to @ref withdrawal_limit from @ref withdraw_from_account. Only @ref authorized_account may do
   * this. Any number of withdrawals may be made so long as the total amount withdrawn per period does not exceed the
   * limit for any given period.
   */
  class withdraw_permission_object : public graphene::db::abstract_object<withdraw_permission_object>
  {
     public:
        static const uint8_t space_id = protocol_ids;
        static const uint8_t type_id  = withdraw_permission_object_type;

        /// The account authorizing @ref authorized_account to withdraw from it
        account_id_type    withdraw_from_account;
        /// The account authorized to make withdrawals from @ref withdraw_from_account
        account_id_type    authorized_account;
        /// The maximum amount which may be withdrawn per period. All withdrawals must be of this asset type
        asset              withdrawal_limit;
        /// The duration of a withdrawal period in seconds
        uint32_t           withdrawal_period_sec = 0;
        /// The beginning of the next withdrawal period
        time_point_sec     period_start_time;
        /// The time at which this withdraw permission expires
        time_point_sec     expiration;

        /// tracks the total amount
        share_type         claimed_this_period;
        /// True if the permission may still be claimed for this period; false if it has already been used
        asset              available_this_period( fc::time_point_sec current_time )const
        {
           if( current_time >= period_start_time + withdrawal_period_sec )
              return withdrawal_limit;
           return asset(
              ( withdrawal_limit.amount > claimed_this_period )
              ? withdrawal_limit.amount - claimed_this_period
              : 0, withdrawal_limit.asset_id );
        }
   };

   struct by_from;
   struct by_authorized;
   struct by_expiration;

   typedef multi_index_container<
      withdraw_permission_object,
      indexed_by<
         ordered_unique< tag<by_id>, member< object, object_id_type, &object::id > >,
         ordered_non_unique< tag<by_from>, member<withdraw_permission_object, account_id_type, &withdraw_permission_object::withdraw_from_account> >,
         ordered_non_unique< tag<by_authorized>, member<withdraw_permission_object, account_id_type, &withdraw_permission_object::authorized_account> >,
         ordered_non_unique< tag<by_expiration>, member<withdraw_permission_object, time_point_sec, &withdraw_permission_object::expiration> >
      >
   > withdraw_permission_object_multi_index_type;

   typedef generic_index<withdraw_permission_object, withdraw_permission_object_multi_index_type> withdraw_permission_index;

} } // graphene::chain

FC_REFLECT_DERIVED( graphene::chain::withdraw_permission_object, (graphene::db::object),
                    (withdraw_from_account)
                    (authorized_account)
                    (withdrawal_limit)
                    (withdrawal_period_sec)
                    (period_start_time)
                    (expiration)
                    (claimed_this_period)
                 )
<|endoftext|>