<commit_before>/*
 * Copyright (c) 2010, Georgia Tech Research Corporation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *     * Redistributions of source code must retain the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer.
 *     * Redistributions in binary form must reproduce the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer in the documentation and/or other materials
 *       provided with the distribution.
 *     * Neither the name of the Georgia Tech Research Corporation 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 GEORGIA TECH RESEARCH CORPORATION ''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 GEORGIA
 * TECH RESEARCH CORPORATION 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.
 *
 */

/** @file RRT.cpp
 *  @author Tobias Kunz
 */

#include "RRT.h"
#include "robotics/World.h"
#include "robotics/Robot.h"
#include "kinematics/Dof.h"

using namespace std;
using namespace Eigen;
using namespace robotics;

namespace planning {

RRT::RRT(World* world, int robot, const Eigen::VectorXi &dofs, const VectorXd &root, double stepSize) :
	world(world),
	robot(robot),
	dofs(dofs),
	ndim(dofs.size()),
	stepSize(stepSize),
	numSamples(0),
	numCollisions(0),
	numNoProgress(0),
	numStepTooLarge(0),
	index(flann::KDTreeIndexParams())
{
	srand(time(NULL));
	addNode(root, -1);
}

RRT::RRT(World* world, int robot, const Eigen::VectorXi &dofs, const vector<VectorXd> &roots, double stepSize) :
	world(world),
	robot(robot),
	dofs(dofs),
	ndim(dofs.size()),
	stepSize(stepSize),
	numSamples(0),
	numCollisions(0),
	numNoProgress(0),
	numStepTooLarge(0),
	index(flann::KDTreeIndexParams())
{
	srand(time(NULL));
	for(int i = 0; i < roots.size(); i++) {
		addNode(roots[i], -1);
	}
}

RRT::~RRT() {
}

bool RRT::connect() {
	VectorXd qtry = getRandomConfig();
	return connect(qtry);
}

bool RRT::connect(const VectorXd &target)
{
	int NNidx = getNearestNeighbor(target);
	StepResult result = STEP_PROGRESS;
	int i = 0;
	while(result == STEP_PROGRESS) {
		result = tryStepFromNode(target, NNidx);
		NNidx = configVector.size() - 1;
		i++;
	}
	return (result == STEP_REACHED);
}

RRT::StepResult RRT::tryStep() {
	VectorXd qtry = getRandomConfig();
	return tryStep(qtry);
}

RRT::StepResult RRT::tryStep(const VectorXd &qtry) {
	int NNidx = getNearestNeighbor(qtry);
	return tryStepFromNode(qtry, NNidx);
}

RRT::StepResult RRT::tryStepFromNode(const VectorXd &qtry, int NNidx)
{
	/*
	 * Calculates a new node to grow towards qtry, checks for collisions, and adds
	 */

	VectorXd qnear = configVector[NNidx];

	if((qtry - qnear).norm() < stepSize) {
		return STEP_REACHED;
	}

	// Scale this vector to step_size and add to end of qnear
	VectorXd qnew = qnear + stepSize * (qtry - qnear).normalized();
	list<VectorXd> intermediatePoints;

	if(!newConfig(intermediatePoints, qnew, qnear, qtry)) {
		return STEP_COLLISION;
	}
	else {
		for(list<VectorXd>::iterator it = intermediatePoints.begin(); it != intermediatePoints.end(); it++) {
			NNidx = addNode(*it, NNidx);
		}
		addNode(qnew, NNidx);
		return STEP_PROGRESS;
	}
}

// Provides a hook for child classes to alter a new config before it gets added to the tree
bool RRT::newConfig(list<VectorXd> &intermediatePoints, VectorXd &qnew, const VectorXd &qnear, const VectorXd &qtarget) {
	return !checkCollisions(qnew);
}

int RRT::addNode(const VectorXd &qnew, int parentId)
{
	// Update graph vectors
	configVector.push_back(qnew);
	parentVector.push_back(parentId);

	uintptr_t id = configVector.size() - 1;
	index.addPoints(flann::Matrix<double>((double*)qnew.data(), 1, qnew.size()));

	activeNode = id;
	return id;
}

inline int RRT::getNearestNeighbor(const VectorXd &qsamp)
{
	int nearest;
	double distance;
	index.knnSearch(flann::Matrix<double>((double*)qsamp.data(), 1, qsamp.size()),
		flann::Matrix<int>(&nearest, 1, 1), flann::Matrix<double>(&distance, 1, 1), 1, flann::SearchParams(flann::FLANN_CHECKS_UNLIMITED));
	activeNode = nearest;
	return nearest;
}

// random # between min & max
inline double RRT::randomInRange(double min, double max) {
	if(min == max) {
		return min;
	}
	return min + ((max-min) * ((double)rand() / ((double)RAND_MAX + 1)));
}

VectorXd RRT::getRandomConfig()
{
	/*
	 * Samples a random point for qtmp in the configuration space,
	 * bounded by the provided configuration vectors (and returns ref to it)
	 */
	VectorXd config(ndim);
	for (int i = 0; i < ndim; ++i) {
		config[i] = randomInRange(world->getRobot(robot)->getDof(dofs[i])->getMin(), world->getRobot(robot)->getDof(dofs[i])->getMax());
	}
	return config;
}

double RRT::getGap(const VectorXd &target) {
	return (target - configVector[activeNode]).norm();
}

void RRT::tracePath(int node, std::list<VectorXd> &path, bool reverse)
{
	int x = node;

	while(x != -1) {
		if(!reverse) {
			path.push_front(configVector[x]);
		}
		else {
			path.push_back(configVector[x]);
		}
		x = parentVector[x];
	}
}

bool RRT::checkCollisions(const VectorXd &c)
{
	world->getRobot(robot)->setDofs(c, dofs);
	return world->checkCollision();
}

unsigned int RRT::getSize() {
	return configVector.size();
}

}<commit_msg>Attempt to fix compiler error on Linux<commit_after>/*
 * Copyright (c) 2010, Georgia Tech Research Corporation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *     * Redistributions of source code must retain the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer.
 *     * Redistributions in binary form must reproduce the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer in the documentation and/or other materials
 *       provided with the distribution.
 *     * Neither the name of the Georgia Tech Research Corporation 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 GEORGIA TECH RESEARCH CORPORATION ''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 GEORGIA
 * TECH RESEARCH CORPORATION 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.
 *
 */

/** @file RRT.cpp
 *  @author Tobias Kunz
 */

#include "RRT.h"
#include "robotics/World.h"
#include "robotics/Robot.h"
#include "kinematics/Dof.h"

using namespace std;
using namespace Eigen;
using namespace robotics;

namespace planning {

RRT::RRT(World* world, int robot, const Eigen::VectorXi &dofs, const VectorXd &root, double stepSize) :
	world(world),
	robot(robot),
	dofs(dofs),
	ndim(dofs.size()),
	stepSize(stepSize),
	numSamples(0),
	numCollisions(0),
	numNoProgress(0),
	numStepTooLarge(0),
	index(flann::KDTreeIndexParams())
{
	srand(time(NULL));
	addNode(root, -1);
}

RRT::RRT(World* world, int robot, const Eigen::VectorXi &dofs, const vector<VectorXd> &roots, double stepSize) :
	world(world),
	robot(robot),
	dofs(dofs),
	ndim(dofs.size()),
	stepSize(stepSize),
	numSamples(0),
	numCollisions(0),
	numNoProgress(0),
	numStepTooLarge(0),
	index(flann::KDTreeIndexParams())
{
	srand(time(NULL));
	for(int i = 0; i < roots.size(); i++) {
		addNode(roots[i], -1);
	}
}

RRT::~RRT() {
}

bool RRT::connect() {
	VectorXd qtry = getRandomConfig();
	return connect(qtry);
}

bool RRT::connect(const VectorXd &target)
{
	int NNidx = getNearestNeighbor(target);
	StepResult result = STEP_PROGRESS;
	int i = 0;
	while(result == STEP_PROGRESS) {
		result = tryStepFromNode(target, NNidx);
		NNidx = configVector.size() - 1;
		i++;
	}
	return (result == STEP_REACHED);
}

RRT::StepResult RRT::tryStep() {
	VectorXd qtry = getRandomConfig();
	return tryStep(qtry);
}

RRT::StepResult RRT::tryStep(const VectorXd &qtry) {
	int NNidx = getNearestNeighbor(qtry);
	return tryStepFromNode(qtry, NNidx);
}

RRT::StepResult RRT::tryStepFromNode(const VectorXd &qtry, int NNidx)
{
	/*
	 * Calculates a new node to grow towards qtry, checks for collisions, and adds
	 */

	VectorXd qnear = configVector[NNidx];

	if((qtry - qnear).norm() < stepSize) {
		return STEP_REACHED;
	}

	// Scale this vector to step_size and add to end of qnear
	VectorXd qnew = qnear + stepSize * (qtry - qnear).normalized();
	list<VectorXd> intermediatePoints;

	if(!newConfig(intermediatePoints, qnew, qnear, qtry)) {
		return STEP_COLLISION;
	}
	else {
		for(list<VectorXd>::iterator it = intermediatePoints.begin(); it != intermediatePoints.end(); it++) {
			NNidx = addNode(*it, NNidx);
		}
		addNode(qnew, NNidx);
		return STEP_PROGRESS;
	}
}

// Provides a hook for child classes to alter a new config before it gets added to the tree
bool RRT::newConfig(list<VectorXd> &intermediatePoints, VectorXd &qnew, const VectorXd &qnear, const VectorXd &qtarget) {
	return !checkCollisions(qnew);
}

int RRT::addNode(const VectorXd &qnew, int parentId)
{
	// Update graph vectors
	configVector.push_back(qnew);
	parentVector.push_back(parentId);

	uintptr_t id = configVector.size() - 1;
	index.addPoints(flann::Matrix<double>((double*)qnew.data(), 1, qnew.size()));

	activeNode = id;
	return id;
}

inline int RRT::getNearestNeighbor(const VectorXd &qsamp)
{
	int nearest;
	double distance;
	flann::Matrix<int> nearestMatrix(&nearest, 1, 1);
	index.knnSearch(flann::Matrix<double>((double*)qsamp.data(), 1, qsamp.size()),
		nearestMatrix, flann::Matrix<double>(&distance, 1, 1), 1, flann::SearchParams(flann::FLANN_CHECKS_UNLIMITED));
	activeNode = nearest;
	return nearest;
}

// random # between min & max
inline double RRT::randomInRange(double min, double max) {
	if(min == max) {
		return min;
	}
	return min + ((max-min) * ((double)rand() / ((double)RAND_MAX + 1)));
}

VectorXd RRT::getRandomConfig()
{
	/*
	 * Samples a random point for qtmp in the configuration space,
	 * bounded by the provided configuration vectors (and returns ref to it)
	 */
	VectorXd config(ndim);
	for (int i = 0; i < ndim; ++i) {
		config[i] = randomInRange(world->getRobot(robot)->getDof(dofs[i])->getMin(), world->getRobot(robot)->getDof(dofs[i])->getMax());
	}
	return config;
}

double RRT::getGap(const VectorXd &target) {
	return (target - configVector[activeNode]).norm();
}

void RRT::tracePath(int node, std::list<VectorXd> &path, bool reverse)
{
	int x = node;

	while(x != -1) {
		if(!reverse) {
			path.push_front(configVector[x]);
		}
		else {
			path.push_back(configVector[x]);
		}
		x = parentVector[x];
	}
}

bool RRT::checkCollisions(const VectorXd &c)
{
	world->getRobot(robot)->setDofs(c, dofs);
	return world->checkCollision();
}

unsigned int RRT::getSize() {
	return configVector.size();
}

}<|endoftext|>


