<commit_before>// $Id: options.C,v 1.17 2000/10/28 21:55:18 amoll Exp $

#include <BALL/DATATYPE/options.h>

#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <math.h>

#include <fstream>
#include <list>
#include <algorithm>

using namespace std;
using std::ofstream;
using std::ios;

namespace BALL
{

	const Size Options::MAX_ENTRY_LENGTH = 1024;

	Options::Options()
		:	StringHashMap<String>(),
			name_("")
	{
	}

	Options::Options(const Options& options, bool deep)
		:	StringHashMap<String>(options, deep),
			name_(options.name_)
	{
	}

	Options::~Options()
	{
	}

	bool Options::isReal(const String& key) const
	{
		errno = 0;
		char*	endptr;
		String value(get(key));

		// an empty String is no real number
		if (value =="")
		{
			return false;
		}

		// try to convert it to a number
		::strtod(value.c_str(), &endptr);

		// return and tell whether it happend to work
		return (errno == 0) && (endptr != value.c_str());
	}

	bool Options::isVector(const String& key) const
	{
		// if the key does not exist - then the nonexistent value
		// cannot contain a vector
		if (!has(key))
		{
			return false;
		}

		// try to interpret the string as three double values
		double dummy;
		if (sscanf(get(key).c_str(), "(%lf %lf %lf)", &dummy, &dummy, &dummy) == 3)
		{
			return true;
		}

		return false;
	}

	bool Options::isBool(const String& key) const
	{
		String s = get(key);
		if (s == "")
			return false;

		s.toLower();
		return (s.compare("true") == 0 || s.compare("false") == 0);
	}

	bool Options::isSet(const String& key) const
	{
		return (StringHashMap<String>::find(key) != StringHashMap<String>::end());
	}

	bool Options::isInteger(const String& key) const
	{
		double double_value;
		long long_value;

		// if it cannot be read as a floating point number
		// it cannot be an integer
		if (!isReal(key))
		{
			return false;
		}

		// check wheter it is an integer
		long_value = ::atol(get(key).c_str());
		double_value = ::atof(get(key).c_str());

		// check if it is an integer (cutoff is 1e-7)
		if (fabs(double_value - ((double)long_value)) <= 1e-7)
		{
			return true;
		}

		// it is a floating point number, but no integer
		return false;
	}

	double Options::getReal(const String& key) const
	{
		if (!has(key))
		{
			return 0.0;
		}
		double value;
		errno = 0;
		value = ::atof((*find(key)).second.c_str());

		if (errno == 0)
		{
			return value;
		}
		else
		{
			return 0.0;
		}
	}

	Vector3	Options::getVector(const String& key) const
	{
		Vector3	h(0,0,0);

		if (!has(key))
		{
			return h;
		}

		// use temporary variables of double precision
		// this avoids trouble if the definition of
		// Vector3 is changed between TVector3<float> and TVector3<double>
		double x, y, z;

		// try to interpret the option as a vector
		sscanf(get(key).c_str(), "(%lf %lf %lf)", &x, &y, &z);
		h.x = x;
		h.y = y;
		h.z = z;

		return h;
	}

	bool Options::getBool(const String& key) const
	{
		if (!has(key))
		{
			return false;
		}

		ConstIterator it = find(key);
		if ((it != end()) && (it->second == "true"))
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	long Options::getInteger(const String& key) const
	{
		if (!has(key))
		{
			return 0;
		}

		long value;
		errno = 0;
		ConstIterator it = find(key);
		if (it == end())
		{
			return 0;
		}
		value = atol((*it).second.c_str());

		if (errno == 0)
		{
			return value;
		}
		else
		{
			errno = 0;
			return 0;
		}
	}

	void Options::set(const String& key, const String& value)
	{
		(*this)[key] = value;
	}

	void Options::setInteger(const String& key, const long value)
	{
		static char buffer[MAX_ENTRY_LENGTH + 1];
		sprintf(buffer, "%ld", value);
		set(key, &(buffer[0]));
	}

	void Options::setReal(const String& key, const double value)
	{
		char buffer[MAX_ENTRY_LENGTH + 1];
		sprintf(buffer, "%f", value);
		set(key, buffer);
	}

	void Options::setVector(const String& key, const Vector3& value)
	{
		char buffer[MAX_ENTRY_LENGTH + 1];
		sprintf(buffer, "(%f %f %f)", value.x, value.y, value.z);
		set(key, buffer);
	}

	void Options::setBool(const String& key, const bool value)
	{
		if (value)
		{
			set(key, "true");
		}
		else
		{
			set(key, "false");
		}
	}

	String Options::setDefault(const String& key, const String& value)
	{
		if (!has(key))
		{
			set(key, value);
			return key;
		}
		else
		{
			return get(key);
		}
	}

	double Options::setDefaultReal(const String& key, const double value)
	{
		if (!has(key) || !isReal(key))
		{
			setReal(key, value);
			return value;
		}
		else
		{
			return getReal(key);
		}
	}

	bool Options::setDefaultBool(const String& key, const bool value)
	{
		if (!has(key) || !isBool(key))
		{
			setBool(key, value);
			return value;
		}
		else
		{
			return getBool(key);
		}
	}

	long Options::setDefaultInteger(const String& key, const long value)
	{
		if (!has(key) || !isInteger(key))
		{
			setInteger(key, value);
			return value;
		}
		else
		{
			return getInteger(key);
		}
	}

	void Options::setName(const String& name)
	{
		name_ = name;
	}

	const String& Options::getName() const
	{
		return name_;
	}

	String Options::get(const String& key) const
	{
		if (!has(key))
		{
			return "";
		}
		ConstIterator it = find(key);

		if (it == end())
		{
			return "";
		}
		else
		{
			return (*it).second;
		}
	}

	bool Options::readOptionFile(const String& filename)
	{
		ifstream		infile;
		infile.open(filename.c_str(), ios::in);
		if (!infile)
		{
			return false;
		}

		char		buffer[MAX_ENTRY_LENGTH + 1];
		String	s, key;
		while (infile.getline(buffer, MAX_ENTRY_LENGTH))
		{
			if ((buffer[0] != '#') && (buffer[0] != '!') && (buffer[0] != ';'))
			{
				s = buffer;
				key = s.getField(0, " ");
				s = s.after(" ");
				set(key, s);
			}
		}

		infile.close();
		return true;
	}

	bool Options::writeOptionFile(const String& filename) const
	{
		std::list<String>		entry_list;
		String							entry;

		std::ofstream stream(filename.c_str());//, File::OUT);
		if (!stream.is_open())
		{
			return false;
		}

		stream << "![OptionsTable: " << getName() << " (" << size() << " entries)]" << endl;

		StringHashMap<String>::ConstIterator	it(begin());
		for(; !(it == end()); ++it)
		{
			entry = (*it).first + ' ' + (*it).second;
			entry_list.push_back(entry);
		}

		entry_list.sort();

		std::list<String>::iterator	list_it = entry_list.begin();
		for (; list_it != entry_list.end(); ++list_it)
		{
	  	stream << *list_it << endl;
		}

		stream << "!-----------------------------------" << endl;

		stream.close();
		entry_list.clear();
		return true;
	}

	void Options::dump (ostream& stream, Size /* depth */) const
	{
		std::list<String>		entry_list;
		String							entry;

		stream << "[OptionsTable: " << getName() << " (" << size() << " entries)]" << endl;

		StringHashMap<String>::ConstIterator	it(begin());
		for(; !(it == end()); ++it)
		{
			entry = (*it).first + ' ' + (*it).second;
			entry_list.push_back(entry);
		}

		entry_list.sort();

		std::list<String>::iterator	list_it = entry_list.begin();
		for (; list_it != entry_list.end(); ++list_it)
		{
	  	stream << *list_it << endl;
		}

		stream << "-----------------------------------" << endl;

		entry_list.clear();
	}

} // namespace BALL
<commit_msg>cosmetic changes added: ==,!=, clear, =<commit_after>// $Id: options.C,v 1.18 2000/11/30 22:57:06 amoll Exp $

#include <BALL/DATATYPE/options.h>

#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <math.h>

#include <fstream>
#include <list>
#include <algorithm>

using namespace std;
using std::ofstream;
using std::ios;

namespace BALL
{

	const Size Options::MAX_ENTRY_LENGTH = 1024;

	Options::Options()
	 throw()
		:	StringHashMap<String>(),
			name_("")
	{
	}

	Options::Options(const Options& options, bool deep)
	 throw()
		:	StringHashMap<String>(options, deep),
			name_(options.name_)
	{
	}

	Options::~Options()
	 throw()
	{
	}

	bool Options::isReal(const String& key) const
	 throw()
	{
		errno = 0;
		char*	endptr;
		String value(get(key));

		// an empty String is no real number
		if (value =="")
		{
			return false;
		}

		// try to convert it to a number
		::strtod(value.c_str(), &endptr);

		// return and tell whether it happend to work
		return (errno == 0) && (endptr != value.c_str());
	}

	bool Options::isVector(const String& key) const
	 throw()
	{
		// if the key does not exist - then the nonexistent value
		// cannot contain a vector
		if (!has(key))
		{
			return false;
		}

		// try to interpret the string as three double values
		double dummy;
		if (sscanf(get(key).c_str(), "(%lf %lf %lf)", &dummy, &dummy, &dummy) == 3)
		{
			return true;
		}

		return false;
	}

	bool Options::isBool(const String& key) const
	 throw()
	{
		String s = get(key);
		if (s == "")
		{
			return false;
		}

		s.toLower();
		return (s.compare("true") == 0 || s.compare("false") == 0);
	}

	bool Options::isSet(const String& key) const
	 throw()
	{
		return (StringHashMap<String>::find(key) != StringHashMap<String>::end());
	}

	bool Options::isInteger(const String& key) const
	 throw()
	{
		// if it cannot be read as a floating point number
		// it cannot be an integer
		if (!isReal(key))
		{
			return false;
		}

		// check wheter it is an integer
		long_value long_value = ::atol(get(key).c_str());
		double double_value   = ::atof(get(key).c_str());

		// check if it is an integer (cutoff is 1e-7)
		if (fabs(double_value - ((double)long_value)) <= 1e-7)
		{
			return true;
		}

		// it is a floating point number, but no integer
		return false;
	}

	double Options::getReal(const String& key) const
	 throw()
	{
		if (!has(key))
		{
			return 0.0;
		}
		double value;
		errno = 0;
		value = ::atof((*find(key)).second.c_str());

		if (errno == 0)
		{
			return value;
		}
		else
		{
			return 0.0;
		}
	}

	Vector3	Options::getVector(const String& key) const
	 throw()
	{
		Vector3	h(0,0,0);

		if (!has(key))
		{
			return h;
		}

		// use temporary variables of double precision
		// this avoids trouble if the definition of
		// Vector3 is changed between TVector3<float> and TVector3<double>
		double x, y, z;

		// try to interpret the option as a vector
		sscanf(get(key).c_str(), "(%lf %lf %lf)", &x, &y, &z);
		h.x = x;
		h.y = y;
		h.z = z;

		return h;
	}