<commit_before>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2008 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "Shape.h"

#include "../base/Logger.h"
#include "../base/Exception.h"

#include "../graphics/Filterfliprgb.h"

#include "OGLTiledSurface.h"
#include "SDLDisplayEngine.h"

#include <Magick++.h>

#include <iostream>
#include <sstream>

using namespace std;

namespace avg {

Shape::Shape(const string& sFilename, int texWrapSMode, int texWrapTMode)
    : Image(sFilename, false),
      m_TexID(-1),
      m_TexWrapSMode(texWrapSMode),
      m_TexWrapTMode(texWrapTMode)
{
}

Shape::~Shape()
{
    if (getState() == GPU) {
        deleteTexture();
    }
}

void Shape::setBitmap(const Bitmap* pBmp)
{
    State prevState = getState();
    Image::setBitmap(pBmp);
    if (getState() == GPU) {
        downloadTexture();
        if (prevState != GPU) {
            m_pVertexArray = VertexArrayPtr(new VertexArray(0, 0, 100, 100));
        }
    }
}

void Shape::moveToGPU(SDLDisplayEngine* pEngine)
{
    Image::moveToGPU(pEngine);
    if (getState() == GPU) {
        downloadTexture();
    }
    m_pVertexArray = VertexArrayPtr(new VertexArray(0, 0, 100, 100));
}

void Shape::moveToCPU()
{
    m_pVertexArray = VertexArrayPtr();
    Image::moveToCPU();
}

VertexArrayPtr Shape::getVertexArray()
{
    return m_pVertexArray;
}

void Shape::draw()
{
    bool bIsTextured = (getState() == GPU);
    if (bIsTextured) {
        glproc::ActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, m_TexID);
    }
    getEngine()->enableTexture(bIsTextured);
    getEngine()->enableGLColorArray(!bIsTextured);
    m_pVertexArray->draw();
}

void Shape::downloadTexture()
{
    PixelFormat pf = getPixelFormat();
    IntPoint size = getSize();
    SDLDisplayEngine* pEngine = getEngine();

    m_TexID = pEngine->createTexture(size, pf);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_TexWrapSMode);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_TexWrapTMode);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "Shape::downloadTexture: glTexParameteri()");

    OGLSurface* pSurface = getSurface();
    unsigned char * pPixels;
    if (pSurface->getMemMode() == OGL) {
        pPixels = pSurface->getBmp()->getPixels();
    } else {
        pPixels = 0;
        pSurface->bindPBO();
    }
    glBindTexture(GL_TEXTURE_2D, m_TexID);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL,
            "VectorNode::downloadTexture: glBindTexture()");
    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size.x, size.y,
            pEngine->getOGLSrcMode(pf), pEngine->getOGLPixelType(pf), pPixels);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL,
            "VectorNode::downloadTexture: glTexSubImage2D()");
    if (pSurface->getMemMode() == PBO) {
        pSurface->unbindPBO();
    }
}

void Shape::deleteTexture()
{
    glDeleteTextures(1, &m_TexID);
}

}
<commit_msg>Fixed memory leak in Shape::setBitmap().<commit_after>//
//  libavg - Media Playback Engine.
//  Copyright (C) 2003-2008 Ulrich von Zadow
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Current versions can be found at www.libavg.de
//

#include "Shape.h"

#include "../base/Logger.h"
#include "../base/Exception.h"

#include "../graphics/Filterfliprgb.h"

#include "OGLTiledSurface.h"
#include "SDLDisplayEngine.h"

#include <Magick++.h>

#include <iostream>
#include <sstream>

using namespace std;

namespace avg {

Shape::Shape(const string& sFilename, int texWrapSMode, int texWrapTMode)
    : Image(sFilename, false),
      m_TexID(-1),
      m_TexWrapSMode(texWrapSMode),
      m_TexWrapTMode(texWrapTMode)
{
}

Shape::~Shape()
{
    deleteTexture();
}

void Shape::setBitmap(const Bitmap* pBmp)
{
    deleteTexture();
    State prevState = getState();
    Image::setBitmap(pBmp);
    if (getState() == GPU) {
        downloadTexture();
        if (prevState != GPU) {
            m_pVertexArray = VertexArrayPtr(new VertexArray(0, 0, 100, 100));
        }
    }
}

void Shape::moveToGPU(SDLDisplayEngine* pEngine)
{
    Image::moveToGPU(pEngine);
    if (getState() == GPU) {
        downloadTexture();
    }
    m_pVertexArray = VertexArrayPtr(new VertexArray(0, 0, 100, 100));
}

void Shape::moveToCPU()
{
    m_pVertexArray = VertexArrayPtr();
    Image::moveToCPU();
}

VertexArrayPtr Shape::getVertexArray()
{
    return m_pVertexArray;
}

void Shape::draw()
{
    bool bIsTextured = (getState() == GPU);
    if (bIsTextured) {
        glproc::ActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, m_TexID);
    }
    getEngine()->enableTexture(bIsTextured);
    getEngine()->enableGLColorArray(!bIsTextured);
    m_pVertexArray->draw();
}

void Shape::downloadTexture()
{
    PixelFormat pf = getPixelFormat();
    IntPoint size = getSize();
    SDLDisplayEngine* pEngine = getEngine();

    m_TexID = pEngine->createTexture(size, pf);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, m_TexWrapSMode);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, m_TexWrapTMode);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL, "Shape::downloadTexture: glTexParameteri()");

    OGLSurface* pSurface = getSurface();
    unsigned char * pPixels;
    if (pSurface->getMemMode() == OGL) {
        pPixels = pSurface->getBmp()->getPixels();
    } else {
        pPixels = 0;
        pSurface->bindPBO();
    }
    glBindTexture(GL_TEXTURE_2D, m_TexID);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL,
            "VectorNode::downloadTexture: glBindTexture()");
    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size.x, size.y,
            pEngine->getOGLSrcMode(pf), pEngine->getOGLPixelType(pf), pPixels);
    OGLErrorCheck(AVG_ERR_VIDEO_GENERAL,
            "VectorNode::downloadTexture: glTexSubImage2D()");
    if (pSurface->getMemMode() == PBO) {
        pSurface->unbindPBO();
    }
}

void Shape::deleteTexture()
{
    if (m_TexID != -1) {
        glDeleteTextures(1, &m_TexID);
    }
}

}
<|endoftext|>


<commit_before>// MIT License

// Copyright (c) 2018 Zhuhao Wang

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include <boost/assert.hpp>

#include "nekit/proxy_manager.h"
#include "nekit/utils/log.h"

namespace nekit {
void ProxyManager::SetRuleManager(
    std::unique_ptr<rule::RuleManager> &&rule_manager) {
  BOOST_VERIFY(CheckOrSetIo(rule_manager.get()));

  rule_manager_ = std::move(rule_manager);
}

void ProxyManager::SetResolver(
    std::unique_ptr<utils::ResolverInterface> &&resolver) {
  BOOST_VERIFY(CheckOrSetIo(resolver.get()));

  resolver_ = std::move(resolver);
}

void ProxyManager::AddListener(
    std::unique_ptr<transport::ListenerInterface> &&listener) {
  BOOST_VERIFY(CheckOrSetIo(listener.get()));

  listeners_.emplace_back(std::move(listener));
}

void ProxyManager::Run() {
  BOOST_ASSERT(rule_manager_);
  BOOST_ASSERT(resolver_);
  BOOST_ASSERT(listeners_.size());

  auto handler =
      [this](std::unique_ptr<data_flow::LocalDataFlowInterface> &&data_flow,
             std::error_code ec) {
        if (ec) {
          NEERROR << "Error happened when accepting new socket " << ec;
          exit(1);
        }

        tunnel_manager_.Build(std::move(data_flow), rule_manager_.get()).Open();
      };

  for (auto &listener : listeners_) {
    listener->Accept(handler);
  }
}

void ProxyManager::Stop() {
  resolver_->Stop();

  for (auto &listener : listeners_) {
    listener->Close();
  }
}

void ProxyManager::Reset() { resolver_->Reset(); }

boost::asio::io_context *ProxyManager::io() { return io_; }

bool ProxyManager::CheckOrSetIo(utils::AsyncIoInterface *io_interface) {
  if (!io_) {
    io_ = io_interface->io();
    return true;
  }

  return io_ == io_interface->io();
}

}  // namespace nekit
<commit_msg>FEAT: Bind resolver to session<commit_after>// MIT License

// Copyright (c) 2018 Zhuhao Wang

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include <boost/assert.hpp>

#include "nekit/proxy_manager.h"
#include "nekit/utils/log.h"

namespace nekit {
void ProxyManager::SetRuleManager(
    std::unique_ptr<rule::RuleManager> &&rule_manager) {
  BOOST_VERIFY(CheckOrSetIo(rule_manager.get()));

  rule_manager_ = std::move(rule_manager);
}

void ProxyManager::SetResolver(
    std::unique_ptr<utils::ResolverInterface> &&resolver) {
  BOOST_VERIFY(CheckOrSetIo(resolver.get()));

  resolver_ = std::move(resolver);
}

void ProxyManager::AddListener(
    std::unique_ptr<transport::ListenerInterface> &&listener) {
  BOOST_VERIFY(CheckOrSetIo(listener.get()));

  listeners_.emplace_back(std::move(listener));
}

void ProxyManager::Run() {
  BOOST_ASSERT(rule_manager_);
  BOOST_ASSERT(resolver_);
  BOOST_ASSERT(listeners_.size());

  auto handler =
      [this](std::unique_ptr<data_flow::LocalDataFlowInterface> &&data_flow,
             std::error_code ec) {
        if (ec) {
          NEERROR << "Error happened when accepting new socket " << ec;
          exit(1);
        }

        data_flow->Session()->set_resolver(resolver_.get());

        tunnel_manager_.Build(std::move(data_flow), rule_manager_.get()).Open();
      };

  for (auto &listener : listeners_) {
    listener->Accept(handler);
  }
}

void ProxyManager::Stop() {
  resolver_->Stop();

  for (auto &listener : listeners_) {
    listener->Close();
  }
}

void ProxyManager::Reset() { resolver_->Reset(); }

boost::asio::io_context *ProxyManager::io() { return io_; }

bool ProxyManager::CheckOrSetIo(utils::AsyncIoInterface *io_interface) {
  if (!io_) {
    io_ = io_interface->io();
    return true;
  }

  return io_ == io_interface->io();
}

}  // namespace nekit
<|endoftext|>


<commit_before>/* Copyright (c) 2012 QtHttpServer Project.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the QtHttpServer 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 QTHTTPSERVER 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.
 */

#include "qhttprequest.h"

#include <QtCore/QUrl>
#include <QtNetwork/QHostAddress>
#include <QtNetwork/QNetworkCookie>

#include "qhttpconnection_p.h"

class QHttpFileData::Private
{
public:
    QString fileName;
    QString contentType;
    QByteArray data;
};

QHttpFileData::QHttpFileData(const QHash<QByteArray, QByteArray> &rawHeaders, const QByteArray &data, QObject *parent)
    : QBuffer(parent)
    , d(new Private)
{
    if (rawHeaders.contains("Content-Type")) {
        d->contentType = QString::fromUtf8(rawHeaders.value("Content-Type"));
    }
    if (rawHeaders.contains("Content-Disposition")) {
        QByteArray contentDisposition = rawHeaders.value("Content-Disposition");
        contentDisposition = contentDisposition.mid(contentDisposition.indexOf("filename=\"") + 10);
        contentDisposition.chop(1);
        d->fileName = QString::fromUtf8(contentDisposition);
    }
    d->data = data;
    setBuffer(&d->data);
    open(QIODevice::ReadOnly);
}

QHttpFileData::~QHttpFileData()
{
    delete d;
}

const QString &QHttpFileData::fileName() const
{
    return d->fileName;
}

const QString &QHttpFileData::contentType() const
{
    return d->contentType;
}

class QHttpRequest::Private : public QObject
{
    Q_OBJECT
public:
    enum ReadState {
        ReadUrl
        , ReadHeaders
        , ReadBody
        , MultipartHeader
        , MultipartBody
        , ReadDone
    };

    Private(QHttpConnection *c, QHttpRequest *parent);

private slots:
    void readyRead();
    void disconnected();

private:
    QHttpRequest *q;

public:
    QHttpConnection *connection;
    QString remoteAddress;
    ReadState state;
    QByteArray method;
    QUrl url;
    QHash<QByteArray, QByteArray> rawHeaders;
    QList<QNetworkCookie> cookies;
    QByteArray data;
    QByteArray multipartBoundary;
    QList<QHttpFileData *> files;
};

QHttpRequest::Private::Private(QHttpConnection *c, QHttpRequest *parent)
    : QObject(parent)
    , q(parent)
    , connection(c)
    , state(ReadUrl)
{
    remoteAddress = connection->peerAddress().toString();
    connect(connection, SIGNAL(readyRead()), this, SLOT(readyRead()));
    connect(connection, SIGNAL(disconnected()), this, SLOT(disconnected()));
    q->setBuffer(&data);
    q->open(QIODevice::ReadOnly);
    QMetaObject::invokeMethod(this, "readyRead", Qt::QueuedConnection);
}

void QHttpRequest::Private::readyRead()
{
    switch (state) {
    case ReadUrl:
        if (connection->canReadLine()) {
            QByteArray line = connection->readLine();
            line = line.left(line.length() - 2);
            QList<QByteArray> array = line.split(' ');

            method = array.takeFirst();

            QString path = QString::fromUtf8(array.takeFirst());
            url.setPath(path.section('?', 0, 0));
            url.setQuery(path.section('?', 1));
            url.setScheme(QLatin1String("http"));

            QByteArray http = array.takeFirst();
            if (http != "HTTP/1.1" && http != "HTTP/1.0") {
                qWarning() << http << "is not supported.";
                connection->disconnectFromHost();
                return;
            }
            state = ReadHeaders;
        }
//        break;
    case ReadHeaders:
        while (connection->canReadLine()) {
            QByteArray line = connection->readLine();
            line = line.left(line.length() - 2);
            if (line.isEmpty()) {
                if (!q->hasRawHeader("Content-Length")) {
                    state = ReadDone;
                    disconnect(connection, SIGNAL(readyRead()), this, SLOT(readyRead()));
                    emit q->ready();
                } else {
                    state = ReadBody;
                    QMetaObject::invokeMethod(this, "readyRead", Qt::QueuedConnection);
                }
                break;
            }

            int space = line.indexOf(' ');
            if (space > 0) {
                QByteArray name = line.left(space - 1);
                QByteArray value = line.mid(space + 1);
                if (name == "Upgrade") {
                    disconnect(connection, 0, this, 0);
                    emit q->upgrade(value, url, rawHeaders);
                    return;
                } else if (name == "Host") {
                    int colon = value.indexOf(':');
                    if (colon > -1) {
                        url.setHost(QString::fromUtf8(value.left(colon)));
                        url.setPort(value.mid(colon + 1).toUInt());
                    } else {
                        url.setHost(QString::fromUtf8(value));
                        url.setPort(80);
                    }
                } else if (name == "Cookie") {
                    foreach (const QByteArray &c, value.split(';')) {
                        cookies.append(QNetworkCookie::parseCookies(c));
                    }
                } else if (name == "Content-Type") {
                    QList<QByteArray> fields = value.split(';');
                    QByteArray boundary(" boundary=");
                    if (fields.first().toLower() == "multipart/form-data" && fields.length() == 2 && fields.at(1).startsWith(boundary)) {
                        rawHeaders.insert(name.toLower(), fields.takeFirst().toLower());
                        multipartBoundary = fields.takeFirst().mid(boundary.length());
                        multipartBoundary.prepend("--");
                    } else {
                        rawHeaders.insert(name.toLower(), value);
                    }
                } else {
                    rawHeaders.insert(name.toLower(), value);
                }
            }
        }
        break;
    case ReadBody:
        if (q->hasRawHeader("Content-Length")) {
            int length = q->rawHeader("Content-Length").toLongLong();
            data.append(connection->read(length - data.length()));
            if (data.length() == length) {
                QHash<QByteArray, QByteArray> multipartRawHeaders;
                QByteArray multipartData;
                if (!multipartBoundary.isEmpty()) {
                    QByteArray newData;
                    foreach (QByteArray ba, data.split('\n')) {
                        switch (state) {
                        case ReadBody:
                            ba.chop(1); // \r
                            if (ba == multipartBoundary) {
                                state = MultipartHeader;
                            } else {
                                qWarning() << Q_FUNC_INFO << __LINE__ << ba << multipartBoundary;
                            }
                            break;
                        case MultipartHeader:
                            ba.chop(1); // \r
                            if (ba.isEmpty()) {
                                state = MultipartBody;
                            } else {
                                int i = ba.indexOf(':');
                                multipartRawHeaders.insert(ba.left(i), ba.mid(i + 2));
                            }
                            break;
                        case MultipartBody:
                            if (ba.startsWith(multipartBoundary)) {
                                ba.chop(1); // \r
                                if (multipartRawHeaders.contains("Content-Type")) {
                                    files.append(new QHttpFileData(multipartRawHeaders, multipartData, this));
                                } else {
                                    QByteArray name = multipartRawHeaders.value("Content-Disposition").split('=').at(1);
                                    name = name.mid(1, name.length() - 2);
                                    if (!newData.isEmpty()) {
                                        newData.append("&");
                                    }
                                    newData.append(name);
                                    newData.append("=");
                                    multipartData.chop(2);
                                    newData.append(multipartData);
                                }
                                multipartRawHeaders.clear();
                                multipartData.clear();
                                if (ba.endsWith("--")) {
                                    data = newData;
                                    state = ReadDone;
                                } else {
                                    state = MultipartHeader;
                                }
                            } else if (ba != "\r") {
                                multipartData.append(ba);
                                multipartData.append("\n");
                            }
                            break;
                        default:
                            break;
                        }
                    }
                }
                state = ReadDone;
                emit q->ready();
            }
        }
        break;
    default:
        break;
    }
}

void QHttpRequest::Private::disconnected()
{
    q->deleteLater();
}

QHttpRequest::QHttpRequest(QHttpConnection *parent)
    : QBuffer(parent)
    , d(new Private(parent, this))
{
}

const QString &QHttpRequest::remoteAddress() const
{
    return d->remoteAddress;
}

const QByteArray &QHttpRequest::method() const
{
    return d->method;
}

bool QHttpRequest::hasRawHeader(const QByteArray &headerName) const
{
    return d->rawHeaders.contains(headerName.toLower());
}

QByteArray QHttpRequest::rawHeader(const QByteArray &headerName) const
{
    return d->rawHeaders.value(headerName.toLower());
}

QList<QByteArray> QHttpRequest::rawHeaderList() const
{
    return d->rawHeaders.keys();
}

const QList<QNetworkCookie> &QHttpRequest::cookies() const
{
    return d->cookies;
}

const QList<QHttpFileData *> &QHttpRequest::files() const
{
    return d->files;
}

const QUrl &QHttpRequest::url() const
{
    return d->url;
}

#include "qhttprequest.moc"
<commit_msg>not add empty file to uploaded files<commit_after>/* Copyright (c) 2012 QtHttpServer Project.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the QtHttpServer 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 QTHTTPSERVER 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.
 */

#include "qhttprequest.h"

#include <QtCore/QUrl>
#include <QtNetwork/QHostAddress>
#include <QtNetwork/QNetworkCookie>

#include "qhttpconnection_p.h"

class QHttpFileData::Private
{
public:
    QString fileName;
    QString contentType;
    QByteArray data;
};

QHttpFileData::QHttpFileData(const QHash<QByteArray, QByteArray> &rawHeaders, const QByteArray &data, QObject *parent)
    : QBuffer(parent)
    , d(new Private)
{
    if (rawHeaders.contains("Content-Type")) {
        d->contentType = QString::fromUtf8(rawHeaders.value("Content-Type"));
    }
    if (rawHeaders.contains("Content-Disposition")) {
        QByteArray contentDisposition = rawHeaders.value("Content-Disposition");
        contentDisposition = contentDisposition.mid(contentDisposition.indexOf("filename=\"") + 10);
        contentDisposition.chop(1);
        d->fileName = QString::fromUtf8(contentDisposition);
    }
    d->data = data;
    setBuffer(&d->data);
    open(QIODevice::ReadOnly);
}

QHttpFileData::~QHttpFileData()
{
    delete d;
}

const QString &QHttpFileData::fileName() const
{
    return d->fileName;
}

const QString &QHttpFileData::contentType() const
{
    return d->contentType;
}

class QHttpRequest::Private : public QObject
{
    Q_OBJECT
public:
    enum ReadState {
        ReadUrl
        , ReadHeaders
        , ReadBody
        , MultipartHeader
        , MultipartBody
        , ReadDone
    };