	bool Options::getBool(const String& key) const
	 throw()
	{
		if (!has(key))
		{
			return false;
		}

		ConstIterator it = find(key);
		if ((it != end()) && (it->second == "true"))
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	long Options::getInteger(const String& key) const
	 throw()
	{
		if (!has(key))
		{
			return 0;
		}

		long value;
		errno = 0;
		ConstIterator it = find(key);
		if (it == end())
		{
			return 0;
		}
		value = atol((*it).second.c_str());

		if (errno == 0)
		{
			return value;
		}
		else
		{
			errno = 0;
			return 0;
		}
	}

	void Options::set(const String& key, const String& value)
	 throw()
	{
		(*this)[key] = value;
	}

	void Options::setInteger(const String& key, const long value)
	 throw()
	{
		static char buffer[MAX_ENTRY_LENGTH + 1];
		sprintf(buffer, "%ld", value);
		set(key, &(buffer[0]));
	}

	void Options::setReal(const String& key, const double value)
	 throw()
	{
		char buffer[MAX_ENTRY_LENGTH + 1];
		sprintf(buffer, "%f", value);
		set(key, buffer);
	}

	void Options::setVector(const String& key, const Vector3& value)
	 throw()
	{
		char buffer[MAX_ENTRY_LENGTH + 1];
		sprintf(buffer, "(%f %f %f)", value.x, value.y, value.z);
		set(key, buffer);
	}

	void Options::setBool(const String& key, const bool value)
	 throw()
	{
		if (value)
		{
			set(key, "true");
		}
		else
		{
			set(key, "false");
		}
	}

	String Options::setDefault(const String& key, const String& value)
	 throw()
	{
		if (!has(key))
		{
			set(key, value);
			return key;
		}
		else
		{
			return get(key);
		}
	}

	double Options::setDefaultReal(const String& key, const double value)
	 throw()
	{
		if (!has(key) || !isReal(key))
		{
			setReal(key, value);
			return value;
		}
		else
		{
			return getReal(key);
		}
	}

	bool Options::setDefaultBool(const String& key, const bool value)
	 throw()
	{
		if (!has(key) || !isBool(key))
		{
			setBool(key, value);
			return value;
		}
		else
		{
			return getBool(key);
		}
	}

	long Options::setDefaultInteger(const String& key, const long value)
	 throw()
	{
		if (!has(key) || !isInteger(key))
		{
			setInteger(key, value);
			return value;
		}
		else
		{
			return getInteger(key);
		}
	}

	void Options::setName(const String& name)
	 throw()
	{
		name_ = name;
	}

	const String& Options::getName() const
	 throw()
	{
		return name_;
	}

	String Options::get(const String& key) const
	 throw()
	{
		if (!has(key))
		{
			return "";
		}
		ConstIterator it = find(key);

		if (it == end())
		{
			return "";
		}
		else
		{
			return (*it).second;
		}
	}

	bool Options::readOptionFile(const String& filename)
	 throw()
	{
		ifstream	infile;
		infile.open(filename.c_str(), ios::in);
		if (!infile)
		{
			return false;
		}

		char		buffer[MAX_ENTRY_LENGTH + 1];
		String	s, key;
		while (infile.getline(buffer, MAX_ENTRY_LENGTH))
		{
			if ((buffer[0] != '#') && (buffer[0] != '!') && (buffer[0] != ';'))
			{
				s = buffer;
				key = s.getField(0, " ");
				s = s.after(" ");
				set(key, s);
			}
		}

		infile.close();
		return true;
	}

	bool Options::writeOptionFile(const String& filename) const
	 throw()
	{
		std::list<String>		entry_list;
		String							entry;

		std::ofstream stream(filename.c_str());//, File::OUT);
		if (!stream.is_open())
		{
			return false;
		}

		stream << "![OptionsTable: " << getName() << " (" << size() << " entries)]" << endl;

		StringHashMap<String>::ConstIterator	it(begin());
		for(; !(it == end()); ++it)
		{
			entry = (*it).first + ' ' + (*it).second;
			entry_list.push_back(entry);
		}

		entry_list.sort();

		std::list<String>::iterator	list_it = entry_list.begin();
		for (; list_it != entry_list.end(); ++list_it)
		{
	  	stream << *list_it << endl;
		}

		stream << "!-----------------------------------" << endl;

		stream.close();
		entry_list.clear();
		return true;
	}

	void Options::dump (ostream& stream, Size /* depth */) const
	 throw()
	{
		std::list<String>		entry_list;
		String							entry;

		stream << "[OptionsTable: " << getName() << " (" << size() << " entries)]" << endl;

		StringHashMap<String>::ConstIterator	it(begin());
		for(; !(it == end()); ++it)
		{
			entry = (*it).first + ' ' + (*it).second;
			entry_list.push_back(entry);
		}

		entry_list.sort();

		std::list<String>::iterator	list_it = entry_list.begin();
		for (; list_it != entry_list.end(); ++list_it)
		{
	  	stream << *list_it << endl;
		}

		stream << "-----------------------------------" << endl;

		entry_list.clear();
	}

	const Options& Options::operator = (const Options& options)
	 throw()
	{
		*this = Options(options);
	}

	bool Options::operator == (const Options::& option) const
		throw()
	{
		if (this->name_ != option.name_)
		{
			return false;
		}

		return StringHashMap<String>::operator == (option);
	}

	bool Options::operator != (const Options::& option) const
		throw()
	{
		return !(*this == option);
	}

	void Options::clear() throw()
	{
		name_ = "";
		StringHashMap<String>::clear();
	}

} // namespace BALL
<|endoftext|>


<commit_before>// For conditions of distribution and use, see copyright notice in license.txt

#include "DebugOperatorNew.h"

#include "UiAPI.h"
#include "UiMainWindow.h"
#include "UiGraphicsView.h"
#include "QtUiAsset.h"
#include "UiProxyWidget.h"

#include "Framework.h"
#include "AssetAPI.h"
#include "GenericAssetFactory.h"
#include "LoggingFunctions.h"
DEFINE_POCO_LOGGING_FUNCTIONS("UiAPI")

#include <QEvent>
#include <QLayout>
#include <QVBoxLayout>
#include <QScrollBar>
#include <QUiLoader>
#include <QFile>

#include "MemoryLeakCheck.h"

/// The SuppressedPaintWidget is used as a viewport for the main Naali QGraphicsView.
/** Its purpose is to disable all automatic drawing of the QGraphicsView to screen so that
    we can composite an Ogre 3D render with the Qt widgets added to a QGraphicsScene. */
class SuppressedPaintWidget : public QWidget {
public:
    SuppressedPaintWidget(QWidget *parent = 0, Qt::WindowFlags f = 0);
    virtual ~SuppressedPaintWidget() {}

protected:
    virtual bool event(QEvent *event);
    virtual void paintEvent(QPaintEvent *event);
};

SuppressedPaintWidget::SuppressedPaintWidget(QWidget *parent, Qt::WindowFlags f)
:QWidget(parent, f)
{
    setAttribute(Qt::WA_PaintOnScreen);
    setAttribute(Qt::WA_NoSystemBackground);
    setAttribute(Qt::WA_OpaquePaintEvent, true);
}

bool SuppressedPaintWidget::event(QEvent *event)
{
    switch(event->type())
    {
    case QEvent::UpdateRequest:
    case QEvent::Paint:
    case QEvent::Wheel:
    case QEvent::Resize:
        return true;
    default:
        return QWidget::event(event);
    }
}

void SuppressedPaintWidget::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);
}

UiAPI::UiAPI(Foundation::Framework *owner_) :
    owner(owner_),
    mainWindow(0),
    graphicsView(0),
    graphicsScene(0)
{
    if (owner->IsHeadless())
        return;

    mainWindow = new UiMainWindow(owner);
    mainWindow->setAutoFillBackground(false);
    //mainWindow->setUpdatesEnabled(false);

    // Apply the Naali main window icon.
    // Note: this will only affect to a icon at main window left top corner.
    //       The application thumbnail icon must be set by adding icon resource
    //       to viewer project
    QIcon icon("./data/ui/images/icon/naali_logo_32px_RC1.ico");
    mainWindow->setWindowIcon(icon);

    graphicsView = new UiGraphicsView(mainWindow);

    ///\todo Memory leak below, see very end of ~Renderer() for comments.

    // QMainWindow has a layout by default. It will not let you set another.
    // Leave this check here if the window type changes to for example QWidget so we dont crash then.
    if (!mainWindow->layout())
        mainWindow->setLayout(new QVBoxLayout());
    mainWindow->layout()->setMargin(0);
    mainWindow->layout()->setContentsMargins(0,0,0,0);
    mainWindow->layout()->addWidget(graphicsView);

    viewportWidget = new SuppressedPaintWidget();
    graphicsView->setViewport(viewportWidget);
//    viewportWidget->setAttribute(Qt::WA_DontShowOnScreen, true);
    viewportWidget->setGeometry(0, 0, graphicsView->width(), graphicsView->height());
    viewportWidget->setContentsMargins(0,0,0,0);

    mainWindow->setContentsMargins(0,0,0,0);
    graphicsView->setContentsMargins(0,0,0,0);

    graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    graphicsView->horizontalScrollBar()->setValue(0);
    graphicsView->horizontalScrollBar()->setRange(0, 0);

    graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    graphicsView->verticalScrollBar()->setValue(0);
    graphicsView->verticalScrollBar()->setRange(0, 0);

    // Setup Qt's main window with title and geometry
    //mainWindow->setWindowTitle(QString(window_title_.c_str()));
    //mainWindow->setGeometry(window_left, window_top, width, height);
    //if (maximized)
    //    mainWindow->showMaximized();

    graphicsScene = new QGraphicsScene(this);

    graphicsView->setScene(graphicsScene);
    graphicsView->scene()->setSceneRect(graphicsView->rect());
    connect(graphicsScene, SIGNAL(changed(const QList<QRectF> &)), graphicsView, SLOT(HandleSceneChanged(const QList<QRectF> &)));
    connect(graphicsScene, SIGNAL(sceneRectChanged(const QRectF &)), SLOT(OnSceneRectChanged(const QRectF &)));

    connect(mainWindow, SIGNAL(WindowResizeEvent(int,int)), graphicsView, SLOT(Resize(int,int)));

    mainWindow->LoadWindowSettingsFromFile();
    graphicsView->Resize(mainWindow->width(), mainWindow->height());

    graphicsView->show();
    mainWindow->show();
    viewportWidget->show();

    /// Do a full repaint of the view now that we've shown it.
    graphicsView->MarkViewUndirty();

    owner_->Asset()->RegisterAssetTypeFactory(AssetTypeFactoryPtr(new GenericAssetFactory<QtUiAsset>("QtUiFile")));
}

UiAPI::~UiAPI()
{
    delete mainWindow;
    delete viewportWidget;
}

UiMainWindow *UiAPI::MainWindow() const
{
    return mainWindow;
}

UiGraphicsView *UiAPI::GraphicsView() const
{
    return graphicsView;
}

QGraphicsScene *UiAPI::GraphicsScene() const
{
    return graphicsScene;
}

UiProxyWidget *UiAPI::AddWidgetToScene(QWidget *widget, Qt::WindowFlags flags)
{
    if (!widget)
    {
        LogError("AddWidgetToScene called with a null proxy widget!");
        return 0;
    }

    // QGraphicsProxyWidget maintains symmetry for the following states:
    // state, enabled, visible, geometry, layoutDirection, style, palette,
    // font, cursor, sizeHint, getContentsMargins and windowTitle

    UiProxyWidget *proxy = new UiProxyWidget(widget, flags);
    assert(proxy->widget() == widget);

    // Synchronize windowState flags
    proxy->widget()->setWindowState(widget->windowState());

    AddProxyWidgetToScene(proxy);

    // If the widget has WA_DeleteOnClose on, connect its proxy's visibleChanged()
    // signal to a slot which handles the deletion. This must be done because closing
    // proxy window in our system doesn't yield closeEvent, but hideEvent instead.
    if (widget->testAttribute(Qt::WA_DeleteOnClose))
        connect(proxy, SIGNAL(visibleChanged()), SLOT(DeleteCallingWidgetOnClose()));

    return proxy;
}

bool UiAPI::AddProxyWidgetToScene(UiProxyWidget *widget)
{
    if (!widget)
    {
        LogError("AddWidgetToScene called with a null proxy widget!");
        return false;
    }

    if (!widget->widget())
    {
        LogError("AddWidgetToScene called for proxy widget that does not embed a widget!");
        return false;
    }

    if (widgets.contains(widget))
    {
        LogWarning("AddWidgetToScene: Scene already contains the given widget!");
        return false;
    }

    connect(widget, SIGNAL(destroyed(QObject *)), this, SLOT(OnProxyDestroyed(QObject *)));

    widgets.append(widget);

    if (widget->isVisible())
        widget->hide();

    // If no position has been set for Qt::Dialog widget, use default one so that the window's title
    // bar - or any other critical part, doesn't go outside the view.
    if ((widget->windowFlags() & Qt::Dialog) && widget->pos() == QPointF() && !(widget->widget()->windowState() & Qt::WindowFullScreen))
        widget->setPos(10.0, 200.0);

    // Resize full screen widgets to fit the scene rect.
    if (widget->widget()->windowState() & Qt::WindowFullScreen)
    {
        fullScreenWidgets << widget;
        widget->setGeometry(graphicsScene->sceneRect().toRect());
    }

    graphicsScene->addItem(widget);
    return true;
}