    Private(QHttpConnection *c, QHttpRequest *parent);

private slots:
    void readyRead();
    void disconnected();

private:
    QHttpRequest *q;

public:
    QHttpConnection *connection;
    QString remoteAddress;
    ReadState state;
    QByteArray method;
    QUrl url;
    QHash<QByteArray, QByteArray> rawHeaders;
    QList<QNetworkCookie> cookies;
    QByteArray data;
    QByteArray multipartBoundary;
    QList<QHttpFileData *> files;
};

QHttpRequest::Private::Private(QHttpConnection *c, QHttpRequest *parent)
    : QObject(parent)
    , q(parent)
    , connection(c)
    , state(ReadUrl)
{
    remoteAddress = connection->peerAddress().toString();
    connect(connection, SIGNAL(readyRead()), this, SLOT(readyRead()));
    connect(connection, SIGNAL(disconnected()), this, SLOT(disconnected()));
    q->setBuffer(&data);
    q->open(QIODevice::ReadOnly);
    QMetaObject::invokeMethod(this, "readyRead", Qt::QueuedConnection);
}

void QHttpRequest::Private::readyRead()
{
    switch (state) {
    case ReadUrl:
        if (connection->canReadLine()) {
            QByteArray line = connection->readLine();
            line = line.left(line.length() - 2);
            QList<QByteArray> array = line.split(' ');

            method = array.takeFirst();

            QString path = QString::fromUtf8(array.takeFirst());
            url.setPath(path.section('?', 0, 0));
            url.setQuery(path.section('?', 1));
            url.setScheme(QLatin1String("http"));

            QByteArray http = array.takeFirst();
            if (http != "HTTP/1.1" && http != "HTTP/1.0") {
                qWarning() << http << "is not supported.";
                connection->disconnectFromHost();
                return;
            }
            state = ReadHeaders;
        }
//        break;
    case ReadHeaders:
        while (connection->canReadLine()) {
            QByteArray line = connection->readLine();
            line = line.left(line.length() - 2);
            if (line.isEmpty()) {
                if (!q->hasRawHeader("Content-Length")) {
                    state = ReadDone;
                    disconnect(connection, SIGNAL(readyRead()), this, SLOT(readyRead()));
                    emit q->ready();
                } else {
                    state = ReadBody;
                    QMetaObject::invokeMethod(this, "readyRead", Qt::QueuedConnection);
                }
                break;
            }

            int space = line.indexOf(' ');
            if (space > 0) {
                QByteArray name = line.left(space - 1);
                QByteArray value = line.mid(space + 1);
                if (name == "Upgrade") {
                    disconnect(connection, 0, this, 0);
                    emit q->upgrade(value, url, rawHeaders);
                    return;
                } else if (name == "Host") {
                    int colon = value.indexOf(':');
                    if (colon > -1) {
                        url.setHost(QString::fromUtf8(value.left(colon)));
                        url.setPort(value.mid(colon + 1).toUInt());
                    } else {
                        url.setHost(QString::fromUtf8(value));
                        url.setPort(80);
                    }
                } else if (name == "Cookie") {
                    foreach (const QByteArray &c, value.split(';')) {
                        cookies.append(QNetworkCookie::parseCookies(c));
                    }
                } else if (name == "Content-Type") {
                    QList<QByteArray> fields = value.split(';');
                    QByteArray boundary(" boundary=");
                    if (fields.first().toLower() == "multipart/form-data" && fields.length() == 2 && fields.at(1).startsWith(boundary)) {
                        rawHeaders.insert(name.toLower(), fields.takeFirst().toLower());
                        multipartBoundary = fields.takeFirst().mid(boundary.length());
                        multipartBoundary.prepend("--");
                    } else {
                        rawHeaders.insert(name.toLower(), value);
                    }
                } else {
                    rawHeaders.insert(name.toLower(), value);
                }
            }
        }
        break;
    case ReadBody:
        if (q->hasRawHeader("Content-Length")) {
            int length = q->rawHeader("Content-Length").toLongLong();
            data.append(connection->read(length - data.length()));
            if (data.length() == length) {
                QHash<QByteArray, QByteArray> multipartRawHeaders;
                QByteArray multipartData;
                if (!multipartBoundary.isEmpty()) {
                    QByteArray newData;
                    foreach (QByteArray ba, data.split('\n')) {
                        switch (state) {
                        case ReadBody:
                            ba.chop(1); // \r
                            if (ba == multipartBoundary) {
                                state = MultipartHeader;
                            } else {
                                qWarning() << Q_FUNC_INFO << __LINE__ << ba << multipartBoundary;
                            }
                            break;
                        case MultipartHeader:
                            ba.chop(1); // \r
                            if (ba.isEmpty()) {
                                state = MultipartBody;
                            } else {
                                int i = ba.indexOf(':');
                                multipartRawHeaders.insert(ba.left(i), ba.mid(i + 2));
                            }
                            break;
                        case MultipartBody:
                            if (ba.startsWith(multipartBoundary)) {
                                ba.chop(1); // \r
                                if (multipartRawHeaders.contains("Content-Type")) {
                                    if (multipartData.size() > 0
                                            && multipartRawHeaders.contains("Content-Disposition")
                                            && !rawHeaders.value("Content-Disposition").contains("filename=\"\"")) {
                                        files.append(new QHttpFileData(multipartRawHeaders, multipartData, this));
                                    }
                                } else {
                                    QByteArray name = multipartRawHeaders.value("Content-Disposition").split('=').at(1);
                                    name = name.mid(1, name.length() - 2);
                                    if (!newData.isEmpty()) {
                                        newData.append("&");
                                    }
                                    newData.append(name);
                                    newData.append("=");
                                    multipartData.chop(2);
                                    newData.append(multipartData);
                                }
                                multipartRawHeaders.clear();
                                multipartData.clear();
                                if (ba.endsWith("--")) {
                                    data = newData;
                                    state = ReadDone;
                                } else {
                                    state = MultipartHeader;
                                }
                            } else if (ba != "\r") {
                                multipartData.append(ba);
                                multipartData.append("\n");
                            }
                            break;
                        default:
                            break;
                        }
                    }
                }
                state = ReadDone;
                emit q->ready();
            }
        }
        break;
    default:
        break;
    }
}

void QHttpRequest::Private::disconnected()
{
    q->deleteLater();
}

QHttpRequest::QHttpRequest(QHttpConnection *parent)
    : QBuffer(parent)
    , d(new Private(parent, this))
{
}

const QString &QHttpRequest::remoteAddress() const
{
    return d->remoteAddress;
}

const QByteArray &QHttpRequest::method() const
{
    return d->method;
}

bool QHttpRequest::hasRawHeader(const QByteArray &headerName) const
{
    return d->rawHeaders.contains(headerName.toLower());
}

QByteArray QHttpRequest::rawHeader(const QByteArray &headerName) const
{
    return d->rawHeaders.value(headerName.toLower());
}

QList<QByteArray> QHttpRequest::rawHeaderList() const
{
    return d->rawHeaders.keys();
}

const QList<QNetworkCookie> &QHttpRequest::cookies() const
{
    return d->cookies;
}

const QList<QHttpFileData *> &QHttpRequest::files() const
{
    return d->files;
}

const QUrl &QHttpRequest::url() const
{
    return d->url;
}

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


<commit_before>#include "rendersystem.h"
#include "componentmanager.h"
#include "rendercomponent.h"
#include "movecomponent.h"
#include "sizecomponent.h"
#include <iostream>
#include "spatialindexer.h"
#include "flagcomponent.h"
#include "heap.h"
#include "dynamicarray.h"
#include "heapsort.h"
#include <queue>

using namespace std;

bool RenderData::operator< (const RenderData& rhs) const {
	//RenderData is first ordered by zindex_base and if the bases are equal then zindex
	//{zindex_base, zindex}
	//{6, 4.9} is greater than {5, 5.0}
	//{5, 5.0} is equal to {5, 5.0}
	//{5, 4.9] is less than {5, 5.0}
	if(renderComponent->zindex_base == rhs.renderComponent->zindex_base) {
		return renderComponent->zindex < rhs.renderComponent->zindex;
	} else {
		return renderComponent->zindex_base < rhs.renderComponent->zindex_base;
	}
}

bool RenderData::operator> (const RenderData& rhs) const { return rhs < *this; }
bool RenderData::operator<=(const RenderData& rhs) const { return !(*this > rhs); }
bool RenderData::operator>=(const RenderData& rhs) const { return !(*this < rhs); }

RenderSystem::RenderSystem(SpatialIndexer* spatialIndexer)
    : spatialIndexer(spatialIndexer) {
	//Initialize SDL
    if(SDL_Init(SDL_INIT_VIDEO) < 0)
    {
        cout << "ERROR: SDL could not initialize! SDL_Error: " << SDL_GetError() << endl;
    } else {
        window = SDL_CreateWindow(
            "SDL Tutorial",
            SDL_WINDOWPOS_UNDEFINED,
            SDL_WINDOWPOS_UNDEFINED,
            SCREEN_WIDTH,
            SCREEN_HEIGHT,
            SDL_WINDOW_SHOWN);

        if(!window) {
            cout << "ERROR: Window could not be created! SDL_Error: " << SDL_GetError() << endl;
        } else {
            renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
            if(!renderer) {
                cout << "ERROR: Renderer could not be created! SDL_Error: " << SDL_GetError() << endl;
            } else {

				//imgFlags is used to initialize PNG-loading
				//so that IMG_Load can be used instead of SDL_LoadBMP
				int imgFlags = IMG_INIT_PNG;
				if(!(IMG_Init(imgFlags) & imgFlags)) {
					cout << "ERROR: Couldnt initialze PNG usage!" << endl;
				} else {

		            SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xFF);

			        targetTexture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, SCREEN_WIDTH, SCREEN_HEIGHT);
					SDL_SetRenderTarget(renderer, targetTexture);
					SDL_RenderClear(renderer);
				}
            }
        }
    }

    //We want to access surfaces by their image path later on, so store paths right away
    for(auto path :{
            "./resources/images/HelloWorld.bmp",
            "./resources/images/player.bmp",
            "./resources/images/grass.bmp",
			"./resources/images/SmallTree.png",
            }
        )
    {
        SDL_Surface* rawImage = IMG_Load(path);
        if(!rawImage) {
            cout << "ERROR: Couldn't load image on: " << path << endl;
        } else {
            //Make purple parts of images transparent by using color keying
            SDL_SetColorKey(rawImage, SDL_TRUE, SDL_MapRGB( rawImage->format, 0xFF, 0x00, 0xFF ));
            SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, rawImage);
            if(!texture) {
                cout << "ERROR: Couldn't convert surface on addr " << rawImage << " to texture! SDL_Error: " << SDL_GetError() << endl;
            } else {
                SDL_FreeSurface(rawImage);
                int w, h;
                SDL_QueryTexture(texture, NULL, NULL, &w, &h);
                textureDatas.insert(
                    make_pair(
                        path,
                        TextureData{
                            texture,
                            w,
                            h
                        }
                    )
                );
            }
        }
    }
}

RenderSystem::~RenderSystem() {
    //Free all loaded images
    for(auto textureData : textureDatas) {
        SDL_DestroyTexture(get<1>(textureData).texture);
    }

    SDL_DestroyTexture(targetTexture);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();
}

void RenderSystem::add(unsigned long long int* id) {
	renderDatas.insert(
        make_pair(
            id,
            RenderData{
                componentManager->renderComponents.at(id),
                componentManager->moveComponents.at(id),
				componentManager->sizeComponents.at(id),
				componentManager->flagComponents.at(id),
            }
        )
    );
	ids.add(id);
}

void RenderSystem::remove(unsigned long long int* id) {
	if(id == nullptr) {
		cout << "WARNING: No id on adress: " << id << endl;
		return;
	}
	if(renderDatas.erase(id) == 0) {
		cout << "WARNING: RenderSystem tried to erase unpresent ID " << *id << ", segfault inc!" << endl;
	}
	ids.remove(id);
}

void RenderSystem::update() {

	//Bellow is an algorithm that for each unmarked entity, that should be rendered,
	//adds it to a priority-queue (pq) and a queue (q).
	//Aslong as q isn't empty, pop an entity (e) from q. For all entities overlapping e,
	//add them to the pq and q, finally mark the overlapping entities.

	//In other words this algorithm adds all entities that should be rendered to a list.
	//An entity should be rendered whenever it is overlapped/overlapping another entity
	//that should be rendered (one entity that is set to be rendered might cause a group
	//of nearby, pairwise, overlapping entities to be redrawn to in order to maintain correct
	//z-order

	unsigned int count = ids.getSize();
	bool marked[100000] {false}; //TODO: Make less arbitrary, somehow..
	queue<unsigned long long int*> q;
	heap<RenderData> pq; //TODO: Use reference instead (no need for copying!)

	//For all ids in rendersystem
	for(auto& id : ids){

		//Always make force textureData to be up-to-date with the image at rendercomponent
		auto& rc = componentManager->renderComponents.at(id);
		rc->textureData = textureDatas.at(rc->imagePath);

		//if all ids havnt been added already
		//and either HAS_CHANGED or doRender is true
		//and the current id hasnt been targeted for rendering
		//then add the id pq of renderdatas to be rendered
		//and put id in the list
		//finally mark it
		if(count != 0 && (componentManager->flagComponents.at(id)->flags & FlagComponent::HAS_CHANGED
				|| renderDatas.at(id).renderComponent->doRender)
				&& !marked[*id]) {

			q.push(id);
			pq.insert(renderDatas.at(id));
			marked[*id] = true;
            componentManager->renderComponents.at(id)->doRender = true;
			count--;

			//as long as list isnt empty and all ids havnt been added already
			//erase an id from the list and add overlapping ids into the pq of
			//renderdatas, and also put them in the list. Mark them.
			while(!q.empty() && count != 0) {
				unsigned long long int* cur = q.back(); q.pop();
				unordered_set<ID> curOverlaps;
				spatialIndexer->overlaps(curOverlaps, cur);
				for(auto overlap : curOverlaps) {
					if(!marked[*overlap] && count != 0) {
						q.push(overlap);
						pq.insert(renderDatas.at(overlap));
						marked[*overlap] = true;
						componentManager->renderComponents.at(overlap)->doRender = true;
						count--;
					}
				}
			}
		}
	}

	while(!pq.isEmpty()) {
		RenderData data = pq.poll();
		render(data);
	}

    SDL_SetRenderTarget(renderer, NULL);
    SDL_RenderClear(renderer);
    SDL_RenderCopy(renderer, targetTexture, NULL, NULL);
	SDL_RenderPresent(renderer);
}

unsigned int RenderSystem::count() const {
	return renderDatas.size();
}

void RenderSystem::render(const RenderData& data) const {
    //render if component wants to be re-rendered
    if(data.renderComponent->doRender) {
        TextureData textureData;
        try {
            textureData = textureDatas.at(data.renderComponent->imagePath);
        } catch (const std::out_of_range &oor) {
            cout << "out_of_range exception caught in SystemManager::getSystem(string identifier): " << oor.what() << endl;
            cout << "1. Maybe there as a typo in the RenderComponent->imagePath, " << data.renderComponent->imagePath << "?" << endl;
            cout << "2. Maybe " << data.renderComponent->imagePath << " wasn't loaded by RenderSystem?" << endl;
            cout << "Things will go wrong from now on!" << endl;
        }

        SDL_Rect rect{
            (int)(data.moveComponent->xpos + data.renderComponent->xoffset),
            (int)(data.moveComponent->ypos + data.renderComponent->yoffset),
            textureData.width,
            textureData.height
        };

        //Render to target texture
        //the target texture in turn will be rendered ontop of default
        //the default is always cleared
        //SDL_RenderPresent invalidates current backbuffer, so hence this required
        //the targetTexture ISNT invalidated, whatever is rendered onto it it saved
        //so it's fine to just re-render the targetTexture
        SDL_SetTextureBlendMode(targetTexture, SDL_BLENDMODE_BLEND);
        SDL_SetRenderTarget(renderer, targetTexture);
        SDL_RenderCopy(renderer, textureDatas.at(data.renderComponent->imagePath).texture, NULL, &rect);

        //Finally, don't render this component until it says otherwise
        data.renderComponent->doRender = false;
    }
}

const string RenderSystem::getIdentifier() const {
	return "RenderSystem";
}

void RenderSystem::sort(RenderData* arr, const unsigned int size) const {
	//Sort the array by z-index

	//set zindex to be lowest y
	for(auto a : renderDatas) {
		get<1>(a).renderComponent->zindex = get<1>(a).moveComponent->ypos + get<1>(a).sizeComponent->height;
	}
	heapsort(arr, size);
}

<commit_msg>removed some warnings by explicit casting where its fine<commit_after>#include "rendersystem.h"
#include "componentmanager.h"
#include "rendercomponent.h"
#include "movecomponent.h"
#include "sizecomponent.h"
#include <iostream>
#include "spatialindexer.h"
#include "flagcomponent.h"
#include "heap.h"
#include "dynamicarray.h"
#include "heapsort.h"
#include <queue>

using namespace std;

bool RenderData::operator< (const RenderData& rhs) const {
	//RenderData is first ordered by zindex_base and if the bases are equal then zindex
	//{zindex_base, zindex}
	//{6, 4.9} is greater than {5, 5.0}
	//{5, 5.0} is equal to {5, 5.0}
	//{5, 4.9] is less than {5, 5.0}
	if(renderComponent->zindex_base == rhs.renderComponent->zindex_base) {
		return renderComponent->zindex < rhs.renderComponent->zindex;
	} else {
		return renderComponent->zindex_base < rhs.renderComponent->zindex_base;
	}
}

bool RenderData::operator> (const RenderData& rhs) const { return rhs < *this; }
bool RenderData::operator<=(const RenderData& rhs) const { return !(*this > rhs); }
bool RenderData::operator>=(const RenderData& rhs) const { return !(*this < rhs); }

RenderSystem::RenderSystem(SpatialIndexer* spatialIndexer)
    : spatialIndexer(spatialIndexer) {
	//Initialize SDL
    if(SDL_Init(SDL_INIT_VIDEO) < 0)
    {
        cout << "ERROR: SDL could not initialize! SDL_Error: " << SDL_GetError() << endl;
    } else {
        window = SDL_CreateWindow(
            "SDL Tutorial",
            SDL_WINDOWPOS_UNDEFINED,
            SDL_WINDOWPOS_UNDEFINED,
            SCREEN_WIDTH,
            SCREEN_HEIGHT,
            SDL_WINDOW_SHOWN);

        if(!window) {
            cout << "ERROR: Window could not be created! SDL_Error: " << SDL_GetError() << endl;
        } else {
            renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
            if(!renderer) {
                cout << "ERROR: Renderer could not be created! SDL_Error: " << SDL_GetError() << endl;
            } else {

				//imgFlags is used to initialize PNG-loading
				//so that IMG_Load can be used instead of SDL_LoadBMP
				int imgFlags = IMG_INIT_PNG;
				if(!(IMG_Init(imgFlags) & imgFlags)) {
					cout << "ERROR: Couldnt initialze PNG usage!" << endl;
				} else {

		            SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xFF);

			        targetTexture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, SCREEN_WIDTH, SCREEN_HEIGHT);
					SDL_SetRenderTarget(renderer, targetTexture);
					SDL_RenderClear(renderer);
				}
            }
        }
    }

    //We want to access surfaces by their image path later on, so store paths right away
    for(auto path :{
            "./resources/images/HelloWorld.bmp",
            "./resources/images/player.bmp",
            "./resources/images/grass.bmp",
			"./resources/images/SmallTree.png",
            }
        )
    {
        SDL_Surface* rawImage = IMG_Load(path);
        if(!rawImage) {
            cout << "ERROR: Couldn't load image on: " << path << endl;
        } else {
            //Make purple parts of images transparent by using color keying
            SDL_SetColorKey(rawImage, SDL_TRUE, SDL_MapRGB( rawImage->format, 0xFF, 0x00, 0xFF ));
            SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, rawImage);
            if(!texture) {
                cout << "ERROR: Couldn't convert surface on addr " << rawImage << " to texture! SDL_Error: " << SDL_GetError() << endl;
            } else {
                SDL_FreeSurface(rawImage);
                int w, h;
                SDL_QueryTexture(texture, NULL, NULL, &w, &h);
                textureDatas.insert(
                    make_pair(
                        path,
                        TextureData{
                            texture,
                            (unsigned int)w,
                            (unsigned int)h
                        }
                    )
                );
            }
        }
    }
}

RenderSystem::~RenderSystem() {
    //Free all loaded images
    for(auto textureData : textureDatas) {
        SDL_DestroyTexture(get<1>(textureData).texture);
    }

    SDL_DestroyTexture(targetTexture);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();
}

void RenderSystem::add(unsigned long long int* id) {
	renderDatas.insert(
        make_pair(
            id,
            RenderData{
                componentManager->renderComponents.at(id),
                componentManager->moveComponents.at(id),
				componentManager->sizeComponents.at(id),
				componentManager->flagComponents.at(id),
            }
        )
    );
	ids.add(id);
}

void RenderSystem::remove(unsigned long long int* id) {
	if(id == nullptr) {
		cout << "WARNING: No id on adress: " << id << endl;
		return;
	}
	if(renderDatas.erase(id) == 0) {
		cout << "WARNING: RenderSystem tried to erase unpresent ID " << *id << ", segfault inc!" << endl;
	}
	ids.remove(id);
}