void UiAPI::RemoveWidgetFromScene(QWidget *widget)
{
    if (!widget)
        return;

    if (graphicsScene)
        graphicsScene->removeItem(widget->graphicsProxyWidget());
    widgets.removeOne(widget->graphicsProxyWidget());
    fullScreenWidgets.removeOne(widget->graphicsProxyWidget());
}

void UiAPI::RemoveWidgetFromScene(QGraphicsProxyWidget *widget)
{
    if (!widget)
        return;

    if (graphicsScene)
        graphicsScene->removeItem(widget);
    widgets.removeOne(widget);
    fullScreenWidgets.removeOne(widget);
}

void UiAPI::OnProxyDestroyed(QObject* obj)
{
    // Make sure we don't get dangling pointers
    // Note: at this point it's a QObject, not a QGraphicsProxyWidget anymore
    QGraphicsProxyWidget* proxy = static_cast<QGraphicsProxyWidget*>(obj);
    widgets.removeOne(proxy);
    fullScreenWidgets.removeOne(proxy);
}

QWidget *UiAPI::LoadFromFile(const QString &filePath, bool addToScene, QWidget *parent)
{
    QWidget *widget = 0;

    if (AssetAPI::ParseAssetRef(filePath) != AssetAPI::AssetRefLocalPath)
    {
        AssetPtr asset = owner->Asset()->GetAsset(filePath);
        if (!asset)
        {
            LogError(("LoadFromFile: Asset \"" + filePath + "\" is not loaded to the asset system. Call RequestAsset prior to use!").toStdString());
            return 0;
        }

        QtUiAsset *uiAsset = dynamic_cast<QtUiAsset*>(asset.get());
        if (!uiAsset)
        {
            LogError(("LoadFromFile: Asset \"" + filePath + "\" is not of type QtUiFile!").toStdString());
            return 0;
        }
        if (!uiAsset->IsLoaded())
        {
            LogError(("LoadFromFile: Asset \"" + filePath + "\" data is not valid!").toStdString());
            return 0;
        }

        // Get the asset data with the assetrefs replaced to point to the disk sources on the current local system.
        QByteArray data = uiAsset->GetRefReplacedAssetData();

        QUiLoader loader;
        QDataStream dataStream(&data, QIODevice::ReadOnly);
        widget = loader.load(dataStream.device(), parent);
    }
    else // The file is from absolute source location.
    {
        QFile file(filePath);
        QUiLoader loader;
        file.open(QFile::ReadOnly);
        widget = loader.load(&file, parent);
    }

    if (!widget)
    {
        LogError(("LoadFromFile: Failed to load widget from file \"" + filePath + "\"!").toStdString());
        return 0;
    }

    if (addToScene && widget)
        AddWidgetToScene(widget);

    return widget;
}

void UiAPI::EmitContextMenuAboutToOpen(QMenu *menu, QList<QObject *> targets)
{
    emit ContextMenuAboutToOpen(menu,targets);
}

void UiAPI::ShowWidget(QWidget *widget) const
{
    if (!widget)
    {
        LogError("ShowWidget called on a null widget!");
        return;
    }

    if (widget->graphicsProxyWidget())
        widget->graphicsProxyWidget()->show();
    else
        widget->show();
}

void UiAPI::HideWidget(QWidget *widget) const
{
    if (!widget)
    {
        LogError("HideWidget called on a null widget!");
        return;
    }

    if (widget->graphicsProxyWidget())
        widget->graphicsProxyWidget()->hide();
    else
        widget->hide();
}

void UiAPI::BringWidgetToFront(QWidget *widget) const
{
    if (!widget)
    {
        LogError("BringWidgetToFront called on a null widget!");
        return;
    }

    ShowWidget(widget);
    graphicsScene->setActiveWindow(widget->graphicsProxyWidget());
    graphicsScene->setFocusItem(widget->graphicsProxyWidget(), Qt::ActiveWindowFocusReason);
}

void UiAPI::BringProxyWidgetToFront(QGraphicsProxyWidget *widget) const
{
    if (!widget)
    {
        LogError("BringWidgetToFront called on a null QGraphicsProxyWidget!");
        return;
    }

    graphicsScene->setActiveWindow(widget);
    graphicsScene->setFocusItem(widget, Qt::ActiveWindowFocusReason);
}

void UiAPI::OnSceneRectChanged(const QRectF &rect)
{
    foreach(QGraphicsProxyWidget *widget, fullScreenWidgets)
        widget->setGeometry(rect);
}

void UiAPI::DeleteCallingWidgetOnClose()
{
    QGraphicsProxyWidget *proxy = dynamic_cast<QGraphicsProxyWidget *>(sender());
    if (proxy && !proxy->isVisible())
        proxy->deleteLater();
}
<commit_msg>Don't download refs of type AssetAPI::AssetRefRelativePath using the AssetAPI in UiAPI::LoadFromFile.<commit_after>// For conditions of distribution and use, see copyright notice in license.txt

#include "DebugOperatorNew.h"

#include "UiAPI.h"
#include "UiMainWindow.h"
#include "UiGraphicsView.h"
#include "QtUiAsset.h"
#include "UiProxyWidget.h"

#include "Framework.h"
#include "AssetAPI.h"
#include "GenericAssetFactory.h"
#include "LoggingFunctions.h"
DEFINE_POCO_LOGGING_FUNCTIONS("UiAPI")

#include <QEvent>
#include <QLayout>
#include <QVBoxLayout>
#include <QScrollBar>
#include <QUiLoader>
#include <QFile>

#include "MemoryLeakCheck.h"

/// The SuppressedPaintWidget is used as a viewport for the main Naali QGraphicsView.
/** Its purpose is to disable all automatic drawing of the QGraphicsView to screen so that
    we can composite an Ogre 3D render with the Qt widgets added to a QGraphicsScene. */
class SuppressedPaintWidget : public QWidget {
public:
    SuppressedPaintWidget(QWidget *parent = 0, Qt::WindowFlags f = 0);
    virtual ~SuppressedPaintWidget() {}

protected:
    virtual bool event(QEvent *event);
    virtual void paintEvent(QPaintEvent *event);
};

SuppressedPaintWidget::SuppressedPaintWidget(QWidget *parent, Qt::WindowFlags f)
:QWidget(parent, f)
{
    setAttribute(Qt::WA_PaintOnScreen);
    setAttribute(Qt::WA_NoSystemBackground);
    setAttribute(Qt::WA_OpaquePaintEvent, true);
}

bool SuppressedPaintWidget::event(QEvent *event)
{
    switch(event->type())
    {
    case QEvent::UpdateRequest:
    case QEvent::Paint:
    case QEvent::Wheel:
    case QEvent::Resize:
        return true;
    default:
        return QWidget::event(event);
    }
}

void SuppressedPaintWidget::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);
}

UiAPI::UiAPI(Foundation::Framework *owner_) :
    owner(owner_),
    mainWindow(0),
    graphicsView(0),
    graphicsScene(0)
{
    if (owner->IsHeadless())
        return;

    mainWindow = new UiMainWindow(owner);
    mainWindow->setAutoFillBackground(false);
    //mainWindow->setUpdatesEnabled(false);

    // Apply the Naali main window icon.
    // Note: this will only affect to a icon at main window left top corner.
    //       The application thumbnail icon must be set by adding icon resource
    //       to viewer project
    QIcon icon("./data/ui/images/icon/naali_logo_32px_RC1.ico");
    mainWindow->setWindowIcon(icon);

    graphicsView = new UiGraphicsView(mainWindow);

    ///\todo Memory leak below, see very end of ~Renderer() for comments.

    // QMainWindow has a layout by default. It will not let you set another.
    // Leave this check here if the window type changes to for example QWidget so we dont crash then.
    if (!mainWindow->layout())
        mainWindow->setLayout(new QVBoxLayout());
    mainWindow->layout()->setMargin(0);
    mainWindow->layout()->setContentsMargins(0,0,0,0);
    mainWindow->layout()->addWidget(graphicsView);

    viewportWidget = new SuppressedPaintWidget();
    graphicsView->setViewport(viewportWidget);
//    viewportWidget->setAttribute(Qt::WA_DontShowOnScreen, true);
    viewportWidget->setGeometry(0, 0, graphicsView->width(), graphicsView->height());
    viewportWidget->setContentsMargins(0,0,0,0);

    mainWindow->setContentsMargins(0,0,0,0);
    graphicsView->setContentsMargins(0,0,0,0);

    graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    graphicsView->horizontalScrollBar()->setValue(0);
    graphicsView->horizontalScrollBar()->setRange(0, 0);

    graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    graphicsView->verticalScrollBar()->setValue(0);
    graphicsView->verticalScrollBar()->setRange(0, 0);

    // Setup Qt's main window with title and geometry
    //mainWindow->setWindowTitle(QString(window_title_.c_str()));
    //mainWindow->setGeometry(window_left, window_top, width, height);
    //if (maximized)
    //    mainWindow->showMaximized();

    graphicsScene = new QGraphicsScene(this);

    graphicsView->setScene(graphicsScene);
    graphicsView->scene()->setSceneRect(graphicsView->rect());
    connect(graphicsScene, SIGNAL(changed(const QList<QRectF> &)), graphicsView, SLOT(HandleSceneChanged(const QList<QRectF> &)));
    connect(graphicsScene, SIGNAL(sceneRectChanged(const QRectF &)), SLOT(OnSceneRectChanged(const QRectF &)));

    connect(mainWindow, SIGNAL(WindowResizeEvent(int,int)), graphicsView, SLOT(Resize(int,int)));

    mainWindow->LoadWindowSettingsFromFile();
    graphicsView->Resize(mainWindow->width(), mainWindow->height());

    graphicsView->show();
    mainWindow->show();
    viewportWidget->show();

    /// Do a full repaint of the view now that we've shown it.
    graphicsView->MarkViewUndirty();

    owner_->Asset()->RegisterAssetTypeFactory(AssetTypeFactoryPtr(new GenericAssetFactory<QtUiAsset>("QtUiFile")));
}

UiAPI::~UiAPI()
{
    delete mainWindow;
    delete viewportWidget;
}

UiMainWindow *UiAPI::MainWindow() const
{
    return mainWindow;
}

UiGraphicsView *UiAPI::GraphicsView() const
{
    return graphicsView;
}

QGraphicsScene *UiAPI::GraphicsScene() const
{
    return graphicsScene;
}

UiProxyWidget *UiAPI::AddWidgetToScene(QWidget *widget, Qt::WindowFlags flags)
{
    if (!widget)
    {
        LogError("AddWidgetToScene called with a null proxy widget!");
        return 0;
    }

    // QGraphicsProxyWidget maintains symmetry for the following states:
    // state, enabled, visible, geometry, layoutDirection, style, palette,
    // font, cursor, sizeHint, getContentsMargins and windowTitle

    UiProxyWidget *proxy = new UiProxyWidget(widget, flags);
    assert(proxy->widget() == widget);

    // Synchronize windowState flags
    proxy->widget()->setWindowState(widget->windowState());

    AddProxyWidgetToScene(proxy);

    // If the widget has WA_DeleteOnClose on, connect its proxy's visibleChanged()
    // signal to a slot which handles the deletion. This must be done because closing
    // proxy window in our system doesn't yield closeEvent, but hideEvent instead.
    if (widget->testAttribute(Qt::WA_DeleteOnClose))
        connect(proxy, SIGNAL(visibleChanged()), SLOT(DeleteCallingWidgetOnClose()));

    return proxy;
}

bool UiAPI::AddProxyWidgetToScene(UiProxyWidget *widget)
{
    if (!widget)
    {
        LogError("AddWidgetToScene called with a null proxy widget!");
        return false;
    }

    if (!widget->widget())
    {
        LogError("AddWidgetToScene called for proxy widget that does not embed a widget!");
        return false;
    }

    if (widgets.contains(widget))
    {
        LogWarning("AddWidgetToScene: Scene already contains the given widget!");
        return false;
    }

    connect(widget, SIGNAL(destroyed(QObject *)), this, SLOT(OnProxyDestroyed(QObject *)));

    widgets.append(widget);

    if (widget->isVisible())
        widget->hide();

    // If no position has been set for Qt::Dialog widget, use default one so that the window's title
    // bar - or any other critical part, doesn't go outside the view.
    if ((widget->windowFlags() & Qt::Dialog) && widget->pos() == QPointF() && !(widget->widget()->windowState() & Qt::WindowFullScreen))
        widget->setPos(10.0, 200.0);

    // Resize full screen widgets to fit the scene rect.
    if (widget->widget()->windowState() & Qt::WindowFullScreen)
    {
        fullScreenWidgets << widget;
        widget->setGeometry(graphicsScene->sceneRect().toRect());
    }

    graphicsScene->addItem(widget);
    return true;
}