void RenderSystem::update() {

	//Bellow is an algorithm that for each unmarked entity, that should be rendered,
	//adds it to a priority-queue (pq) and a queue (q).
	//Aslong as q isn't empty, pop an entity (e) from q. For all entities overlapping e,
	//add them to the pq and q, finally mark the overlapping entities.

	//In other words this algorithm adds all entities that should be rendered to a list.
	//An entity should be rendered whenever it is overlapped/overlapping another entity
	//that should be rendered (one entity that is set to be rendered might cause a group
	//of nearby, pairwise, overlapping entities to be redrawn to in order to maintain correct
	//z-order

	unsigned int count = ids.getSize();
	bool marked[100000] {false}; //TODO: Make less arbitrary, somehow..
	queue<unsigned long long int*> q;
	heap<RenderData> pq; //TODO: Use reference instead (no need for copying!)

	//For all ids in rendersystem
	for(auto& id : ids){

		//Always make force textureData to be up-to-date with the image at rendercomponent
		auto& rc = componentManager->renderComponents.at(id);
		rc->textureData = textureDatas.at(rc->imagePath);

		//if all ids havnt been added already
		//and either HAS_CHANGED or doRender is true
		//and the current id hasnt been targeted for rendering
		//then add the id pq of renderdatas to be rendered
		//and put id in the list
		//finally mark it
		if(count != 0 && (componentManager->flagComponents.at(id)->flags & FlagComponent::HAS_CHANGED
				|| renderDatas.at(id).renderComponent->doRender)
				&& !marked[*id]) {

			q.push(id);
			pq.insert(renderDatas.at(id));
			marked[*id] = true;
            componentManager->renderComponents.at(id)->doRender = true;
			count--;

			//as long as list isnt empty and all ids havnt been added already
			//erase an id from the list and add overlapping ids into the pq of
			//renderdatas, and also put them in the list. Mark them.
			while(!q.empty() && count != 0) {
				unsigned long long int* cur = q.back(); q.pop();
				unordered_set<ID> curOverlaps;
				spatialIndexer->overlaps(curOverlaps, cur);
				for(auto overlap : curOverlaps) {
					if(!marked[*overlap] && count != 0) {
						q.push(overlap);
						pq.insert(renderDatas.at(overlap));
						marked[*overlap] = true;
						componentManager->renderComponents.at(overlap)->doRender = true;
						count--;
					}
				}
			}
		}
	}

	while(!pq.isEmpty()) {
		RenderData data = pq.poll();
		render(data);
	}

    SDL_SetRenderTarget(renderer, NULL);
    SDL_RenderClear(renderer);
    SDL_RenderCopy(renderer, targetTexture, NULL, NULL);
	SDL_RenderPresent(renderer);
}

unsigned int RenderSystem::count() const {
	return renderDatas.size();
}

void RenderSystem::render(const RenderData& data) const {
    //render if component wants to be re-rendered
    if(data.renderComponent->doRender) {
        TextureData textureData;
        try {
            textureData = textureDatas.at(data.renderComponent->imagePath);
        } catch (const std::out_of_range &oor) {
            cout << "out_of_range exception caught in SystemManager::getSystem(string identifier): " << oor.what() << endl;
            cout << "1. Maybe there as a typo in the RenderComponent->imagePath, " << data.renderComponent->imagePath << "?" << endl;
            cout << "2. Maybe " << data.renderComponent->imagePath << " wasn't loaded by RenderSystem?" << endl;
            cout << "Things will go wrong from now on!" << endl;
        }

        SDL_Rect rect{
            (int)(data.moveComponent->xpos + data.renderComponent->xoffset),
            (int)(data.moveComponent->ypos + data.renderComponent->yoffset),
            (int)textureData.width,
            (int)textureData.height
        };

        //Render to target texture
        //the target texture in turn will be rendered ontop of default
        //the default is always cleared
        //SDL_RenderPresent invalidates current backbuffer, so hence this required
        //the targetTexture ISNT invalidated, whatever is rendered onto it it saved
        //so it's fine to just re-render the targetTexture
        SDL_SetTextureBlendMode(targetTexture, SDL_BLENDMODE_BLEND);
        SDL_SetRenderTarget(renderer, targetTexture);
        SDL_RenderCopy(renderer, textureDatas.at(data.renderComponent->imagePath).texture, NULL, &rect);

        //Finally, don't render this component until it says otherwise
        data.renderComponent->doRender = false;
    }
}

const string RenderSystem::getIdentifier() const {
	return "RenderSystem";
}

void RenderSystem::sort(RenderData* arr, const unsigned int size) const {
	//Sort the array by z-index

	//set zindex to be lowest y
	for(auto a : renderDatas) {
		get<1>(a).renderComponent->zindex = get<1>(a).moveComponent->ypos + get<1>(a).sizeComponent->height;
	}
	heapsort(arr, size);
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "rpc/protocol.h"

#include "random.h"
#include "tinyformat.h"
#include "util.h"
#include "utilstrencodings.h"
#include "utiltime.h"
#include "version.h"

#include <stdint.h>
#include <fstream>

using namespace std;

/**
 * JSON-RPC protocol.  Bitcoin speaks version 1.0 for maximum compatibility,
 * but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
 * unspecified (HTTP errors and contents of 'error').
 *
 * 1.0 spec: http://json-rpc.org/wiki/specification
 * 1.2 spec: http://jsonrpc.org/historical/json-rpc-over-http.html
 */

string JSONRPCRequest(const string& strMethod, const UniValue& params, const UniValue& id)
{
    UniValue request(UniValue::VOBJ);
    request.push_back(Pair("method", strMethod));
    request.push_back(Pair("params", params));
    request.push_back(Pair("id", id));
    return request.write() + "\n";
}

UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id)
{
    UniValue reply(UniValue::VOBJ);
    if (!error.isNull())
        reply.push_back(Pair("result", NullUniValue));
    else
        reply.push_back(Pair("result", result));
    reply.push_back(Pair("error", error));
    reply.push_back(Pair("id", id));
    return reply;
}

string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id)
{
    UniValue reply = JSONRPCReplyObj(result, error, id);
    return reply.write() + "\n";
}

UniValue JSONRPCError(int code, const string& message)
{
    UniValue error(UniValue::VOBJ);
    error.push_back(Pair("code", code));
    error.push_back(Pair("message", message));
    return error;
}

/** Username used when cookie authentication is in use (arbitrary, only for
 * recognizability in debugging/logging purposes)
 */
static const std::string COOKIEAUTH_USER = "__cookie__";
/** Default name for auth cookie file */
static const std::string COOKIEAUTH_FILE = ".cookie";

boost::filesystem::path GetAuthCookieFile()
{
    boost::filesystem::path path(GetArg("-rpccookiefile", COOKIEAUTH_FILE));
    if (!path.is_complete()) path = GetDataDir() / path;
    return path;
}

bool GenerateAuthCookie(std::string *cookie_out)
{
    unsigned char rand_pwd[32];
    GetRandBytes(rand_pwd, 32);
    std::string cookie = COOKIEAUTH_USER + ":" + EncodeBase64(&rand_pwd[0],32);

    /** the umask determines what permissions are used to create this file -
     * these are set to 077 in init.cpp unless overridden with -sysperms.
     */
    std::ofstream file;
    boost::filesystem::path filepath = GetAuthCookieFile();
    file.open(filepath.string().c_str());
    if (!file.is_open()) {
        LogPrintf("Unable to open cookie authentication file %s for writing\n", filepath.string());
        return false;
    }
    file << cookie;
    file.close();
    LogPrintf("Generated RPC authentication cookie %s\n", filepath.string());

    if (cookie_out)
        *cookie_out = cookie;
    return true;
}

bool GetAuthCookie(std::string *cookie_out)
{
    std::ifstream file;
    std::string cookie;
    boost::filesystem::path filepath = GetAuthCookieFile();
    file.open(filepath.string().c_str());
    if (!file.is_open())
        return false;
    std::getline(file, cookie);
    file.close();

    if (cookie_out)
        *cookie_out = cookie;
    return true;
}

void DeleteAuthCookie()
{
    try {
        boost::filesystem::remove(GetAuthCookieFile());
    } catch (const boost::filesystem::filesystem_error& e) {
        LogPrintf("%s: Unable to remove random auth cookie file: %s\n", __func__, e.what());
    }
}

<commit_msg>rpc: Generate auth cookie in hex instead of base64<commit_after>// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "rpc/protocol.h"

#include "random.h"
#include "tinyformat.h"
#include "util.h"
#include "utilstrencodings.h"
#include "utiltime.h"
#include "version.h"

#include <stdint.h>
#include <fstream>

using namespace std;

/**
 * JSON-RPC protocol.  Bitcoin speaks version 1.0 for maximum compatibility,
 * but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
 * unspecified (HTTP errors and contents of 'error').
 *
 * 1.0 spec: http://json-rpc.org/wiki/specification
 * 1.2 spec: http://jsonrpc.org/historical/json-rpc-over-http.html
 */

string JSONRPCRequest(const string& strMethod, const UniValue& params, const UniValue& id)
{
    UniValue request(UniValue::VOBJ);
    request.push_back(Pair("method", strMethod));
    request.push_back(Pair("params", params));
    request.push_back(Pair("id", id));
    return request.write() + "\n";
}

UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id)
{
    UniValue reply(UniValue::VOBJ);
    if (!error.isNull())
        reply.push_back(Pair("result", NullUniValue));
    else
        reply.push_back(Pair("result", result));
    reply.push_back(Pair("error", error));
    reply.push_back(Pair("id", id));
    return reply;
}

string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id)
{
    UniValue reply = JSONRPCReplyObj(result, error, id);
    return reply.write() + "\n";
}

UniValue JSONRPCError(int code, const string& message)
{
    UniValue error(UniValue::VOBJ);
    error.push_back(Pair("code", code));
    error.push_back(Pair("message", message));
    return error;
}

/** Username used when cookie authentication is in use (arbitrary, only for
 * recognizability in debugging/logging purposes)
 */
static const std::string COOKIEAUTH_USER = "__cookie__";
/** Default name for auth cookie file */
static const std::string COOKIEAUTH_FILE = ".cookie";

boost::filesystem::path GetAuthCookieFile()
{
    boost::filesystem::path path(GetArg("-rpccookiefile", COOKIEAUTH_FILE));
    if (!path.is_complete()) path = GetDataDir() / path;
    return path;
}

bool GenerateAuthCookie(std::string *cookie_out)
{
    const size_t COOKIE_SIZE = 32;
    unsigned char rand_pwd[COOKIE_SIZE];
    GetRandBytes(rand_pwd, COOKIE_SIZE);
    std::string cookie = COOKIEAUTH_USER + ":" + HexStr(rand_pwd, rand_pwd+COOKIE_SIZE);

    /** the umask determines what permissions are used to create this file -
     * these are set to 077 in init.cpp unless overridden with -sysperms.
     */
    std::ofstream file;
    boost::filesystem::path filepath = GetAuthCookieFile();
    file.open(filepath.string().c_str());
    if (!file.is_open()) {
        LogPrintf("Unable to open cookie authentication file %s for writing\n", filepath.string());
        return false;
    }
    file << cookie;
    file.close();
    LogPrintf("Generated RPC authentication cookie %s\n", filepath.string());

    if (cookie_out)
        *cookie_out = cookie;
    return true;
}

bool GetAuthCookie(std::string *cookie_out)
{
    std::ifstream file;
    std::string cookie;
    boost::filesystem::path filepath = GetAuthCookieFile();
    file.open(filepath.string().c_str());
    if (!file.is_open())
        return false;
    std::getline(file, cookie);
    file.close();

    if (cookie_out)
        *cookie_out = cookie;
    return true;
}

void DeleteAuthCookie()
{
    try {
        boost::filesystem::remove(GetAuthCookieFile());
    } catch (const boost::filesystem::filesystem_error& e) {
        LogPrintf("%s: Unable to remove random auth cookie file: %s\n", __func__, e.what());
    }
}

<|endoftext|>


<commit_before><commit_msg>[psm] Removing node discretization in the top layer<commit_after><|endoftext|>


<commit_before>#include <ecto/ecto.hpp>
#include <ecto/module.hpp>

#include <boost/python.hpp>
#include <boost/python/raw_function.hpp>
#include <boost/python/iterator.hpp>
#include <boost/python/slice.hpp>
#include <boost/python/stl_iterator.hpp>

#include <ecto/python/std_map_indexing_suite.hpp>
#include <ecto/python/raw_constructor.hpp>
#include <ecto/python/repr.hpp>
#include <string>
namespace bp = boost::python;

namespace ecto
{
  namespace py
  {
#if 1
#undef SHOW
#define SHOW() do{}while(false)
#endif

    struct modwrap: module, bp::wrapper<module>
    {

      void dispatch_declare_params(tendrils& params)
      {
        SHOW();
        if (bp::override init = this->get_override("declare_params"))
          init(boost::ref(params));
      }

      void dispatch_declare_io(const tendrils&params, tendrils& inputs, tendrils& outputs)
      {
        SHOW();
        if (bp::override declare_io = this->get_override("declare_io"))
          declare_io(boost::ref(params), boost::ref(inputs), boost::ref(outputs));
      }

      void dispatch_configure(tendrils& params, tendrils& inputs, tendrils& outputs)
      {
        SHOW();
        if (bp::override config = this->get_override("configure"))
          config(boost::ref(params));
      }

      ReturnCode dispatch_process(const tendrils& inputs, tendrils& outputs)
      {
        SHOW();
        if (bp::override proc = this->get_override("process"))
          {
            proc(boost::ref(inputs), boost::ref(outputs));
          }
        return OK;
      }

      void dispatch_destroy()
      {
        SHOW();
        if (bp::override dest = this->get_override("destroy"))
          dest();
      }

      std::string dispatch_name() const
      {
        SHOW();
        bp::reference_existing_object::apply<modwrap*>::type converter;
        PyObject* obj = converter(this);
        bp::object real_obj = bp::object(bp::handle<>(obj));
        bp::object n = real_obj.attr("__class__").attr("__name__");
        std::string nm = bp::extract<std::string>(n);
        return nm;
      }

      static std::string doc(modwrap* mod)
      {
        SHOW();
        bp::reference_existing_object::apply<modwrap*>::type converter;
        PyObject* obj = converter(mod);
        bp::object real_obj = bp::object(bp::handle<>(obj));
        bp::object n = real_obj.attr("__class__").attr("__doc__");
        bp::extract<std::string> get_str(n);
        if (get_str.check())
          return get_str();
        return "No Doc str.";
      }
    };

    const tendrils& inputs(module& mod)
    {
      return mod.inputs;
    }
    tendrils& outputs(module& mod)
    {
      return mod.outputs;
    }
    tendrils& params(module& mod)
    {
      return mod.parameters;
    }

    struct TendrilSpecification
    {
      module::ptr mod_input, mod_output;
      std::string key;

      TendrilSpecification()
      {
      }
      bool check(module::ptr mod, const std::string& key)
      {
        if (key.empty())
          return true;
        if (mod->inputs.find(key) == mod->inputs.end() && mod->outputs.find(key) == mod->outputs.end()
            && mod->parameters.find(key) == mod->parameters.end())
          {
            return false;
          }
        return true;
      }
      TendrilSpecification(module::ptr mod_in, module::ptr mod_out, const std::string& key) :
        mod_input(mod_in), mod_output(mod_out), key(key)
      {
        if (!check(mod_in, key))
          throw std::runtime_error(
          "The module " + mod_in->name() + " does not contain any inputs or outputs or parameters by the given name: "
              + key);
        if (!check(mod_out, key))
          throw std::runtime_error(
          "The module " + mod_out->name() + " does not contain any inputs or outputs or parameters by the given name: "
              + key);
      }
      TendrilSpecification(module::ptr mod, const std::string& key) :
        mod_input(mod), mod_output(mod), key(key)
      {
        if (!check(mod, key))
          throw std::runtime_error(
              "The module " + mod->name() + " does not contain any inputs or outputs or parameters by the given name: "
              + key);
      }
      tendril::ptr toTendril(int t)
      {
        switch (t)
          {
          case 0:
            return mod_output->outputs.at(key);
          case 1:
            return mod_input->inputs.at(key);
          case 2:
            return mod_input->parameters.at(key);
          default:
            return tendril::ptr();
          }
      }
      bp::str __str__()
      {
        bp::str str = bp::str(mod_input->name());
        str += ", " + bp::str(key);
        return str;
      }
    };

    struct TendrilSpecifications
    {
      typedef std::vector<TendrilSpecification> Vector;
      TendrilSpecifications()
      {
      }
      TendrilSpecifications(Vector vts) :
        vts(vts)
      {
      }
      TendrilSpecifications(bp::list l)
      {
        bp::stl_input_iterator<const TendrilSpecification&> begin(l), end;
        std::copy(begin, end, std::back_inserter(vts));
      }

      TendrilSpecification toSpec()
      {
        if (vts.size() != 1)
          {
            throw std::runtime_error("This specification must be of length one. e.g. module['only one key']");
          }
        return vts.front();
      }

      static tendrils::ptr toTendrils(bp::dict d, int tt)
      {
        bp::list keys = d.keys();
        bp::stl_input_iterator<std::string> begin(keys), end;
        tendrils::ptr ts(new tendrils);

        while (begin != end)
          {
            std::string key = *begin;
            TendrilSpecifications spec = bp::extract<TendrilSpecifications>(d.get(bp::str(key)));
            (*ts)[key] = spec.toSpec().toTendril(tt);
            ++begin;

          }
        return ts;

      }
      Vector vts;
    };

    TendrilSpecifications getitem_str(module::ptr mod, const std::string& key)
    {
      return TendrilSpecifications::Vector(1, TendrilSpecification(mod, key));
    }

    TendrilSpecifications getitem_tuple(module::ptr mod, bp::tuple keys)
    {
      int end = bp::len(keys);
      TendrilSpecifications l;
      l.vts.reserve(end);
      for (int i = 0; i != end; ++i)
        {
          bp::extract<std::string> se(keys[i]);
          if (se.check())
            l.vts.push_back(TendrilSpecification(mod, se()));
          else
            throw std::runtime_error("All items must be str's");
        }
      return l;
    }

    TendrilSpecifications getitem_list(module::ptr mod, bp::list keys)
    {
      bp::tuple t(keys);
      return getitem_tuple(mod, t);
    }

    TendrilSpecifications getitem_slice(module::ptr mod, bp::slice s)
    {

      if (s == bp::slice())
        {
          return TendrilSpecifications::Vector(1, TendrilSpecification(mod, ""));
        }
      else
        {
          throw std::runtime_error("Slice is only valid if its the [:] form...");
        }
    }
    TendrilSpecifications expand(module::ptr mod, const tendrils& t)
    {
      TendrilSpecifications l;

      BOOST_FOREACH(const tendrils::value_type& pair, t)
        {
          l.vts.push_back(TendrilSpecification(mod, pair.first));
        }
      return l;
    }

    bp::list rshift_spec(TendrilSpecifications& lhs, TendrilSpecifications& rhs)
    {
      bp::list result;
      if (lhs.vts.size() == 1 && lhs.vts.front().key.empty())
        {
          lhs = expand(lhs.vts.front().mod_output, lhs.vts.front().mod_output->outputs);
        }
      if (rhs.vts.size() == 1 && rhs.vts.front().key.empty())
        {
          rhs = expand(rhs.vts.front().mod_input, rhs.vts.front().mod_input->inputs);
        }
      //the spec must be the same size...
      if (lhs.vts.size() != rhs.vts.size())
        {
          std::string msg = boost::str(
                                       boost::format("Specification mismatch... len(lhs) != len(rhs) -> %d != %d")
                                           % lhs.vts.size() % rhs.vts.size());
          throw std::runtime_error(msg);
        }
      for (size_t i = 0, end = lhs.vts.size(); i < end; i++)
        {
          TendrilSpecification out = lhs.vts[i], in = rhs.vts[i];
          //check types, this will also assert on not found...
          out.mod_output->outputs.at(out.key)->compatible_type(*in.mod_input->inputs.at(in.key));
          result.append(bp::make_tuple(out.mod_output, out.key, in.mod_input, in.key));
        }
      return result;
    }
    bp::list rshift_spec_tuples(TendrilSpecifications& lhs, bp::tuple& rhs)
    {
      bp::list result;
      bp::stl_input_iterator< TendrilSpecifications& > begin(rhs),end;
      while(begin != end)
        {
          result.extend(rshift_spec(lhs,*begin));
          ++begin;
        }
      return result;
    }

    void wrapModule()
    {
      //use private names so that python people know these are internal
      bp::class_<module, boost::shared_ptr<module>, boost::noncopyable>("_module_cpp", bp::no_init);

      bp::class_<modwrap, boost::shared_ptr<modwrap>, boost::noncopyable> m_base("_module_base" /*bp::no_init*/);
      m_base.def("declare_params", &module::declare_params);
      m_base.def("declare_io", ((void(module::*)()) &module::declare_io));
      m_base .def("configure", ((void(module::*)()) &module::configure));
      m_base .def("process", (void(module::*)()) &module::process);
      m_base .def("destroy", &module::destroy);

      m_base.add_property("inputs", make_function(&inputs, bp::return_internal_reference<>()));
      m_base.add_property("outputs", make_function(outputs, bp::return_internal_reference<>()));
      m_base.add_property("params", make_function(params, bp::return_internal_reference<>()));
      m_base.def("type", &module::type);
      m_base.def("name", (std::string(module::*)() const) &module::name);
      m_base .def("doc", &modwrap::doc);
      m_base.def("gen_doc", &module::gen_doc);
      m_base.def("__getitem__", getitem_str);
      m_base.def("__getitem__", getitem_tuple);
      m_base.def("__getitem__", getitem_list);
      m_base.def("__getitem__", getitem_slice);

      bp::class_<TendrilSpecification> ts("TendrilSpecification");
      ts.def_readwrite("module_input", &TendrilSpecification::mod_input);
      ts.def_readwrite("module_output", &TendrilSpecification::mod_output);
      ts.def_readwrite("key", &TendrilSpecification::key);

      bp::class_<TendrilSpecifications> vts("TendrilSpecifications", bp::init<bp::list>());
      vts.def("to_tendrils", &TendrilSpecifications::toTendrils);
      vts.staticmethod("to_tendrils");
      vts.def("to_spec", &TendrilSpecifications::toSpec);
      vts.def("__rshift__", rshift_spec);
      vts.def("__rshift__", rshift_spec_tuples);

    }

  }
}
<commit_msg>- better error message<commit_after>#include <ecto/ecto.hpp>
#include <ecto/module.hpp>