void UiAPI::RemoveWidgetFromScene(QWidget *widget)
{
    if (!widget)
        return;

    if (graphicsScene)
        graphicsScene->removeItem(widget->graphicsProxyWidget());
    widgets.removeOne(widget->graphicsProxyWidget());
    fullScreenWidgets.removeOne(widget->graphicsProxyWidget());
}

void UiAPI::RemoveWidgetFromScene(QGraphicsProxyWidget *widget)
{
    if (!widget)
        return;

    if (graphicsScene)
        graphicsScene->removeItem(widget);
    widgets.removeOne(widget);
    fullScreenWidgets.removeOne(widget);
}

void UiAPI::OnProxyDestroyed(QObject* obj)
{
    // Make sure we don't get dangling pointers
    // Note: at this point it's a QObject, not a QGraphicsProxyWidget anymore
    QGraphicsProxyWidget* proxy = static_cast<QGraphicsProxyWidget*>(obj);
    widgets.removeOne(proxy);
    fullScreenWidgets.removeOne(proxy);
}

QWidget *UiAPI::LoadFromFile(const QString &filePath, bool addToScene, QWidget *parent)
{
    QWidget *widget = 0;

    AssetAPI::AssetRefType refType = AssetAPI::ParseAssetRef(filePath);
    if (refType != AssetAPI::AssetRefLocalPath && refType != AssetAPI::AssetRefRelativePath)
    {
        AssetPtr asset = owner->Asset()->GetAsset(filePath);
        if (!asset)
        {
            LogError(("LoadFromFile: Asset \"" + filePath + "\" is not loaded to the asset system. Call RequestAsset prior to use!").toStdString());
            return 0;
        }

        QtUiAsset *uiAsset = dynamic_cast<QtUiAsset*>(asset.get());
        if (!uiAsset)
        {
            LogError(("LoadFromFile: Asset \"" + filePath + "\" is not of type QtUiFile!").toStdString());
            return 0;
        }
        if (!uiAsset->IsLoaded())
        {
            LogError(("LoadFromFile: Asset \"" + filePath + "\" data is not valid!").toStdString());
            return 0;
        }

        // Get the asset data with the assetrefs replaced to point to the disk sources on the current local system.
        QByteArray data = uiAsset->GetRefReplacedAssetData();

        QUiLoader loader;
        QDataStream dataStream(&data, QIODevice::ReadOnly);
        widget = loader.load(dataStream.device(), parent);
    }
    else // The file is from absolute source location.
    {
        QFile file(filePath);
        QUiLoader loader;
        file.open(QFile::ReadOnly);
        widget = loader.load(&file, parent);
    }

    if (!widget)
    {
        LogError(("LoadFromFile: Failed to load widget from file \"" + filePath + "\"!").toStdString());
        return 0;
    }

    if (addToScene && widget)
        AddWidgetToScene(widget);

    return widget;
}

void UiAPI::EmitContextMenuAboutToOpen(QMenu *menu, QList<QObject *> targets)
{
    emit ContextMenuAboutToOpen(menu,targets);
}

void UiAPI::ShowWidget(QWidget *widget) const
{
    if (!widget)
    {
        LogError("ShowWidget called on a null widget!");
        return;
    }

    if (widget->graphicsProxyWidget())
        widget->graphicsProxyWidget()->show();
    else
        widget->show();
}

void UiAPI::HideWidget(QWidget *widget) const
{
    if (!widget)
    {
        LogError("HideWidget called on a null widget!");
        return;
    }

    if (widget->graphicsProxyWidget())
        widget->graphicsProxyWidget()->hide();
    else
        widget->hide();
}

void UiAPI::BringWidgetToFront(QWidget *widget) const
{
    if (!widget)
    {
        LogError("BringWidgetToFront called on a null widget!");
        return;
    }

    ShowWidget(widget);
    graphicsScene->setActiveWindow(widget->graphicsProxyWidget());
    graphicsScene->setFocusItem(widget->graphicsProxyWidget(), Qt::ActiveWindowFocusReason);
}

void UiAPI::BringProxyWidgetToFront(QGraphicsProxyWidget *widget) const
{
    if (!widget)
    {
        LogError("BringWidgetToFront called on a null QGraphicsProxyWidget!");
        return;
    }

    graphicsScene->setActiveWindow(widget);
    graphicsScene->setFocusItem(widget, Qt::ActiveWindowFocusReason);
}

void UiAPI::OnSceneRectChanged(const QRectF &rect)
{
    foreach(QGraphicsProxyWidget *widget, fullScreenWidgets)
        widget->setGeometry(rect);
}

void UiAPI::DeleteCallingWidgetOnClose()
{
    QGraphicsProxyWidget *proxy = dynamic_cast<QGraphicsProxyWidget *>(sender());
    if (proxy && !proxy->isVisible())
        proxy->deleteLater();
}
<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// <string>

// void push_back(charT c)

#include <string>
#include <cassert>

#include "test_macros.h"
#include "min_allocator.h"

struct veryLarge
{
  long long a;
  char b;
};

template <class S>
void
test(S s, typename S::value_type c, S expected)
{
    s.push_back(c);
    LIBCPP_ASSERT(s.__invariants());
    assert(s == expected);
}

int main()
{
    {
    typedef std::string S;
    test(S(), 'a', S(1, 'a'));
    test(S("12345"), 'a', S("12345a"));
    test(S("12345678901234567890"), 'a', S("12345678901234567890a"));
    }
#if TEST_STD_VER >= 11
    {
    typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
    test(S(), 'a', S(1, 'a'));
    test(S("12345"), 'a', S("12345a"));
    test(S("12345678901234567890"), 'a', S("12345678901234567890a"));
    }
#endif
    {
// https://bugs.llvm.org/show_bug.cgi?id=31454
    std::basic_string<veryLarge> s;
    veryLarge vl;
    s.push_back(vl);
    s.push_back(vl);
    s.push_back(vl);
    }
}
<commit_msg>Ooops. I checked in a test for a bug I haven't fixed yet. Temporrarily commented it out.<commit_after>//===----------------------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// <string>

// void push_back(charT c)

#include <string>
#include <cassert>

#include "test_macros.h"
#include "min_allocator.h"

struct veryLarge
{
  long long a;
  char b;
};

template <class S>
void
test(S s, typename S::value_type c, S expected)
{
    s.push_back(c);
    LIBCPP_ASSERT(s.__invariants());
    assert(s == expected);
}

int main()
{
    {
    typedef std::string S;
    test(S(), 'a', S(1, 'a'));
    test(S("12345"), 'a', S("12345a"));
    test(S("12345678901234567890"), 'a', S("12345678901234567890a"));
    }
#if TEST_STD_VER >= 11
    {
    typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
    test(S(), 'a', S(1, 'a'));
    test(S("12345"), 'a', S("12345a"));
    test(S("12345678901234567890"), 'a', S("12345678901234567890a"));
    }
#endif
#if 0
    {
// https://bugs.llvm.org/show_bug.cgi?id=31454
    std::basic_string<veryLarge> s;
    veryLarge vl;
    s.push_back(vl);
    s.push_back(vl);
    s.push_back(vl);
    }
#endif
}
<|endoftext|>


<commit_before>#include "ExternalInput.h"
#include "../WebRtcConnection.h"
#include "../RTPSink.h"
#include <cstdio>

#include <boost/cstdint.hpp>
#include <sys/time.h>
#include <arpa/inet.h>

namespace erizo {

  ExternalInput::ExternalInput(const std::string& inputUrl){
    sourcefbSink_=NULL;
    context_ = NULL;
    sendVideoBuffer_=NULL;
    running_ = false;
    url_ = inputUrl;
  }

  ExternalInput::~ExternalInput(){
    printf("Destructor EI\n");
    this->closeSource();
  }

  int ExternalInput::init(){
    context_ = avformat_alloc_context();
    av_register_all();
    avcodec_register_all();
    avformat_network_init();
    //open rtsp
    printf("trying to open input\n");
    int res = avformat_open_input(&context_, url_.c_str(),NULL,NULL);
    char errbuff[500];
    printf ("RES %d\n", res);
    if(res != 0){
      av_strerror(res, (char*)(&errbuff), 500);
      printf("fail when opening input %s\n", errbuff);
      return res;
    }
    res = avformat_find_stream_info(context_,NULL);
    if(res!=0){
      av_strerror(res, (char*)(&errbuff), 500);
      printf("fail when finding stream info %s\n", errbuff);
      return res;
    }

    VideoCodecInfo info;

    int streamNo = av_find_best_stream(context_, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
    if (streamNo < 0){
      printf("No video stream?\n");
      return streamNo;
    }
    sendVideoBuffer_ = (char*) malloc(2000);

    video_stream_index_ = streamNo;
    AVStream* st = context_->streams[streamNo];
    inCodec_.initDecoder(st->codec);

    bufflen_ = st->codec->width*st->codec->height*3/2;
    decodedBuffer_ = (unsigned char*) malloc(bufflen_);

    MediaInfo om;
    om.proccessorType = RTP_ONLY;
    om.videoCodec.codec = VIDEO_CODEC_VP8;
    om.videoCodec.bitRate = 1000000;
    om.videoCodec.width = 640;
    om.videoCodec.height = 480;
    om.videoCodec.frameRate = 20;
    om.hasVideo = true;

    om.hasAudio = false;
    if (om.hasAudio) {
      om.audioCodec.sampleRate = 8000;
      om.audioCodec.bitRate = 64000;
    }

    op_ = new OutputProcessor();
    op_->init(om, this);

    printf("Success initializing external input for codec %s\n", st->codec->codec_name);
    av_init_packet(&avpacket_);

    AVStream* stream=NULL;
    int cnt = 0;

    thread_ = boost::thread(&ExternalInput::receiveLoop, this);
    running_ = true;
    encodeThread_ = boost::thread(&ExternalInput::encodeLoop, this);
    return true;
  }

  void ExternalInput::closeSource() {
    running_ = false;
    encodeThread_.join();
    thread_.join();
    av_free_packet(&avpacket_);
    if (context_!=NULL)
      avformat_free_context(context_);
    if (sendVideoBuffer_!=NULL)
      free(sendVideoBuffer_);
    if(decodedBuffer_!=NULL)
      free(decodedBuffer_);
  }

  int ExternalInput::sendFirPacket() {
    return 0;
  }

  void ExternalInput::receiveRtpData(unsigned char*rtpdata, int len) {
    if (videoSink_!=NULL){
      memcpy(sendVideoBuffer_, rtpdata, len);
      videoSink_->deliverVideoData(sendVideoBuffer_, len);
    }

  }

  void ExternalInput::receiveLoop(){
    av_read_play(context_);//play RTSP
    int gotDecodedFrame = 0;
    while(av_read_frame(context_,&avpacket_)>=0&& running_==true){//read 100 frames
      if(avpacket_.stream_index == video_stream_index_){//packet is video
        //        packet.stream_index = stream->id;
        inCodec_.decodeVideo(avpacket_.data, avpacket_.size, decodedBuffer_, bufflen_, &gotDecodedFrame);
        RawDataPacket packetR;
        if (gotDecodedFrame){
          packetR.data = decodedBuffer_;
          packetR.length = bufflen_;
          packetR.type = VIDEO;
          queueMutex_.lock();
          packetQueue_.push(packetR);
          queueMutex_.unlock();
          gotDecodedFrame=0;
        }
      }
      av_free_packet(&avpacket_);
      av_init_packet(&avpacket_);
    }
    running_=false;
    av_read_pause(context_);
  }

  void ExternalInput::encodeLoop() {
    while (running_ == true) {
      queueMutex_.lock();
      if (packetQueue_.size() > 0) {
        op_->receiveRawData(packetQueue_.front());
        packetQueue_.pop();

        //      printf("Queue Size! %d\n", packetQueue_.size());
        queueMutex_.unlock();
      } else {
        queueMutex_.unlock();
        usleep(1000);
      }
    }
  }

}

<commit_msg>Fixed error when getting stream info<commit_after>#include "ExternalInput.h"
#include "../WebRtcConnection.h"
#include "../RTPSink.h"
#include <cstdio>

#include <boost/cstdint.hpp>
#include <sys/time.h>
#include <arpa/inet.h>

namespace erizo {