#include <boost/python.hpp>
#include <boost/python/raw_function.hpp>
#include <boost/python/iterator.hpp>
#include <boost/python/slice.hpp>
#include <boost/python/stl_iterator.hpp>

#include <ecto/python/std_map_indexing_suite.hpp>
#include <ecto/python/raw_constructor.hpp>
#include <ecto/python/repr.hpp>
#include <string>
namespace bp = boost::python;

namespace ecto
{
  namespace py
  {
#if 1
#undef SHOW
#define SHOW() do{}while(false)
#endif

    struct modwrap: module, bp::wrapper<module>
    {

      void dispatch_declare_params(tendrils& params)
      {
        SHOW();
        if (bp::override init = this->get_override("declare_params"))
          init(boost::ref(params));
      }

      void dispatch_declare_io(const tendrils&params, tendrils& inputs, tendrils& outputs)
      {
        SHOW();
        if (bp::override declare_io = this->get_override("declare_io"))
          declare_io(boost::ref(params), boost::ref(inputs), boost::ref(outputs));
      }

      void dispatch_configure(tendrils& params, tendrils& inputs, tendrils& outputs)
      {
        SHOW();
        if (bp::override config = this->get_override("configure"))
          config(boost::ref(params));
      }

      ReturnCode dispatch_process(const tendrils& inputs, tendrils& outputs)
      {
        SHOW();
        if (bp::override proc = this->get_override("process"))
          {
            proc(boost::ref(inputs), boost::ref(outputs));
          }
        return OK;
      }

      void dispatch_destroy()
      {
        SHOW();
        if (bp::override dest = this->get_override("destroy"))
          dest();
      }

      std::string dispatch_name() const
      {
        SHOW();
        bp::reference_existing_object::apply<modwrap*>::type converter;
        PyObject* obj = converter(this);
        bp::object real_obj = bp::object(bp::handle<>(obj));
        bp::object n = real_obj.attr("__class__").attr("__name__");
        std::string nm = bp::extract<std::string>(n);
        return nm;
      }

      static std::string doc(modwrap* mod)
      {
        SHOW();
        bp::reference_existing_object::apply<modwrap*>::type converter;
        PyObject* obj = converter(mod);
        bp::object real_obj = bp::object(bp::handle<>(obj));
        bp::object n = real_obj.attr("__class__").attr("__doc__");
        bp::extract<std::string> get_str(n);
        if (get_str.check())
          return get_str();
        return "No Doc str.";
      }
    };

    const tendrils& inputs(module& mod)
    {
      return mod.inputs;
    }
    tendrils& outputs(module& mod)
    {
      return mod.outputs;
    }
    tendrils& params(module& mod)
    {
      return mod.parameters;
    }

    struct TendrilSpecification
    {
      module::ptr mod_input, mod_output;
      std::string key;

      TendrilSpecification()
      {
      }
      bool check(module::ptr mod, const std::string& key)
      {
        if (key.empty())
          return true;
        if (mod->inputs.find(key) == mod->inputs.end() && mod->outputs.find(key) == mod->outputs.end()
            && mod->parameters.find(key) == mod->parameters.end())
          {
            return false;
          }
        return true;
      }
      TendrilSpecification(module::ptr mod_in, module::ptr mod_out, const std::string& key) :
        mod_input(mod_in), mod_output(mod_out), key(key)
      {
        if (!check(mod_in, key))
          throw std::runtime_error(
          "The module " + mod_in->name() + " does not contain any input or parameter by the given name: "
              + key);
        if (!check(mod_out, key))
          throw std::runtime_error(
          "The module " + mod_out->name() + " does not contain any output or parameter by the given name: "
              + key);
      }
      TendrilSpecification(module::ptr mod, const std::string& key) :
        mod_input(mod), mod_output(mod), key(key)
      {
        if (!check(mod, key))
          throw std::runtime_error(
              "The module " + mod->name() + " does not contain any inputs or outputs or parameters by the given name: "
              + key);
      }
      tendril::ptr toTendril(int t)
      {
        switch (t)
          {
          case 0:
            return mod_output->outputs.at(key);
          case 1:
            return mod_input->inputs.at(key);
          case 2:
            return mod_input->parameters.at(key);
          default:
            return tendril::ptr();
          }
      }
      bp::str __str__()
      {
        bp::str str = bp::str(mod_input->name());
        str += ", " + bp::str(key);
        return str;
      }
    };

    struct TendrilSpecifications
    {
      typedef std::vector<TendrilSpecification> Vector;
      TendrilSpecifications()
      {
      }
      TendrilSpecifications(Vector vts) :
        vts(vts)
      {
      }
      TendrilSpecifications(bp::list l)
      {
        bp::stl_input_iterator<const TendrilSpecification&> begin(l), end;
        std::copy(begin, end, std::back_inserter(vts));
      }

      TendrilSpecification toSpec()
      {
        if (vts.size() != 1)
          {
            throw std::runtime_error("This specification must be of length one. e.g. module['only one key']");
          }
        return vts.front();
      }

      static tendrils::ptr toTendrils(bp::dict d, int tt)
      {
        bp::list keys = d.keys();
        bp::stl_input_iterator<std::string> begin(keys), end;
        tendrils::ptr ts(new tendrils);

        while (begin != end)
          {
            std::string key = *begin;
            TendrilSpecifications spec = bp::extract<TendrilSpecifications>(d.get(bp::str(key)));
            (*ts)[key] = spec.toSpec().toTendril(tt);
            ++begin;

          }
        return ts;

      }
      Vector vts;
    };

    TendrilSpecifications getitem_str(module::ptr mod, const std::string& key)
    {
      return TendrilSpecifications::Vector(1, TendrilSpecification(mod, key));
    }

    TendrilSpecifications getitem_tuple(module::ptr mod, bp::tuple keys)
    {
      int end = bp::len(keys);
      TendrilSpecifications l;
      l.vts.reserve(end);
      for (int i = 0; i != end; ++i)
        {
          bp::extract<std::string> se(keys[i]);
          if (se.check())
            l.vts.push_back(TendrilSpecification(mod, se()));
          else
            throw std::runtime_error("All items must be str's");
        }
      return l;
    }

    TendrilSpecifications getitem_list(module::ptr mod, bp::list keys)
    {
      bp::tuple t(keys);
      return getitem_tuple(mod, t);
    }

    TendrilSpecifications getitem_slice(module::ptr mod, bp::slice s)
    {

      if (s == bp::slice())
        {
          return TendrilSpecifications::Vector(1, TendrilSpecification(mod, ""));
        }
      else
        {
          throw std::runtime_error("Slice is only valid if its the [:] form...");
        }
    }
    TendrilSpecifications expand(module::ptr mod, const tendrils& t)
    {
      TendrilSpecifications l;

      BOOST_FOREACH(const tendrils::value_type& pair, t)
        {
          l.vts.push_back(TendrilSpecification(mod, pair.first));
        }
      return l;
    }

    bp::list rshift_spec(TendrilSpecifications& lhs, TendrilSpecifications& rhs)
    {
      bp::list result;
      if (lhs.vts.size() == 1 && lhs.vts.front().key.empty())
        {
          lhs = expand(lhs.vts.front().mod_output, lhs.vts.front().mod_output->outputs);
        }
      if (rhs.vts.size() == 1 && rhs.vts.front().key.empty())
        {
          rhs = expand(rhs.vts.front().mod_input, rhs.vts.front().mod_input->inputs);
        }
      //the spec must be the same size...
      if (lhs.vts.size() != rhs.vts.size())
        {
          std::string msg = boost::str(
                                       boost::format("Specification mismatch... len(lhs) != len(rhs) -> %d != %d")
                                           % lhs.vts.size() % rhs.vts.size());
          throw std::runtime_error(msg);
        }
      for (size_t i = 0, end = lhs.vts.size(); i < end; i++)
        {
          TendrilSpecification out = lhs.vts[i], in = rhs.vts[i];
          //check types, this will also assert on not found...
          out.mod_output->outputs.at(out.key)->compatible_type(*in.mod_input->inputs.at(in.key));
          result.append(bp::make_tuple(out.mod_output, out.key, in.mod_input, in.key));
        }
      return result;
    }
    bp::list rshift_spec_tuples(TendrilSpecifications& lhs, bp::tuple& rhs)
    {
      bp::list result;
      bp::stl_input_iterator< TendrilSpecifications& > begin(rhs),end;
      while(begin != end)
        {
          result.extend(rshift_spec(lhs,*begin));
          ++begin;
        }
      return result;
    }

    void wrapModule()
    {
      //use private names so that python people know these are internal
      bp::class_<module, boost::shared_ptr<module>, boost::noncopyable>("_module_cpp", bp::no_init);

      bp::class_<modwrap, boost::shared_ptr<modwrap>, boost::noncopyable> m_base("_module_base" /*bp::no_init*/);
      m_base.def("declare_params", &module::declare_params);
      m_base.def("declare_io", ((void(module::*)()) &module::declare_io));
      m_base .def("configure", ((void(module::*)()) &module::configure));
      m_base .def("process", (void(module::*)()) &module::process);
      m_base .def("destroy", &module::destroy);

      m_base.add_property("inputs", make_function(&inputs, bp::return_internal_reference<>()));
      m_base.add_property("outputs", make_function(outputs, bp::return_internal_reference<>()));
      m_base.add_property("params", make_function(params, bp::return_internal_reference<>()));
      m_base.def("type", &module::type);
      m_base.def("name", (std::string(module::*)() const) &module::name);
      m_base .def("doc", &modwrap::doc);
      m_base.def("gen_doc", &module::gen_doc);
      m_base.def("__getitem__", getitem_str);
      m_base.def("__getitem__", getitem_tuple);
      m_base.def("__getitem__", getitem_list);
      m_base.def("__getitem__", getitem_slice);

      bp::class_<TendrilSpecification> ts("TendrilSpecification");
      ts.def_readwrite("module_input", &TendrilSpecification::mod_input);
      ts.def_readwrite("module_output", &TendrilSpecification::mod_output);
      ts.def_readwrite("key", &TendrilSpecification::key);

      bp::class_<TendrilSpecifications> vts("TendrilSpecifications", bp::init<bp::list>());
      vts.def("to_tendrils", &TendrilSpecifications::toTendrils);
      vts.staticmethod("to_tendrils");
      vts.def("to_spec", &TendrilSpecifications::toSpec);
      vts.def("__rshift__", rshift_spec);
      vts.def("__rshift__", rshift_spec_tuples);

    }

  }
}
<|endoftext|>