  ExternalInput::ExternalInput(const std::string& inputUrl){
    sourcefbSink_=NULL;
    context_ = NULL;
    sendVideoBuffer_=NULL;
    running_ = false;
    url_ = inputUrl;
  }

  ExternalInput::~ExternalInput(){
    printf("Destructor EI\n");
    this->closeSource();
  }

  int ExternalInput::init(){
    context_ = avformat_alloc_context();
    av_register_all();
    avcodec_register_all();
    avformat_network_init();
    //open rtsp
    printf("trying to open input\n");
    int res = avformat_open_input(&context_, url_.c_str(),NULL,NULL);
    char errbuff[500];
    printf ("RES %d\n", res);
    if(res != 0){
      av_strerror(res, (char*)(&errbuff), 500);
      printf("fail when opening input %s\n", errbuff);
      return res;
    }
    res = avformat_find_stream_info(context_,NULL);
    if(res<0){
      av_strerror(res, (char*)(&errbuff), 500);
      printf("fail when finding stream info %s\n", errbuff);
      return res;
    }

    VideoCodecInfo info;

    int streamNo = av_find_best_stream(context_, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
    if (streamNo < 0){
      printf("No video stream?\n");
      return streamNo;
    }
    sendVideoBuffer_ = (char*) malloc(2000);

    video_stream_index_ = streamNo;
    AVStream* st = context_->streams[streamNo];
    inCodec_.initDecoder(st->codec);

    bufflen_ = st->codec->width*st->codec->height*3/2;
    decodedBuffer_ = (unsigned char*) malloc(bufflen_);

    MediaInfo om;
    om.proccessorType = RTP_ONLY;
    om.videoCodec.codec = VIDEO_CODEC_VP8;
    om.videoCodec.bitRate = 1000000;
    om.videoCodec.width = 640;
    om.videoCodec.height = 480;
    om.videoCodec.frameRate = 20;
    om.hasVideo = true;

    om.hasAudio = false;
    if (om.hasAudio) {
      om.audioCodec.sampleRate = 8000;
      om.audioCodec.bitRate = 64000;
    }

    op_ = new OutputProcessor();
    op_->init(om, this);

    printf("Success initializing external input for codec %s\n", st->codec->codec_name);
    av_init_packet(&avpacket_);

    AVStream* stream=NULL;
    int cnt = 0;

    thread_ = boost::thread(&ExternalInput::receiveLoop, this);
    running_ = true;
    encodeThread_ = boost::thread(&ExternalInput::encodeLoop, this);
    return true;
  }

  void ExternalInput::closeSource() {
    running_ = false;
    encodeThread_.join();
    thread_.join();
    av_free_packet(&avpacket_);
    if (context_!=NULL)
      avformat_free_context(context_);
    if (sendVideoBuffer_!=NULL)
      free(sendVideoBuffer_);
    if(decodedBuffer_!=NULL)
      free(decodedBuffer_);
  }

  int ExternalInput::sendFirPacket() {
    return 0;
  }

  void ExternalInput::receiveRtpData(unsigned char*rtpdata, int len) {
    if (videoSink_!=NULL){
      memcpy(sendVideoBuffer_, rtpdata, len);
      videoSink_->deliverVideoData(sendVideoBuffer_, len);
    }

  }

  void ExternalInput::receiveLoop(){
    av_read_play(context_);//play RTSP
    int gotDecodedFrame = 0;
    while(av_read_frame(context_,&avpacket_)>=0&& running_==true){//read 100 frames
      if(avpacket_.stream_index == video_stream_index_){//packet is video
        //        packet.stream_index = stream->id;
        inCodec_.decodeVideo(avpacket_.data, avpacket_.size, decodedBuffer_, bufflen_, &gotDecodedFrame);
        RawDataPacket packetR;
        if (gotDecodedFrame){
          packetR.data = decodedBuffer_;
          packetR.length = bufflen_;
          packetR.type = VIDEO;
          queueMutex_.lock();
          packetQueue_.push(packetR);
          queueMutex_.unlock();
          gotDecodedFrame=0;
        }
      }
      av_free_packet(&avpacket_);
      av_init_packet(&avpacket_);
    }
    running_=false;
    av_read_pause(context_);
  }

  void ExternalInput::encodeLoop() {
    while (running_ == true) {
      queueMutex_.lock();
      if (packetQueue_.size() > 0) {
        op_->receiveRawData(packetQueue_.front());
        packetQueue_.pop();

        //      printf("Queue Size! %d\n", packetQueue_.size());
        queueMutex_.unlock();
      } else {
        queueMutex_.unlock();
        usleep(1000);
      }
    }
  }

}

<|endoftext|>


<commit_before>// Copyright 2016-2019 Envoy Project Authors
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// NOLINT(namespace-envoy)
#include "proxy_wasm_intrinsics.h"

// Required Proxy-Wasm ABI version.
extern "C" PROXY_WASM_KEEPALIVE void proxy_abi_version_0_1_0() {}

static std::unordered_map<std::string, RootFactory> *root_factories = nullptr;
static std::unordered_map<std::string, ContextFactory> *context_factories = nullptr;
static std::unordered_map<int32_t, std::unique_ptr<ContextBase>> context_map;
static std::unordered_map<std::string, RootContext *> root_context_map;

RegisterContextFactory::RegisterContextFactory(ContextFactory context_factory,
                                               RootFactory root_factory, std::string_view root_id) {
  if (!root_factories) {
    root_factories = new std::unordered_map<std::string, RootFactory>;
    context_factories = new std::unordered_map<std::string, ContextFactory>;
  }
  if (context_factory)
    (*context_factories)[std::string(root_id)] = context_factory;
  if (root_factory)
    (*root_factories)[std::string(root_id)] = root_factory;
}

static Context *ensureContext(uint32_t context_id, uint32_t root_context_id) {
  auto e = context_map.insert(std::make_pair(context_id, nullptr));
  if (e.second) {
    RootContext *root = context_map[root_context_id].get()->asRoot();
    std::string root_id = std::string(root->root_id());
    if (!context_factories) {
      e.first->second = std::make_unique<Context>(context_id, root);
      return e.first->second->asContext();
    }
    auto factory = context_factories->find(root_id);
    if (factory == context_factories->end()) {
      e.first->second = std::make_unique<Context>(context_id, root);
      return e.first->second->asContext();
    } else {
      e.first->second = factory->second(context_id, root);
    }
  }
  return e.first->second->asContext();
}

static RootContext *ensureRootContext(uint32_t context_id) {
  auto it = context_map.find(context_id);
  if (it != context_map.end()) {
    return it->second->asRoot();
  }
  const char *root_id_ptr = nullptr;
  size_t root_id_size = 0;
  CHECK_RESULT(proxy_get_property("plugin_root_id", sizeof("plugin_root_id") - 1, &root_id_ptr,
                                  &root_id_size));
  auto root_id = std::make_unique<WasmData>(root_id_ptr, root_id_size);
  auto root_id_string = root_id->toString();
  if (!root_factories) {
    auto context = std::make_unique<RootContext>(context_id, root_id->view());
    RootContext *root_context = context->asRoot();
    context_map[context_id] = std::move(context);
    root_context_map[root_id_string] = root_context;
    return root_context;
  }
  auto factory = root_factories->find(root_id_string);
  RootContext *root_context;
  if (factory != root_factories->end()) {
    auto context = factory->second(context_id, root_id->view());
    root_context = context->asRoot();
    root_context_map[root_id_string] = root_context;
    context_map[context_id] = std::move(context);
  } else {
    auto context = std::make_unique<RootContext>(context_id, root_id->view());
    root_context = context->asRoot();
    context_map[context_id] = std::move(context);
    root_context_map[root_id_string] = root_context;
  }
  return root_context;
}

ContextBase *getContextBase(uint32_t context_id) {
  auto it = context_map.find(context_id);
  if (it == context_map.end()) {
    return nullptr;
  }
  return it->second.get();
}

Context *getContext(uint32_t context_id) {
  auto it = context_map.find(context_id);
  if (it == context_map.end() || !it->second->asContext()) {
    return nullptr;
  }
  return it->second->asContext();
}

RootContext *getRootContext(uint32_t context_id) {
  auto it = context_map.find(context_id);
  if (it == context_map.end() || !it->second->asRoot()) {
    return nullptr;
  }
  return it->second->asRoot();
}

RootContext *getRoot(std::string_view root_id) {
  auto it = root_context_map.find(std::string(root_id));
  if (it != root_context_map.end()) {
    return it->second;
  }
  return nullptr;
}

extern "C" PROXY_WASM_KEEPALIVE uint32_t proxy_on_vm_start(uint32_t root_context_id,
                                                           uint32_t vm_configuration_size) {
  return getRootContext(root_context_id)->onStart(vm_configuration_size);
}

extern "C" PROXY_WASM_KEEPALIVE uint32_t proxy_validate_configuration(uint32_t root_context_id,
                                                                      uint32_t configuration_size) {
  return getRootContext(root_context_id)->validateConfiguration(configuration_size) ? 1 : 0;
}

extern "C" PROXY_WASM_KEEPALIVE uint32_t proxy_on_configure(uint32_t root_context_id,
                                                            uint32_t configuration_size) {
  return getRootContext(root_context_id)->onConfigure(configuration_size) ? 1 : 0;
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_tick(uint32_t root_context_id) {
  getRootContext(root_context_id)->onTick();
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_context_create(uint32_t context_id,
                                                             uint32_t parent_context_id) {
  if (parent_context_id) {
    ensureContext(context_id, parent_context_id)->onCreate();
  } else {
    ensureRootContext(context_id)->onCreate();
  }
}

extern "C" PROXY_WASM_KEEPALIVE FilterStatus proxy_on_new_connection(uint32_t context_id) {
  return getContext(context_id)->onNewConnection();
}

extern "C" PROXY_WASM_KEEPALIVE FilterStatus proxy_on_downstream_data(uint32_t context_id,
                                                                      uint32_t data_length,
                                                                      uint32_t end_of_stream) {
  return getContext(context_id)
      ->onDownstreamData(static_cast<size_t>(data_length), end_of_stream != 0);
}

extern "C" PROXY_WASM_KEEPALIVE FilterStatus proxy_on_upstream_data(uint32_t context_id,
                                                                    uint32_t data_length,
                                                                    uint32_t end_of_stream) {
  return getContext(context_id)
      ->onUpstreamData(static_cast<size_t>(data_length), end_of_stream != 0);
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_downstream_connection_close(uint32_t context_id,
                                                                          uint32_t close_type) {
  return getContext(context_id)->onDownstreamConnectionClose(static_cast<CloseType>(close_type));
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_upstream_connection_close(uint32_t context_id,
                                                                        uint32_t close_type) {
  return getContext(context_id)->onUpstreamConnectionClose(static_cast<CloseType>(close_type));
}

extern "C" PROXY_WASM_KEEPALIVE FilterHeadersStatus
proxy_on_request_headers(uint32_t context_id, uint32_t headers, uint32_t end_of_stream) {
  return getContext(context_id)->onRequestHeaders(headers, end_of_stream != 0);
}

extern "C" PROXY_WASM_KEEPALIVE FilterMetadataStatus proxy_on_request_metadata(uint32_t context_id,
                                                                               uint32_t elements) {
  return getContext(context_id)->onRequestMetadata(elements);
}

extern "C" PROXY_WASM_KEEPALIVE FilterDataStatus proxy_on_request_body(uint32_t context_id,
                                                                       uint32_t body_buffer_length,
                                                                       uint32_t end_of_stream) {
  return getContext(context_id)
      ->onRequestBody(static_cast<size_t>(body_buffer_length), end_of_stream != 0);
}

extern "C" PROXY_WASM_KEEPALIVE FilterTrailersStatus proxy_on_request_trailers(uint32_t context_id,
                                                                               uint32_t trailers) {
  return getContext(context_id)->onRequestTrailers(trailers);
}

extern "C" PROXY_WASM_KEEPALIVE FilterHeadersStatus
proxy_on_response_headers(uint32_t context_id, uint32_t headers, uint32_t end_of_stream) {
  return getContext(context_id)->onResponseHeaders(headers, end_of_stream != 0);
}

extern "C" PROXY_WASM_KEEPALIVE FilterMetadataStatus proxy_on_response_metadata(uint32_t context_id,
                                                                                uint32_t elements) {
  return getContext(context_id)->onResponseMetadata(elements);
}

extern "C" PROXY_WASM_KEEPALIVE FilterDataStatus proxy_on_response_body(uint32_t context_id,
                                                                        uint32_t body_buffer_length,
                                                                        uint32_t end_of_stream) {
  return getContext(context_id)
      ->onResponseBody(static_cast<size_t>(body_buffer_length), end_of_stream != 0);
}

extern "C" PROXY_WASM_KEEPALIVE FilterTrailersStatus proxy_on_response_trailers(uint32_t context_id,
                                                                                uint32_t trailers) {
  return getContext(context_id)->onResponseTrailers(trailers);
}

extern "C" PROXY_WASM_KEEPALIVE uint32_t proxy_on_done(uint32_t context_id) {
  return getContextBase(context_id)->onDoneBase();
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_log(uint32_t context_id) {
  getContext(context_id)->onLog();
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_delete(uint32_t context_id) {
  getContextBase(context_id)->onDelete();
  context_map.erase(context_id);
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_http_call_response(uint32_t context_id,
                                                                 uint32_t token, uint32_t headers,
                                                                 uint32_t body_size,
                                                                 uint32_t trailers) {
  getRootContext(context_id)
      ->onHttpCallResponse(token, headers, static_cast<size_t>(body_size), trailers);
}

extern "C" PROXY_WASM_KEEPALIVE void
proxy_on_grpc_receive_initial_metadata(uint32_t context_id, uint32_t token, uint32_t headers) {
  getRootContext(context_id)->onGrpcReceiveInitialMetadata(token, headers);
}

extern "C" PROXY_WASM_KEEPALIVE void
proxy_on_grpc_receive_trailing_metadata(uint32_t context_id, uint32_t token, uint32_t trailers) {
  getRootContext(context_id)->onGrpcReceiveTrailingMetadata(token, trailers);
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_grpc_receive(uint32_t context_id, uint32_t token,
                                                           uint32_t response_size) {
  getRootContext(context_id)->onGrpcReceive(token, static_cast<size_t>(response_size));
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_grpc_close(uint32_t context_id, uint32_t token,
                                                         uint32_t status_code) {
  getRootContext(context_id)->onGrpcClose(token, static_cast<GrpcStatus>(status_code));
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_queue_ready(uint32_t context_id, uint32_t token) {
  getRootContext(context_id)->onQueueReady(token);
}

extern "C" PROXY_WASM_KEEPALIVE void
proxy_on_foreign_function(uint32_t context_id, uint32_t foreign_function_id, uint32_t data_size) {
  getContextBase(context_id)->onForeignFunction(foreign_function_id, data_size);
}
<commit_msg>Bump Proxy-Wasm ABI version to 0.2.0. (#39)<commit_after>// Copyright 2016-2019 Envoy Project Authors
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// NOLINT(namespace-envoy)
#include "proxy_wasm_intrinsics.h"

// Required Proxy-Wasm ABI version.
extern "C" PROXY_WASM_KEEPALIVE void proxy_abi_version_0_2_0() {}

static std::unordered_map<std::string, RootFactory> *root_factories = nullptr;
static std::unordered_map<std::string, ContextFactory> *context_factories = nullptr;
static std::unordered_map<int32_t, std::unique_ptr<ContextBase>> context_map;
static std::unordered_map<std::string, RootContext *> root_context_map;

RegisterContextFactory::RegisterContextFactory(ContextFactory context_factory,
                                               RootFactory root_factory, std::string_view root_id) {
  if (!root_factories) {
    root_factories = new std::unordered_map<std::string, RootFactory>;
    context_factories = new std::unordered_map<std::string, ContextFactory>;
  }
  if (context_factory)
    (*context_factories)[std::string(root_id)] = context_factory;
  if (root_factory)
    (*root_factories)[std::string(root_id)] = root_factory;
}

static Context *ensureContext(uint32_t context_id, uint32_t root_context_id) {
  auto e = context_map.insert(std::make_pair(context_id, nullptr));
  if (e.second) {
    RootContext *root = context_map[root_context_id].get()->asRoot();
    std::string root_id = std::string(root->root_id());
    if (!context_factories) {
      e.first->second = std::make_unique<Context>(context_id, root);
      return e.first->second->asContext();
    }
    auto factory = context_factories->find(root_id);
    if (factory == context_factories->end()) {
      e.first->second = std::make_unique<Context>(context_id, root);
      return e.first->second->asContext();
    } else {
      e.first->second = factory->second(context_id, root);
    }
  }
  return e.first->second->asContext();
}

static RootContext *ensureRootContext(uint32_t context_id) {
  auto it = context_map.find(context_id);
  if (it != context_map.end()) {
    return it->second->asRoot();
  }
  const char *root_id_ptr = nullptr;
  size_t root_id_size = 0;
  CHECK_RESULT(proxy_get_property("plugin_root_id", sizeof("plugin_root_id") - 1, &root_id_ptr,
                                  &root_id_size));
  auto root_id = std::make_unique<WasmData>(root_id_ptr, root_id_size);
  auto root_id_string = root_id->toString();
  if (!root_factories) {
    auto context = std::make_unique<RootContext>(context_id, root_id->view());
    RootContext *root_context = context->asRoot();
    context_map[context_id] = std::move(context);
    root_context_map[root_id_string] = root_context;
    return root_context;
  }
  auto factory = root_factories->find(root_id_string);
  RootContext *root_context;
  if (factory != root_factories->end()) {
    auto context = factory->second(context_id, root_id->view());
    root_context = context->asRoot();
    root_context_map[root_id_string] = root_context;
    context_map[context_id] = std::move(context);
  } else {
    auto context = std::make_unique<RootContext>(context_id, root_id->view());
    root_context = context->asRoot();
    context_map[context_id] = std::move(context);
    root_context_map[root_id_string] = root_context;
  }
  return root_context;
}

ContextBase *getContextBase(uint32_t context_id) {
  auto it = context_map.find(context_id);
  if (it == context_map.end()) {
    return nullptr;
  }
  return it->second.get();
}

Context *getContext(uint32_t context_id) {
  auto it = context_map.find(context_id);
  if (it == context_map.end() || !it->second->asContext()) {
    return nullptr;
  }
  return it->second->asContext();
}

RootContext *getRootContext(uint32_t context_id) {
  auto it = context_map.find(context_id);
  if (it == context_map.end() || !it->second->asRoot()) {
    return nullptr;
  }
  return it->second->asRoot();
}

RootContext *getRoot(std::string_view root_id) {
  auto it = root_context_map.find(std::string(root_id));
  if (it != root_context_map.end()) {
    return it->second;
  }
  return nullptr;
}

extern "C" PROXY_WASM_KEEPALIVE uint32_t proxy_on_vm_start(uint32_t root_context_id,
                                                           uint32_t vm_configuration_size) {
  return getRootContext(root_context_id)->onStart(vm_configuration_size);
}

extern "C" PROXY_WASM_KEEPALIVE uint32_t proxy_validate_configuration(uint32_t root_context_id,
                                                                      uint32_t configuration_size) {
  return getRootContext(root_context_id)->validateConfiguration(configuration_size) ? 1 : 0;
}

extern "C" PROXY_WASM_KEEPALIVE uint32_t proxy_on_configure(uint32_t root_context_id,
                                                            uint32_t configuration_size) {
  return getRootContext(root_context_id)->onConfigure(configuration_size) ? 1 : 0;
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_tick(uint32_t root_context_id) {
  getRootContext(root_context_id)->onTick();
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_context_create(uint32_t context_id,
                                                             uint32_t parent_context_id) {
  if (parent_context_id) {
    ensureContext(context_id, parent_context_id)->onCreate();
  } else {
    ensureRootContext(context_id)->onCreate();
  }
}

extern "C" PROXY_WASM_KEEPALIVE FilterStatus proxy_on_new_connection(uint32_t context_id) {
  return getContext(context_id)->onNewConnection();
}

extern "C" PROXY_WASM_KEEPALIVE FilterStatus proxy_on_downstream_data(uint32_t context_id,
                                                                      uint32_t data_length,
                                                                      uint32_t end_of_stream) {
  return getContext(context_id)
      ->onDownstreamData(static_cast<size_t>(data_length), end_of_stream != 0);
}

extern "C" PROXY_WASM_KEEPALIVE FilterStatus proxy_on_upstream_data(uint32_t context_id,
                                                                    uint32_t data_length,
                                                                    uint32_t end_of_stream) {
  return getContext(context_id)
      ->onUpstreamData(static_cast<size_t>(data_length), end_of_stream != 0);
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_downstream_connection_close(uint32_t context_id,
                                                                          uint32_t close_type) {
  return getContext(context_id)->onDownstreamConnectionClose(static_cast<CloseType>(close_type));
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_upstream_connection_close(uint32_t context_id,
                                                                        uint32_t close_type) {
  return getContext(context_id)->onUpstreamConnectionClose(static_cast<CloseType>(close_type));
}

extern "C" PROXY_WASM_KEEPALIVE FilterHeadersStatus
proxy_on_request_headers(uint32_t context_id, uint32_t headers, uint32_t end_of_stream) {
  return getContext(context_id)->onRequestHeaders(headers, end_of_stream != 0);
}

extern "C" PROXY_WASM_KEEPALIVE FilterMetadataStatus proxy_on_request_metadata(uint32_t context_id,
                                                                               uint32_t elements) {
  return getContext(context_id)->onRequestMetadata(elements);
}

extern "C" PROXY_WASM_KEEPALIVE FilterDataStatus proxy_on_request_body(uint32_t context_id,
                                                                       uint32_t body_buffer_length,
                                                                       uint32_t end_of_stream) {
  return getContext(context_id)
      ->onRequestBody(static_cast<size_t>(body_buffer_length), end_of_stream != 0);
}

extern "C" PROXY_WASM_KEEPALIVE FilterTrailersStatus proxy_on_request_trailers(uint32_t context_id,
                                                                               uint32_t trailers) {
  return getContext(context_id)->onRequestTrailers(trailers);
}

extern "C" PROXY_WASM_KEEPALIVE FilterHeadersStatus
proxy_on_response_headers(uint32_t context_id, uint32_t headers, uint32_t end_of_stream) {
  return getContext(context_id)->onResponseHeaders(headers, end_of_stream != 0);
}

extern "C" PROXY_WASM_KEEPALIVE FilterMetadataStatus proxy_on_response_metadata(uint32_t context_id,
                                                                                uint32_t elements) {
  return getContext(context_id)->onResponseMetadata(elements);
}

extern "C" PROXY_WASM_KEEPALIVE FilterDataStatus proxy_on_response_body(uint32_t context_id,
                                                                        uint32_t body_buffer_length,
                                                                        uint32_t end_of_stream) {
  return getContext(context_id)
      ->onResponseBody(static_cast<size_t>(body_buffer_length), end_of_stream != 0);
}

extern "C" PROXY_WASM_KEEPALIVE FilterTrailersStatus proxy_on_response_trailers(uint32_t context_id,
                                                                                uint32_t trailers) {
  return getContext(context_id)->onResponseTrailers(trailers);
}

extern "C" PROXY_WASM_KEEPALIVE uint32_t proxy_on_done(uint32_t context_id) {
  return getContextBase(context_id)->onDoneBase();
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_log(uint32_t context_id) {
  getContext(context_id)->onLog();
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_delete(uint32_t context_id) {
  getContextBase(context_id)->onDelete();
  context_map.erase(context_id);
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_http_call_response(uint32_t context_id,
                                                                 uint32_t token, uint32_t headers,
                                                                 uint32_t body_size,
                                                                 uint32_t trailers) {
  getRootContext(context_id)
      ->onHttpCallResponse(token, headers, static_cast<size_t>(body_size), trailers);
}

extern "C" PROXY_WASM_KEEPALIVE void
proxy_on_grpc_receive_initial_metadata(uint32_t context_id, uint32_t token, uint32_t headers) {
  getRootContext(context_id)->onGrpcReceiveInitialMetadata(token, headers);
}

extern "C" PROXY_WASM_KEEPALIVE void
proxy_on_grpc_receive_trailing_metadata(uint32_t context_id, uint32_t token, uint32_t trailers) {
  getRootContext(context_id)->onGrpcReceiveTrailingMetadata(token, trailers);
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_grpc_receive(uint32_t context_id, uint32_t token,
                                                           uint32_t response_size) {
  getRootContext(context_id)->onGrpcReceive(token, static_cast<size_t>(response_size));
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_grpc_close(uint32_t context_id, uint32_t token,
                                                         uint32_t status_code) {
  getRootContext(context_id)->onGrpcClose(token, static_cast<GrpcStatus>(status_code));
}

extern "C" PROXY_WASM_KEEPALIVE void proxy_on_queue_ready(uint32_t context_id, uint32_t token) {
  getRootContext(context_id)->onQueueReady(token);
}

extern "C" PROXY_WASM_KEEPALIVE void
proxy_on_foreign_function(uint32_t context_id, uint32_t foreign_function_id, uint32_t data_size) {
  getContextBase(context_id)->onForeignFunction(foreign_function_id, data_size);
}
<|endoftext|>


<commit_before>#include "WebSocks.h"
#include "Log.h"

#ifdef WITH_EVENTS
#include "ClientContext.h"
#include "Identity.h"
#include "Destination.h"
#include "Streaming.h"
#include <functional>

#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>

#include <boost/property_tree/ini_parser.hpp>
#define GCC47_BOOST149 ((BOOST_VERSION == 104900) && (__GNUC__ == 4) && (__GNUC_MINOR__ >= 7))
#if !GCC47_BOOST149
#include <boost/property_tree/json_parser.hpp>
#endif

namespace i2p
{
namespace client
{
  typedef websocketpp::server<websocketpp::config::asio> WebSocksServerImpl;

  typedef std::function<void(std::shared_ptr<i2p::stream::Stream>)> StreamConnectFunc;

  struct IWebSocksConn
  {
    virtual void Close() = 0;
    virtual void GotMessage(const websocketpp::connection_hdl & conn, WebSocksServerImpl::message_ptr msg) = 0;
  };

  typedef std::shared_ptr<IWebSocksConn> WebSocksConn_ptr;

  WebSocksConn_ptr CreateWebSocksConn(const websocketpp::connection_hdl & conn, WebSocksImpl * parent);

	class WebSocksImpl
	{

    typedef std::mutex mutex_t;
    typedef std::unique_lock<mutex_t> lock_t;

    typedef std::shared_ptr<ClientDestination> Destination_t;
  public:

    typedef WebSocksServerImpl ServerImpl;
    typedef ServerImpl::message_ptr MessagePtr;

		WebSocksImpl(const std::string & addr, int port) :
      m_Run(false),
      m_Addr(addr),
      m_Port(port),
      m_Thread(nullptr)
		{
      m_Server.init_asio();
      m_Server.set_open_handler(std::bind(&WebSocksImpl::ConnOpened, this, std::placeholders::_1));
      i2p::data::PrivateKeys k = i2p::data::PrivateKeys::CreateRandomKeys(i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519);
      m_Dest = std::make_shared<ClientDestination>(k, false);
		}

    ServerImpl::connection_ptr GetConn(const websocketpp::connection_hdl & conn)
    {
      return m_Server.get_con_from_hdl(conn);
    }

    void CloseConn(const websocketpp::connection_hdl & conn)
    {
      auto c = GetConn(conn);
      if(c) c->close(websocketpp::close::status::normal, "closed");
    }

    void CreateStreamTo(const std::string & addr, int port, StreamConnectFunc complete)
    {
      auto & addressbook = i2p::client::context.GetAddressBook();
      i2p::data::IdentHash ident;
      if(addressbook.GetIdentHash(addr, ident)) {
        // address found
        m_Dest->CreateStream(complete, ident, port);
      } else {
        // not found
        complete(nullptr);
      }
    }

    void ConnOpened(websocketpp::connection_hdl conn)
    {
      m_Conns.push_back(CreateWebSocksConn(conn, this));
    }

    void Start()
    {
      if(m_Run) return; // already started
      m_Server.listen(boost::asio::ip::address::from_string(m_Addr), m_Port);
      m_Server.start_accept();
      m_Run = true;
      m_Thread = new std::thread([&] (){
          while(m_Run) {
            try {
              m_Server.run();
            } catch( std::exception & ex) {
              LogPrint(eLogError, "Websocks runtime exception: ", ex.what());
            }
          }
      });
      m_Dest->Start();
    }

    void Stop()
    {
      for(const auto & conn : m_Conns)
        conn->Close();

      m_Dest->Stop();
      m_Run = false;
      m_Server.stop();
      if(m_Thread) {
        m_Thread->join();
        delete m_Thread;
      }
      m_Thread = nullptr;
    }

  private:
    std::vector<WebSocksConn_ptr> m_Conns;
    bool m_Run;
    ServerImpl m_Server;
    std::string m_Addr;
    int m_Port;
    std::thread * m_Thread;
    Destination_t m_Dest;
	};

  struct WebSocksConn : public IWebSocksConn
  {
    enum ConnState
    {
      eWSCInitial,
      eWSCTryConnect,
      eWSCFailConnect,
      eWSCOkayConnect,
      eWSCClose,
      eWSCEnd
    };

    typedef WebSocksServerImpl ServerImpl;
    typedef ServerImpl::message_ptr Message_t;
    typedef websocketpp::connection_hdl ServerConn;
    typedef std::shared_ptr<ClientDestination> Destination_t;
    typedef std::shared_ptr<i2p::stream::StreamingDestination> StreamDest_t;
    typedef std::shared_ptr<i2p::stream::Stream> Stream_t;

    ServerConn m_Conn;
    Stream_t m_Stream;
    ConnState m_State;
    WebSocksImpl * m_Parent;
    std::string m_RemoteAddr;
    int m_RemotePort;
    uint8_t m_RecvBuf[2048];

    WebSocksConn(const ServerConn & conn, WebSocksImpl * parent) :
      m_Conn(conn),
      m_Stream(nullptr),
      m_State(eWSCInitial),
      m_Parent(parent)
    {

    }

    ~WebSocksConn()
    {
      Close();
    }

    void EnterState(ConnState state)
    {
      LogPrint(eLogDebug, "websocks: state ", m_State, " -> ", state);
      switch(m_State)
      {
      case eWSCInitial:
        if (state == eWSCClose) {
          m_State = eWSCClose;
          // connection was opened but never used
          LogPrint(eLogInfo, "websocks: connection closed but never used");
          Close();
          return;
        } else if (state == eWSCTryConnect) {
          // we will try to connect
          m_State = eWSCTryConnect;
          m_Parent->CreateStreamTo(m_RemoteAddr, m_RemotePort, std::bind(&WebSocksConn::ConnectResult, this, std::placeholders::_1));
        } else {
          LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state);
        }
        return;
      case eWSCTryConnect:
        if(state == eWSCOkayConnect) {
          // we connected okay
          LogPrint(eLogDebug, "websocks: connected to ", m_RemoteAddr, ":", m_RemotePort);
          SendResponse("");
          m_State = eWSCOkayConnect;
        } else if(state == eWSCFailConnect) {
          // we did not connect okay
          LogPrint(eLogDebug, "websocks: failed to connect to ", m_RemoteAddr, ":", m_RemotePort);
          SendResponse("failed to connect");
          m_State = eWSCFailConnect;
          EnterState(eWSCInitial);
        } else if(state == eWSCClose) {
          // premature close
          LogPrint(eLogWarning, "websocks: websocket connection closed prematurely");
          m_State = eWSCClose;
        } else {
          LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state);
        }
        return;
      case eWSCFailConnect:
        if (state == eWSCInitial) {
          // reset to initial state so we can try connecting again
          m_RemoteAddr = "";
          m_RemotePort = 0;
          LogPrint(eLogDebug, "websocks: reset websocket conn to initial state");
          m_State = eWSCInitial;
        } else if (state == eWSCClose) {
          // we are going to close the connection
          m_State = eWSCClose;
          Close();
        } else {
          LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state);
        }
        return;
      case eWSCOkayConnect:
        if(state == eWSCClose) {
          // graceful close
          m_State = eWSCClose;
          Close();
        } else {
          LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state);
        }
      case eWSCClose:
        if(state == eWSCEnd) {
          LogPrint(eLogDebug, "websocks: socket ended");
        } else {
          LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state);
        }
        return;
      default:
        LogPrint(eLogError, "websocks: bad state ", m_State);
      }
    }

    void StartForwarding()
    {
      LogPrint(eLogDebug, "websocks: begin forwarding data");
			uint8_t b[1];
			m_Stream->Send(b, 0);
      AsyncRecv();
    }

    void HandleAsyncRecv(const boost::system::error_code &ec, std::size_t n)
    {
      if(ec) {
        // error
        LogPrint(eLogWarning, "websocks: connection error ", ec.message());
        EnterState(eWSCClose);
      } else {
        // forward data
        LogPrint(eLogDebug, "websocks recv ", n);

				std::string str((char*)m_RecvBuf, n);
				auto conn = m_Parent->GetConn(m_Conn);
				if(!conn)  {
					LogPrint(eLogWarning, "websocks: connection is gone");
					EnterState(eWSCClose);
					return;
				}
				conn->send(str);
				AsyncRecv();

      }
    }

    void AsyncRecv()
    {
      m_Stream->AsyncReceive(
        boost::asio::buffer(m_RecvBuf, sizeof(m_RecvBuf)),
        std::bind(&WebSocksConn::HandleAsyncRecv, this, std::placeholders::_1, std::placeholders::_2), 60);
    }

    /** @brief send error message or empty string for success */
    void SendResponse(const std::string & errormsg)
    {
      boost::property_tree::ptree resp;
      if(errormsg.size()) {
        resp.put("error", errormsg);
        resp.put("success", 0);
      } else {
        resp.put("success", 1);
      }
      std::ostringstream ss;
      write_json(ss, resp);
      auto conn = m_Parent->GetConn(m_Conn);
      if(conn) conn->send(ss.str());
    }

    void ConnectResult(Stream_t stream)
    {
      m_Stream = stream;
      if(m_State == eWSCClose) {
        // premature close of websocket
        Close();
        return;
      }
      if(m_Stream) {
        // connect good
        EnterState(eWSCOkayConnect);
				StartForwarding();
      } else {
        // connect failed
        EnterState(eWSCFailConnect);
      }
    }

    virtual void GotMessage(const websocketpp::connection_hdl & conn, WebSocksServerImpl::message_ptr msg)
    {
      (void) conn;
      std::string payload = msg->get_payload();
      if(m_State == eWSCOkayConnect)
      {
        // forward to server
        LogPrint(eLogDebug, "websocks: forward ", payload.size());
        m_Stream->Send((uint8_t*)payload.c_str(), payload.size());
      } else if (m_State == eWSCInitial) {
        // recv connect request
        auto itr = payload.find(":");
        if(itr == std::string::npos) {
          // no port
          m_RemotePort = 0;
          m_RemoteAddr = payload;
        } else {
          // includes port
          m_RemotePort = std::stoi(payload.substr(itr+1));
          m_RemoteAddr = payload.substr(0, itr);
        }
        EnterState(eWSCTryConnect);
      } else {
        // wtf?
        LogPrint(eLogWarning, "websocks: got message in invalid state ", m_State);
      }
    }

    virtual void Close()
    {
      if(m_State == eWSCClose) {
        LogPrint(eLogDebug, "websocks: closing connection");
        if(m_Stream) m_Stream->Close();
        m_Parent->CloseConn(m_Conn);
        EnterState(eWSCEnd);
      } else {
        EnterState(eWSCClose);
      }
    }
  };

  WebSocksConn_ptr CreateWebSocksConn(const websocketpp::connection_hdl & conn, WebSocksImpl * parent)
  {
    auto ptr = std::make_shared<WebSocksConn>(conn, parent);
    auto c = parent->GetConn(conn);
    c->set_message_handler(std::bind(&WebSocksConn::GotMessage, ptr.get(), std::placeholders::_1, std::placeholders::_2));
    return ptr;
  }

}
}
#else

// no websocket support

namespace i2p
{
namespace client
{
	class WebSocksImpl
	{
	public:
		WebSocks(const std::string & addr, int port) {}
		~WebSocks(){}
		void Start()
		{
			LogPrint(eLogInfo, "WebSockets not enabled on compile time");
		}

		void Stop() {}
	};
}
}

#endif
namespace i2p
{
namespace client
{
	WebSocks::WebSocks(const std::string & addr, int port) : m_Impl(new WebSocksImpl(addr, port)) {}
	WebSocks::~WebSocks() { delete m_Impl; }

	void WebSocks::Start()
	{
		m_Impl->Start();
	}

	void WebSocks::Stop()
	{
		m_Impl->Stop();
	}
}
}
<commit_msg>fix typo<commit_after>#include "WebSocks.h"
#include "Log.h"
#include <string>

#ifdef WITH_EVENTS
#include "ClientContext.h"
#include "Identity.h"
#include "Destination.h"
#include "Streaming.h"
#include <functional>

#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>

#include <boost/property_tree/ini_parser.hpp>
#define GCC47_BOOST149 ((BOOST_VERSION == 104900) && (__GNUC__ == 4) && (__GNUC_MINOR__ >= 7))
#if !GCC47_BOOST149
#include <boost/property_tree/json_parser.hpp>
#endif

namespace i2p
{
namespace client
{
  typedef websocketpp::server<websocketpp::config::asio> WebSocksServerImpl;

  typedef std::function<void(std::shared_ptr<i2p::stream::Stream>)> StreamConnectFunc;

  struct IWebSocksConn
  {
    virtual void Close() = 0;
    virtual void GotMessage(const websocketpp::connection_hdl & conn, WebSocksServerImpl::message_ptr msg) = 0;
  };

  typedef std::shared_ptr<IWebSocksConn> WebSocksConn_ptr;

  WebSocksConn_ptr CreateWebSocksConn(const websocketpp::connection_hdl & conn, WebSocksImpl * parent);

	class WebSocksImpl
	{

    typedef std::mutex mutex_t;
    typedef std::unique_lock<mutex_t> lock_t;

    typedef std::shared_ptr<ClientDestination> Destination_t;
  public:

    typedef WebSocksServerImpl ServerImpl;
    typedef ServerImpl::message_ptr MessagePtr;

		WebSocksImpl(const std::string & addr, int port) :
      m_Run(false),
      m_Addr(addr),
      m_Port(port),
      m_Thread(nullptr)
		{
      m_Server.init_asio();
      m_Server.set_open_handler(std::bind(&WebSocksImpl::ConnOpened, this, std::placeholders::_1));
      i2p::data::PrivateKeys k = i2p::data::PrivateKeys::CreateRandomKeys(i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519);
      m_Dest = std::make_shared<ClientDestination>(k, false);
		}

    ServerImpl::connection_ptr GetConn(const websocketpp::connection_hdl & conn)
    {
      return m_Server.get_con_from_hdl(conn);
    }

    void CloseConn(const websocketpp::connection_hdl & conn)
    {
      auto c = GetConn(conn);
      if(c) c->close(websocketpp::close::status::normal, "closed");
    }

    void CreateStreamTo(const std::string & addr, int port, StreamConnectFunc complete)
    {
      auto & addressbook = i2p::client::context.GetAddressBook();
      i2p::data::IdentHash ident;
      if(addressbook.GetIdentHash(addr, ident)) {
        // address found
        m_Dest->CreateStream(complete, ident, port);
      } else {
        // not found
        complete(nullptr);
      }
    }

    void ConnOpened(websocketpp::connection_hdl conn)
    {
      m_Conns.push_back(CreateWebSocksConn(conn, this));
    }

    void Start()
    {
      if(m_Run) return; // already started
      m_Server.listen(boost::asio::ip::address::from_string(m_Addr), m_Port);
      m_Server.start_accept();
      m_Run = true;
      m_Thread = new std::thread([&] (){
          while(m_Run) {
            try {
              m_Server.run();
            } catch( std::exception & ex) {
              LogPrint(eLogError, "Websocks runtime exception: ", ex.what());
            }
          }
      });
      m_Dest->Start();
    }

    void Stop()
    {
      for(const auto & conn : m_Conns)
        conn->Close();

      m_Dest->Stop();
      m_Run = false;
      m_Server.stop();
      if(m_Thread) {
        m_Thread->join();
        delete m_Thread;
      }
      m_Thread = nullptr;
    }

  private:
    std::vector<WebSocksConn_ptr> m_Conns;
    bool m_Run;
    ServerImpl m_Server;
    std::string m_Addr;
    int m_Port;
    std::thread * m_Thread;
    Destination_t m_Dest;
	};

  struct WebSocksConn : public IWebSocksConn
  {
    enum ConnState
    {
      eWSCInitial,
      eWSCTryConnect,
      eWSCFailConnect,
      eWSCOkayConnect,
      eWSCClose,
      eWSCEnd
    };

    typedef WebSocksServerImpl ServerImpl;
    typedef ServerImpl::message_ptr Message_t;
    typedef websocketpp::connection_hdl ServerConn;
    typedef std::shared_ptr<ClientDestination> Destination_t;
    typedef std::shared_ptr<i2p::stream::StreamingDestination> StreamDest_t;
    typedef std::shared_ptr<i2p::stream::Stream> Stream_t;

    ServerConn m_Conn;
    Stream_t m_Stream;
    ConnState m_State;
    WebSocksImpl * m_Parent;
    std::string m_RemoteAddr;
    int m_RemotePort;
    uint8_t m_RecvBuf[2048];

    WebSocksConn(const ServerConn & conn, WebSocksImpl * parent) :
      m_Conn(conn),
      m_Stream(nullptr),
      m_State(eWSCInitial),
      m_Parent(parent)
    {

    }

    ~WebSocksConn()
    {
      Close();
    }

    void EnterState(ConnState state)
    {
      LogPrint(eLogDebug, "websocks: state ", m_State, " -> ", state);
      switch(m_State)
      {
      case eWSCInitial:
        if (state == eWSCClose) {
          m_State = eWSCClose;
          // connection was opened but never used
          LogPrint(eLogInfo, "websocks: connection closed but never used");
          Close();
          return;
        } else if (state == eWSCTryConnect) {
          // we will try to connect
          m_State = eWSCTryConnect;
          m_Parent->CreateStreamTo(m_RemoteAddr, m_RemotePort, std::bind(&WebSocksConn::ConnectResult, this, std::placeholders::_1));
        } else {
          LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state);
        }
        return;
      case eWSCTryConnect:
        if(state == eWSCOkayConnect) {
          // we connected okay
          LogPrint(eLogDebug, "websocks: connected to ", m_RemoteAddr, ":", m_RemotePort);
          SendResponse("");
          m_State = eWSCOkayConnect;
        } else if(state == eWSCFailConnect) {
          // we did not connect okay
          LogPrint(eLogDebug, "websocks: failed to connect to ", m_RemoteAddr, ":", m_RemotePort);
          SendResponse("failed to connect");
          m_State = eWSCFailConnect;
          EnterState(eWSCInitial);
        } else if(state == eWSCClose) {
          // premature close
          LogPrint(eLogWarning, "websocks: websocket connection closed prematurely");
          m_State = eWSCClose;
        } else {
          LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state);
        }
        return;
      case eWSCFailConnect:
        if (state == eWSCInitial) {
          // reset to initial state so we can try connecting again
          m_RemoteAddr = "";
          m_RemotePort = 0;
          LogPrint(eLogDebug, "websocks: reset websocket conn to initial state");
          m_State = eWSCInitial;
        } else if (state == eWSCClose) {
          // we are going to close the connection
          m_State = eWSCClose;
          Close();
        } else {
          LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state);
        }
        return;
      case eWSCOkayConnect:
        if(state == eWSCClose) {
          // graceful close
          m_State = eWSCClose;
          Close();
        } else {
          LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state);
        }
      case eWSCClose:
        if(state == eWSCEnd) {
          LogPrint(eLogDebug, "websocks: socket ended");
        } else {
          LogPrint(eLogWarning, "websocks: invalid state change ", m_State, " -> ", state);
        }
        return;
      default:
        LogPrint(eLogError, "websocks: bad state ", m_State);
      }
    }

    void StartForwarding()
    {
      LogPrint(eLogDebug, "websocks: begin forwarding data");
			uint8_t b[1];
			m_Stream->Send(b, 0);
      AsyncRecv();
    }

    void HandleAsyncRecv(const boost::system::error_code &ec, std::size_t n)
    {
      if(ec) {
        // error
        LogPrint(eLogWarning, "websocks: connection error ", ec.message());
        EnterState(eWSCClose);
      } else {
        // forward data
        LogPrint(eLogDebug, "websocks recv ", n);

				std::string str((char*)m_RecvBuf, n);
				auto conn = m_Parent->GetConn(m_Conn);
				if(!conn)  {
					LogPrint(eLogWarning, "websocks: connection is gone");
					EnterState(eWSCClose);
					return;
				}
				conn->send(str);
				AsyncRecv();

      }
    }

    void AsyncRecv()
    {
      m_Stream->AsyncReceive(
        boost::asio::buffer(m_RecvBuf, sizeof(m_RecvBuf)),
        std::bind(&WebSocksConn::HandleAsyncRecv, this, std::placeholders::_1, std::placeholders::_2), 60);
    }

    /** @brief send error message or empty string for success */
    void SendResponse(const std::string & errormsg)
    {
      boost::property_tree::ptree resp;
      if(errormsg.size()) {
        resp.put("error", errormsg);
        resp.put("success", 0);
      } else {
        resp.put("success", 1);
      }
      std::ostringstream ss;
      write_json(ss, resp);
      auto conn = m_Parent->GetConn(m_Conn);
      if(conn) conn->send(ss.str());
    }

    void ConnectResult(Stream_t stream)
    {
      m_Stream = stream;
      if(m_State == eWSCClose) {
        // premature close of websocket
        Close();
        return;
      }
      if(m_Stream) {
        // connect good
        EnterState(eWSCOkayConnect);
				StartForwarding();
      } else {
        // connect failed
        EnterState(eWSCFailConnect);
      }
    }

    virtual void GotMessage(const websocketpp::connection_hdl & conn, WebSocksServerImpl::message_ptr msg)
    {
      (void) conn;
      std::string payload = msg->get_payload();
      if(m_State == eWSCOkayConnect)
      {
        // forward to server
        LogPrint(eLogDebug, "websocks: forward ", payload.size());
        m_Stream->Send((uint8_t*)payload.c_str(), payload.size());
      } else if (m_State == eWSCInitial) {
        // recv connect request
        auto itr = payload.find(":");
        if(itr == std::string::npos) {
          // no port
          m_RemotePort = 0;
          m_RemoteAddr = payload;
        } else {
          // includes port
          m_RemotePort = std::stoi(payload.substr(itr+1));
          m_RemoteAddr = payload.substr(0, itr);
        }
        EnterState(eWSCTryConnect);
      } else {
        // wtf?
        LogPrint(eLogWarning, "websocks: got message in invalid state ", m_State);
      }
    }

    virtual void Close()
    {
      if(m_State == eWSCClose) {
        LogPrint(eLogDebug, "websocks: closing connection");
        if(m_Stream) m_Stream->Close();
        m_Parent->CloseConn(m_Conn);
        EnterState(eWSCEnd);
      } else {
        EnterState(eWSCClose);
      }
    }
  };

  WebSocksConn_ptr CreateWebSocksConn(const websocketpp::connection_hdl & conn, WebSocksImpl * parent)
  {
    auto ptr = std::make_shared<WebSocksConn>(conn, parent);
    auto c = parent->GetConn(conn);
    c->set_message_handler(std::bind(&WebSocksConn::GotMessage, ptr.get(), std::placeholders::_1, std::placeholders::_2));
    return ptr;
  }

}
}
#else

// no websocket support

namespace i2p
{
namespace client
{
	class WebSocksImpl
	{
	public:
		WebSocksImpl(const std::string & addr, int port)
		{
		}

		~WebSocksImpl()
		{
		}

		void Start()
		{
			LogPrint(eLogInfo, "WebSockets not enabled on compile time");
		}

		void Stop()
		{

		}

	};
}
}

#endif
namespace i2p
{
namespace client
{
	WebSocks::WebSocks(const std::string & addr, int port) : m_Impl(new WebSocksImpl(addr, port)) {}
	WebSocks::~WebSocks() { delete m_Impl; }

	void WebSocks::Start()
	{
		m_Impl->Start();
	}

	void WebSocks::Stop()
	{
		m_Impl->Stop();
	}
}
}
<|endoftext|>