text:
//  Copyright 2018 Stephan Menzel. Distributed under the Boost
//  Software License, Version 1.0. (See accompanying file
//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include "MRedisConnection.hpp"
#include "AsyncClient.hpp"
#include "MRedisCommands.hpp"

#include "tools/Log.hpp"
#include "tools/Assert.hpp"

#include <boost/lexical_cast.hpp>
#include <boost/variant.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/minmax.hpp>

namespace moose {
namespace mredis {

using boost::asio::steady_timer;
using namespace moose::tools;
namespace asio = boost::asio;
namespace ip = asio::ip;

MRedisConnection::MRedisConnection(AsyncClient &n_parent)
		: m_parent{ n_parent }
		, m_socket{ n_parent.io_context() }

		, m_send_streambuf{ }
		, m_send_buffer_busy{ false }
		, m_send_retry_timer{ n_parent.io_context() }
		, m_send_timeout{ n_parent.io_context() }

		, m_receive_streambuf{ }
		, m_receive_buffer_busy{ false }
		, m_receive_retry_timer{ n_parent.io_context() }
		, m_receive_timeout{ n_parent.io_context() }

		, m_connect_timeout{ n_parent.io_context() }

		, m_status{ Status::Disconnected } {

}

MRedisConnection::~MRedisConnection() noexcept {

}

void MRedisConnection::connect(const std::string &n_server, const boost::uint16_t n_port) {

	BOOST_LOG_FUNCTION();
	BOOST_LOG_SEV(logger(), debug) << "Connecting to TCP redis server on " << n_server << ":" << n_port;

	m_server_name = n_server;
	m_server_port = n_port;

	const std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();

	m_status = Status::Connecting;

	// Set a deadline for the connect operation.
	m_connect_timeout.expires_after(std::chrono::seconds(MREDIS_CONNECT_TIMEOUT));
	// Initially start the timeout handlers.
	m_connect_timeout.async_wait([this](const boost::system::error_code &n_error) { this->check_connect_deadline(n_error); });

	ip::tcp::resolver resolver(m_parent.io_context());
	ip::tcp::resolver::query query(n_server, boost::lexical_cast<std::string>(n_port), ip::tcp::resolver::query::numeric_service);
	ip::tcp::resolver::results_type resolved_endpoints = resolver.resolve(query);
	if (resolved_endpoints.empty()) {
		m_connect_timeout.cancel();
		BOOST_THROW_EXCEPTION(network_error() << error_message("Cannot resolve host name") << error_argument(n_server));
	}

	// I believe connect() should be sync so I catch the result in here.
	promised_response_ptr promise{ std::make_shared<promised_response>() };
	future_response res = promise->get_future();

	asio::async_connect(m_socket, resolved_endpoints,
		[this, promise, n_server](const boost::system::error_code &n_errc, const ip::tcp::endpoint &n_endpoint) {

			// cancel the connection timeout
			m_connect_timeout.cancel();

			if (n_errc) {
				BOOST_LOG_SEV(logger(), warning) << "Could not connect to redis server '" << n_server << "': " << n_errc.message();
				stop();

				promise->set_exception(redis_error() << error_message("Could not connect")
						<< error_argument(n_server) << error_code(n_errc));
				return;
			}

			// The async_connect() function automatically opens the socket at the start
			// of the asynchronous operation. If the socket is closed at this time then
			// the timeout handler must have run first.
			if (!m_socket.is_open()) {

				// Example code tried to connect to other endpoints like this:
				//	start_connect(++endpoint_iter);
				// I will not do this now and just throw an error
				stop();

				promise->set_exception(redis_error() << error_message("Connection timeout"));
				return;
			}

			// send a ping to say hello. Only one ping though, Vassily
			{
#ifdef _WIN32
				std::ostream os(&m_send_streambuf, std::ostream::binary);
#else
				std::ostream os(&m_send_streambuf);
#endif
				format_ping(os);
			}

			// put a wait handler into the
			m_outstanding.emplace_back([promise] (const RedisMessage &n_response) {
				promise->set_value(n_response);
			});

			// send the content of the streambuf to redis
			asio::async_write(m_socket, m_send_streambuf,
				[this](const boost::system::error_code n_errc, const std::size_t n_bytes_sent) {

					if (handle_error(n_errc, "sending ping to server")) {
						stop();
						return;
					}

					read_response();

// #no_timeouts disabled
		//			m_read_timeout.async_wait([this](const boost::system::error_code &n_error) { this->check_read_deadline(n_error); });
			});
	});

	// Wait for slightly longer than the actual timeout would be, so the deadline timer can kill the connection,
	// which would cause the get() to throw, rather than enforcing it here and having dangling stuff
	if (res.wait_for(boost::chrono::seconds(MREDIS_CONNECT_TIMEOUT + 2)) == boost::future_status::timeout) {
		BOOST_LOG_SEV(logger(), error) << "Connection promise was not set within connection timeout parameters. This is a bug in mredis";
		stop();

		BOOST_THROW_EXCEPTION(network_error() << error_message("Connection timed out on promise. This is a bug"));
	}

	// And wait for the callback to call the future. This will throw on connection or read timeout
	RedisMessage r = res.get();

	if (!is_string(r)) {
		BOOST_LOG_SEV(logger(), error) << "Server did not pong";
		stop();
		BOOST_THROW_EXCEPTION(network_error() << error_message("Server did not respond to ping"));
	}

	if (!boost::algorithm::equals(boost::get<std::string>(r), "PONG")) {
		BOOST_LOG_SEV(logger(), error) << "Server did not pong";
		stop();
		BOOST_THROW_EXCEPTION(network_error() << error_message("Server did not respond to ping with PONG"));
	}

	// Normally, connections are pushing. Meaning they send commands actively
	// as opposed to reading the socket for subscription channel messages
	m_status = Status::Pushing;
	const std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();

	BOOST_LOG_SEV(logger(), normal) << "Connected to redis in " << std::chrono::duration_cast<std::chrono::milliseconds>(end-start).count() << "ms";
}

void MRedisConnection::async_connect(const std::string &n_server, const boost::uint16_t n_port, std::shared_ptr<boost::promise<bool> > n_ret) {

	BOOST_LOG_FUNCTION();
	BOOST_LOG_SEV(logger(), debug) << "Async connecting to TCP redis server on " << n_server << ":" << n_port;

	const std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();

	// Set a deadline for the connect operation.
	m_connect_timeout.expires_after(std::chrono::seconds(MREDIS_CONNECT_TIMEOUT));

	m_status = Status::Connecting;

	ip::tcp::resolver resolver(m_parent.io_context());
	ip::tcp::resolver::query query(n_server, boost::lexical_cast<std::string>(n_port), ip::tcp::resolver::query::numeric_service);
	ip::tcp::resolver::results_type resolved_endpoints = resolver.resolve(query);
	if (resolved_endpoints.empty()) {
		n_ret->set_exception(redis_error() << error_message("Cannot resolve host name") << error_argument(n_server));
		return;
	}

	asio::async_connect(m_socket, resolved_endpoints,
		[this, n_ret, n_server, start](const boost::system::error_code &n_errc, const ip::tcp::endpoint &n_endpoint) {

			// cancel the connection timeout
			m_connect_timeout.cancel();

			if (n_errc) {
				BOOST_LOG_SEV(logger(), warning) << "Could not connect to redis server '" << n_server << "': " << n_errc.message();
				stop();

				n_ret->set_exception(redis_error() << error_message("Could not connect")
						<< error_argument(n_server) << error_code(n_errc));
				return;
			}

			// The async_connect() function automatically opens the socket at the start
			// of the asynchronous operation. If the socket is closed at this time then
			// the timeout handler must have run first.
			if (!m_socket.is_open()) {
				// Example code tried to connect to other endpoints like this:
				//	start_connect(++endpoint_iter);
				// I will not do this now and just throw an error

				n_ret->set_exception(redis_error() << error_message("Connection timeout"));
				return;
			}

			// send a ping to say hello. Only one ping though, Vassily
			{
				std::ostream os(&m_send_streambuf);
				format_ping(os);
			}

			// Put a callback into the expected responses queue to know what we do when ping returns
			m_outstanding.emplace_back([this, n_ret, start](const RedisMessage &n_response) {

				if (is_error(n_response)) {
					n_ret->set_exception(boost::get<redis_error>(n_response));
					return;
				}

				if (!is_string(n_response) || !boost::algorithm::equals(boost::get<std::string>(n_response), "PONG")) {
					n_ret->set_exception(redis_error() << error_message("Server did not pong"));
					return;
				}

				// Normally, connections are pushing. Meaning they send commands actively
				// as opposed to reading the socket for subscription channel messages
				m_status = Status::Pushing;
				const std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();

				BOOST_LOG_SEV(logger(), normal) << "Connected to redis in " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms";
				n_ret->set_value(true);
			});

			// send the content of the streambuf to redis
			asio::async_write(m_socket, m_send_streambuf,
				[this, n_ret](const boost::system::error_code n_errc, const std::size_t n_bytes_sent) {

					if (handle_error(n_errc, "sending ping to server")) {
						stop();

						return;
					}

					read_response();

// #no_timeouts disabled
//					m_read_timeout.async_wait([this](const boost::system::error_code &n_error) { this->check_read_deadline(n_error); });
			});
	});

	// Initially start the timeout handlers. (Expiry already set)
	m_connect_timeout.async_wait([this](const boost::system::error_code &n_error) { this->check_connect_deadline(n_error); });
}

void MRedisConnection::async_reconnect() {

	BOOST_LOG_FUNCTION();
	BOOST_LOG_SEV(logger(), debug) << "Reconnecting to TCP redis server on " << m_server_name;

	// #moep delete me or assert when stuff works
	if (m_status != Status::ShutdownReconnect) {
		BOOST_LOG_SEV(logger(), error) << "not in reconnect state, we are in: " << status_string();
		return;
	}

	const std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();

	// Re-initialize the socket as I expect shutdown_reconnect() to leave it closed
	m_socket = boost::asio::ip::tcp::socket{ m_parent.io_context() };

	m_status = Status::Connecting;

	ip::tcp::resolver resolver(m_parent.io_context());
	ip::tcp::resolver::query query(m_server_name, std::to_string(m_server_port), ip::tcp::resolver::query::numeric_service);
	ip::tcp::resolver::results_type resolved_endpoints = resolver.resolve(query);
	if (resolved_endpoints.empty()) {
		BOOST_LOG_SEV(logger(), warning) << "Could not resolve redis endpoints";
		boost::system::error_code ignored_error;
		m_socket.close(ignored_error);
		m_status = Status::ShutdownReconnect;    // we have set our status to connecting earlier
		asio::post(m_parent.io_context(), [this] { this->async_reconnect(); });
		return;
	}

	// Set a deadline for the connect operation.
	m_connect_timeout.expires_after(std::chrono::seconds(MREDIS_CONNECT_TIMEOUT));

	// So, what is the plan? I am assuming I was called by send_outstanding, which means there's stuff
	// to be sent but no connection to send it through.
	// I will continuously try to reconnect until the connection succeeds. When it does, I hand back
	// over to send_outstanding
	asio::async_connect(m_socket, resolved_endpoints,
		[this, start](const boost::system::error_code &n_errc, const ip::tcp::endpoint &n_endpoint) {

			m_connect_timeout.cancel();

			// If we encountered an error, we retry too but delete the socket first
			if (n_errc) {
				BOOST_LOG_SEV(logger(), warning) << "Could not reconnect to redis server on '" << n_endpoint << "': " << n_errc.message();
				boost::system::error_code ignored_error;
				m_socket.close(ignored_error);

				async_reconnect();
				return;
			}

			// The async_connect() function automatically opens the socket at the start
			// of the asynchronous operation. If the socket is closed at this time then
			// the timeout handler must have run first.
			if (!m_socket.is_open()) {
				// This is a condition I don't really expect but feat as remains of earlier impl
				BOOST_LOG_SEV(logger(), error) << "Could not reconnect to redis server: " << n_errc.message();
				boost::system::error_code ignored_error;
				m_socket.close(ignored_error);

				async_reconnect();
				return;
			}

			m_status = Status::Pushing;
			const std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();

			BOOST_LOG_SEV(logger(), normal) << "Reconnected to redis in " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms";

			// Soooo, I suppose I'm connected to the same endpoint as before. No ping or anything
			// I'll start send_outstanding, assuming that this is what we came here for
			send_outstanding_requests();

// #no_timeouts disabled
//			m_read_timeout.async_wait([this](const boost::system::error_code &n_error) { this->check_read_deadline(n_error); });

	});

	// Initially start the timeout handlers. (Expiry for connect already set)
	m_connect_timeout.async_wait([this](const boost::system::error_code &n_error) {

		if (this->m_status == Status::ShuttingDown || this->m_status == Status::Shutdown) {
			BOOST_LOG_SEV(logger(), debug) << "Shutting down, reconnect timeout ignored";
			return;
		}

		// Check whether the deadline has passed.
		if (m_connect_timeout.expiry() <= steady_timer::clock_type::now()) {
			// The deadline has passed. The socket is closed so that any outstanding
			// asynchronous operations are cancelled.
			BOOST_LOG_SEV(logger(), debug) << "Reconnect timeout, killing socket";

			async_reconnect();

			// There is no longer an active deadline. The expiry is set to the
			// maximum time point so that the actor takes no action until a new
			// deadline is set.
			m_connect_timeout.expires_at(steady_timer::time_point::max());
		} else {
			std::cout << "deadline not passed, timeout ignored" << std::endl;
		}
	});
}

void MRedisConnection::stop() noexcept {

	BOOST_LOG_FUNCTION();

	if (m_status >= Status::ShuttingDown) {
		// We may already be shutting down
		return;
	}

	BOOST_LOG_SEV(logger(), normal) << "MRedis TCP connection now shutting down";

	m_status = Status::ShuttingDown;

	// requests we haven't sent yet timeout immediately
	for (const mrequest &r : m_requests_not_sent) {

		asio::post(m_parent.io_context(), [cb{ r.m_callback }] {
			try {
				redis_error err;
				BOOST_LOG_SEV(logger(), normal) << "Stop aborting remaining unsent handler";
				err.set_server_message("unsent handler aborted");
				cb(err);
			} catch (const std::exception &sex) {
				BOOST_LOG_SEV(logger(), warning) << "Aborting client callback caused exception: " << sex.what();
			} catch (...) {
				BOOST_LOG_SEV(logger(), warning) << "Aborting client callback caused unknown exception";
			}
		});
	}

	m_requests_not_sent.clear();

	// Post remaining handlers into the owning parent's io_service to be executed with a
	// timeout exception
	// I'd much rather salvage them and use them in a new connection but this has to wait
	// because that would imply keeping the prepare functions as well, so we can send them again
	// after the reconnect
	for (const Callback &cb : m_outstanding) {

		asio::post(m_parent.io_context(), [cb] {
			try {
				redis_error err;
				BOOST_LOG_SEV(logger(), normal) << "Stop aborting remaining handler";
				err.set_server_message("handler aborted");
				cb(err);
			} catch (const std::exception &sex) {
				BOOST_LOG_SEV(logger(), warning) << "Aborting client callback caused exception: " << sex.what();
			} catch (...) {
				BOOST_LOG_SEV(logger(), warning) << "Aborting client callback caused unknown exception";
			}
		});
	}

	m_outstanding.clear();

	m_send_retry_timer.cancel();
	m_receive_retry_timer.cancel();
	m_connect_timeout.cancel();

	// Closing the socket will cause read_response to return its handler with an error
	boost::system::error_code ignored_error;
	m_socket.shutdown(asio::ip::tcp::socket::shutdown_both, ignored_error);
	m_socket.close(ignored_error);

	// All remaining handlers will be posted for execution with an error into the io_service

	m_status = Status::Shutdown;

}

void MRedisConnection::shutdown_reconnect() noexcept {

	BOOST_LOG_FUNCTION();

	if (m_status == Status::ShuttingDownReconnect || m_status == Status::ShuttingDown || m_status == Status::Shutdown) {
		// We may already be shutting down
		return;
	}

	// Leave it in this status
	m_status = Status::ShuttingDownReconnect;

	BOOST_LOG_SEV(logger(), normal) << "[Reconnect] TCP connection now shutting down to reconnect";

	// requests we haven't sent yet timeout immediately
	for (const mrequest &r : m_requests_not_sent) {
		try {
			redis_error err;
			BOOST_LOG_SEV(logger(), normal) << "[Reconnect] aborting remaining unsent handler";
			err.set_server_message("unsent handler aborted");
			r.m_callback(err);
		} catch (const std::exception &sex) {
			BOOST_LOG_SEV(logger(), warning) << "Aborting client callback caused exception: " << sex.what();
		} catch (...) {
			BOOST_LOG_SEV(logger(), warning) << "Aborting client callback caused unknown exception";
		}
	}

	m_requests_not_sent.clear();
	BOOST_LOG_SEV(logger(), debug) << "[Reconnect] Unsent handlers emptied";

	// Post remaining handlers into the owning parent's io_service to be executed with a
	// timeout exception
	// I'd much rather salvage them and use them in a new connection but this has to wait
	// because that would imply keeping the prepare functions as well, so we can send them again
	// after the reconnect
	for (const Callback &cb : m_outstanding) {
		try {
			redis_error err;
			BOOST_LOG_SEV(logger(), normal) << "[Reconnect] aborting remaining handler";
			err.set_server_message("handler aborted");
			cb(err);
		} catch (const std::exception &sex) {
			BOOST_LOG_SEV(logger(), warning) << "Aborting client callback caused exception: " << sex.what();
		} catch (...) {
			BOOST_LOG_SEV(logger(), error) << "Aborting client callback caused unknown exception";
		}
	}

	// after executing the callbacks with an error, delete them.
	m_outstanding.clear();
	BOOST_LOG_SEV(logger(), debug) << "[Reconnect] Outstanding sent handlers emptied with an exception each";

	m_send_retry_timer.cancel();
	m_receive_retry_timer.cancel();
	m_connect_timeout.cancel();
	m_parent.io_context().poll();
	BOOST_LOG_SEV(logger(), debug) << "[Reconnect] Timers cancelled";

	// Closing the socket will cause read_response to return its handler with an error
	boost::system::error_code ignored_error;
	m_socket.shutdown(asio::ip::tcp::socket::shutdown_both, ignored_error);
	m_socket.close(ignored_error);

	// which is why we poll it now. We are in io_service's thread
	m_parent.io_context().poll();
	BOOST_LOG_SEV(logger(), debug) << "[Reconnect] Polled Q after closing socket";

	// Whatever is left in the streambuf is BS now. I want to clear it. There is no described
	// way to do this though, so I resort to take all the input sequence
	m_send_streambuf.consume(m_send_streambuf.size());
	m_receive_streambuf.consume(m_receive_streambuf.size());

	m_status = Status::ShutdownReconnect;

	BOOST_LOG_SEV(logger(), normal) << "[Reconnect] TCP connection now in shutdown status (" << status_string() << "), ready to reconnect";

	// I'm posting one handler for send_outstanding just in case there are some.
	// The handler will do nothing if there's no reason to reconnect right away
	asio::post(m_parent.io_context(), [this] { this->send_outstanding_requests(); });
}

void MRedisConnection::send(std::function<void(std::ostream &n_os)> &&n_prepare, Callback &&n_callback) noexcept {

	{
		// MOEP! Introduce lockfree queue!

		mrequest req{ std::move(n_prepare) , std::move(n_callback) };
		boost::unique_lock<boost::mutex> slock(m_request_queue_lock);
		m_requests_not_sent.emplace_back(std::move(req));
	}

	m_parent.io_context().post([this]() { this->send_outstanding_requests(); });
}

promised_response_ptr MRedisConnection::send(std::function<void(std::ostream &n_os)> &&n_prepare) noexcept {

	// We keep ownership over this promise in the mrequest object
	promised_response_ptr promise(std::make_shared<promised_response>());

	{
		// Assemble a request object which will live until we have sent the request (via prepare function)
		// after which we discard the object and only keep the promised answer
		mrequest req{
			// Prepare function (will issue command on stream)
			std::move(n_prepare),

			// Callback will be called once the connection receives a response to the call
			[promise](const RedisMessage &n_response) {

				// A received (nested) error is re-thrown as a real exception
				// that will rise out of the future.
				if (is_error(n_response)) {
					promise->set_exception(boost::get<redis_error>(n_response));
				} else {
					promise->set_value(n_response);
				}
			}
		};

		// #moep Introduce lockfree queue!

		boost::unique_lock<boost::mutex> slock(m_request_queue_lock);
		m_requests_not_sent.emplace_back(std::move(req));
	}

	m_parent.io_context().post([this]() { this->send_outstanding_requests(); });

	return promise;
}

void MRedisConnection::send_outstanding_requests() noexcept {

// 	if (m_status >= Status::ShuttingDown) {
// 		return;
// 	}

	try {
		// if the streambuf is still in use we have to wait
		// we have to wait for it to become available. We store both handlers until later
		if (m_send_buffer_busy) {
			// If we already have a retry timer set, don't do it again
			//BOOST_LOG_SEV(logger(), debug) << "Setting send retry timer";
			m_send_retry_timer.expires_after(asio::chrono::milliseconds(5));
			m_send_retry_timer.async_wait(
				[this](const boost::system::error_code &n_error) {

					// this also happens when a new timer is set, e.g. because more requests come in
					if (n_error == asio::error::operation_aborted) {
						//BOOST_LOG_SEV(logger(), debug) << "Send retry timer aborted";
						return;
					}

					if (!n_error && this->m_status == Status::Pushing) {
						this->send_outstanding_requests();
					}
			});

			return;
		}

		if (m_status == Status::ShuttingDownReconnect) {
			// we are being shut down by some error condition and try a reconnect
			BOOST_LOG_SEV(logger(), debug) << "send_outstanding idle due to being shut down for reconnect.";
			return;

		} else if (m_status == Status::ShutdownReconnect) {
			// we have been shutdown by some error condition and are ready for a reconnect
			if (m_requests_not_sent.empty()) {
				BOOST_LOG_SEV(logger(), debug) << "We are shut down for reconnect, no work to be done. I'm outta here.";
			} else {
				BOOST_LOG_SEV(logger(), debug) << "We are shut down for reconnect and there's stuff to be sent. Going to reconnect.";
				async_reconnect();
			}

			return;
		}

		// we have waited for our buffer to become available. Right now I assume there is
		// no async operation in progress on it
		MOOSE_ASSERT(!m_send_buffer_busy)
		m_send_buffer_busy = true;

		{
#ifdef _WIN32
			std::ostream os(&m_send_streambuf, std::ostream::binary);
#else
			std::ostream os(&m_send_streambuf);
#endif

	//		BOOST_LOG_SEV(logger(), debug) << "Sending " << m_requests_not_sent.size() << " outstanding requests";

			// MOEP! Please, lockfree!
			boost::unique_lock<boost::mutex> slock(m_request_queue_lock);

			// See if we have unsent requests and stream them first in the order they came in
			for (mrequest &req : m_requests_not_sent) {
				req.m_prepare(os);
				m_outstanding.emplace_back(std::move(req.m_callback));
			}

			m_requests_not_sent.clear();
		}

		// send the content of the streambuf to redis
		asio::async_write(m_socket, m_send_streambuf,
			[this](const boost::system::error_code n_errc, const std::size_t n_bytes_transferred) {

				m_send_buffer_busy = false;
				if (handle_error(n_errc, "sending command(s) to server")) {
					stop();
					return;
				}

				if (m_status >= Status::ShuttingDown) {
					return;
				}

				read_response();
			});

	} catch (const boost::system::system_error &serr) {
		// Very likely we failed to set a retry timer. Doesn't matter. We still wake up as the next command comes in
		BOOST_LOG_SEV(logger(), warning) << "Error sending command: " << boost::diagnostic_information(serr);
	} catch (const tools::moose_error &merr) {
		// Not expected at all
		BOOST_LOG_SEV(logger(), warning) << "Error sending command: " << boost::diagnostic_information(merr);
	} catch (const std::exception &sex) {
		// The caller didn't provide callbacks that were nothrow
		BOOST_LOG_SEV(logger(), error) << "Unexpected exception in send_command(): " << boost::diagnostic_information(sex);
	}
}

void MRedisConnection::read_response() noexcept {

	if (m_status >= Status::ShuttingDown) {
		return;
	}

	try {
		// if the streambuf is in use we cannot push data into it
		// we have to wait for it to become available. We store both handlers until later
		if (m_receive_buffer_busy) {

			// I will only post a wait handler if the queue of outstanding
			// responses is not empty to avoid having multiple in flight
			if (m_outstanding.empty()) {
				BOOST_LOG_SEV(logger(), debug) << "Don't set read retry timer, no reason to read";
				return;
			}

			//BOOST_LOG_SEV(logger(), debug) << "Setting read retry timer";
			m_receive_retry_timer.expires_after(asio::chrono::milliseconds(5));
			m_receive_retry_timer.async_wait(
				[this](const boost::system::error_code &n_error) {

					// this also happens when a new timer is set, e.g. because more requests come in
					if (n_error == asio::error::operation_aborted) {
						//BOOST_LOG_SEV(logger(), debug) << "Receive retry timer aborted";
						return;
					}

					if (!n_error && this->m_status == Status::Pushing) {
						this->read_response();
					}
			});

			return;
		}

		// we have waited for our buffer to become available. Right now I assume there is
		// no async operation in progress on it
		MOOSE_ASSERT(!m_receive_buffer_busy)
		m_receive_buffer_busy = true;

		// perhaps we already have bytes to read in our streambuf. If so, I parse those first
		while (!m_outstanding.empty() && m_receive_streambuf.size()) {

			RedisMessage r;

			// As long as we can parse messages from our stream, continue to do so.
			bool success = parse_from_streambuf(m_receive_streambuf, r);
			if (success) {
				// call the callback which was stored along with the request
				m_outstanding.front()(r);

				// remove the callback
				m_outstanding.pop_front();
			} else {
				break;
			}
		}

		// If there's nothing left to read, exit this strand. We should re-enter
		// as new incoming request trigger this.
		if (m_outstanding.empty()) {
//			BOOST_LOG_SEV(logger(), debug) << "Expecting no more responses. Nothing to read here, move along";
			m_receive_timeout.cancel();
			m_receive_buffer_busy = false;
			return;
		}

		// Otherwise read more from the socket
//		BOOST_LOG_SEV(logger(), debug) << "Set new timeout and read more responses";
		m_receive_timeout.expires_after(asio::chrono::seconds(MREDIS_READ_TIMEOUT));
		m_receive_timeout.async_wait([this](const boost::system::error_code &n_error) { this->check_read_deadline(n_error); });

		// read one response and evaluate
		asio::async_read(m_socket, m_receive_streambuf, asio::transfer_at_least(1),
			[this](const boost::system::error_code n_errc, const std::size_t n_bytes_transferred) {

				if (handle_error(n_errc, "reading response")) {
					m_receive_buffer_busy = false;

					if (m_status == Status::ShuttingDownReconnect) {
						// Our status has been to ShutdownReconnect because the timeout kicked in.
						// We exit here and rely on the fact that a handler is already posted.
						BOOST_LOG_SEV(logger(), debug) << "read timeout cancelled read, all good.";
					} else {
						BOOST_LOG_SEV(logger(), warning) << "stop connection";
						stop();
					}

					return;
				}

				m_receive_buffer_busy = false;

				if (m_status >= Status::ShuttingDown) {
					BOOST_LOG_SEV(logger(), normal) << "Shutting down, not reading any more responses. There are " << m_outstanding.size() << " callbacks left";
					return;
				}

				// this is going to parse
				read_response();
			});
	} catch (const boost::system::system_error &serr) {
		// Very likely we failed to set a retry timer. Doesn't matter. We still wake up as the next command comes in
		BOOST_LOG_SEV(logger(), warning) << "Error reading response: " << boost::diagnostic_information(serr);
	} catch (const tools::moose_error &merr) {
		// Not expected at all
		BOOST_LOG_SEV(logger(), warning) << "Error reading response: " << boost::diagnostic_information(merr);
	} catch (const std::exception &sex) {
		// The caller didn't provide callbacks that were nothrow
		BOOST_LOG_SEV(logger(), error) << "Unexpected exception in read_response(): " << boost::diagnostic_information(sex);
	}
}

bool MRedisConnection::handle_error(const boost::system::error_code n_errc, const char *n_message) const {

	if (!n_errc) {
		return false;
	}

	// Most likely an operation has been canceled due to shutdown
	if (m_status >= Status::ShuttingDown) {
		BOOST_LOG_SEV(logger(), normal) << "Async operation aborted, shutting down: " << n_errc.message();
		return false;
	}

	if (n_errc == boost::asio::error::operation_aborted) {
		BOOST_LOG_SEV(logger(), normal) << "Async operation aborted - " << n_message << ": " << n_errc.message();
		return true;
	}

	if (n_errc == boost::asio::error::broken_pipe) {
		BOOST_LOG_SEV(logger(), warning) << "Server closed connection - " << n_message << ": " << n_errc.message();
		return true;
	}

	BOOST_LOG_SEV(logger(), warning) << "Error " << n_message << ": " << n_errc.message();
	return true;
}

void MRedisConnection::check_connect_deadline(const boost::system::error_code &n_error) {

	if (n_error == boost::asio::error::operation_aborted) {
		BOOST_LOG_SEV(logger(), debug) << "Connection timeout cancelled";
		return;
	}

	if (m_status == Status::ShuttingDown || m_status == Status::Shutdown) {
		BOOST_LOG_SEV(logger(), debug) << "Shutting down, connection timeout ignored";
		return;
	}

	// Check whether the deadline has passed. We compare the deadline against
	// the current time since a new asynchronous operation may have moved the
	// deadline before this actor had a chance to run.
	if (m_connect_timeout.expiry() <= steady_timer::clock_type::now()) {
		// The deadline has passed. The socket is closed so that any outstanding
		// asynchronous operations are cancelled.
		BOOST_LOG_SEV(logger(), warning) << "Connect timeout, killing connection";
		stop();
	}
}

void MRedisConnection::check_read_deadline(const boost::system::error_code &n_error) {

	if (n_error == asio::error::operation_aborted) {
//		BOOST_LOG_SEV(logger(), debug) << "Timeout aborted";
		return;
	}

	if (m_status == Status::ShuttingDown || m_status == Status::Shutdown) {
		BOOST_LOG_SEV(logger(), debug) << "Shutting down, read timeout ignored. We are in status: " << status_string();
		return;
	}

	// Check whether the deadline has passed. We compare the deadline against
	// the current time since a new asynchronous operation may have moved the
	// deadline before this actor had a chance to run.
	if (m_receive_timeout.expiry() <= steady_timer::clock_type::now()) {
		// The deadline has passed. The socket is closed so that any outstanding
		// asynchronous operations are cancelled.
		BOOST_LOG_SEV(logger(), normal) << "Read timeout, killing connection for reconnect...";

		shutdown_reconnect();

		// There is no longer an active deadline. The expiry is set to the
		// maximum time point so that the actor takes no action until a new
		// deadline is set.
//		m_read_timeout.expires_at(steady_timer::time_point::max());
	} else {
//		BOOST_LOG_SEV(logger(), debug) << "Read deadline not passed, timeout ignored";
	}

	// Put the actor back to sleep.
//	m_read_timeout.async_wait([this](const boost::system::error_code &e) { this->check_read_deadline(e); });
}

const char *MRedisConnection::status_string() const noexcept {

	switch (m_status) {
		default:                            return "invalid/error";
		case Status::Disconnected:          return "disconnected";
		case Status::Connecting:            return "connecting";
		case Status::Connected:             return "connected";
		case Status::Pushing:               return "pushing";
		case Status::Pubsub:                return "pub/sub";
		case Status::ShuttingDownReconnect: return "shutting down for reconnect";
		case Status::ShutdownReconnect:     return "shutdown/reconnect";
		case Status::ShuttingDown:          return "shutting down";
		case Status::Shutdown:              return "down";
	}
}

}
}

max_stars_repo_name: MrMoose/mredis

max_issues_repo_name: MrMoose/mredis

max_forks_repo_name: MrMoose/mredis


text:
#ifdef STAN_LANG_MPI

#include <gtest/gtest.h>
#include <stan/math/torsten/mpi.hpp>
#include <boost/mpi.hpp>
#include <fstream>

using Eigen::MatrixXd;
using Eigen::Matrix;
using std::vector;
using stan::math::mpi::Communicator;
using stan::math::mpi::Session;

TORSTEN_MPI_SESSION_INIT;

TEST(mpi_comm_test, mpi_inter_intra_comms) {
  const Communicator world_comm(MPI_COMM_STAN);
  const Communicator& inter_comm(Session::inter_chain_comm(3));
  const Communicator& intra_comm(Session::intra_chain_comm(3));
  if (world_comm.size() == 3) {
    switch (world_comm.rank()) {
    case 0:
      EXPECT_EQ(inter_comm.rank(), 0);
      EXPECT_EQ(intra_comm.rank(), 0);
      break;
    case 1:
      EXPECT_EQ(inter_comm.rank(), 1);
      EXPECT_EQ(intra_comm.rank(), 0);
      break;
    case 2:
      EXPECT_EQ(inter_comm.rank(), 2);
      EXPECT_EQ(intra_comm.rank(), 0);
      break;
    }
  } else if (world_comm.size() == 4) {
    switch (world_comm.rank()) {
    case 0:
      EXPECT_EQ(inter_comm.rank(), 0);
      EXPECT_EQ(intra_comm.rank(), 0);
      break;
    case 1:
      EXPECT_EQ(inter_comm.rank(), -1);
      EXPECT_EQ(intra_comm.rank(), 1);
      break;
    case 2:
      EXPECT_EQ(inter_comm.rank(), 1);
      EXPECT_EQ(intra_comm.rank(), 0);
      break;
    case 3:
      EXPECT_EQ(inter_comm.rank(), 2);
      EXPECT_EQ(intra_comm.rank(), 0);
      break;
    }
  } else if (world_comm.size() == 5) {
    switch (world_comm.rank()) {
    case 0:
      EXPECT_EQ(inter_comm.rank(), 0);
      EXPECT_EQ(intra_comm.rank(), 0);
      break;
    case 1:
      EXPECT_EQ(inter_comm.rank(), -1);
      EXPECT_EQ(intra_comm.rank(), 1);
      break;
    case 2:
      EXPECT_EQ(inter_comm.rank(), 1);
      EXPECT_EQ(intra_comm.rank(), 0);
      break;
    case 3:
      EXPECT_EQ(inter_comm.rank(), -1);
      EXPECT_EQ(intra_comm.rank(), 1);
      break;
    case 4:
      EXPECT_EQ(inter_comm.rank(), 2);
      EXPECT_EQ(intra_comm.rank(), 0);
      break;
    }
  } else if (world_comm.size() == 6) {
    switch (world_comm.rank()) {
    case 0:
      EXPECT_EQ(inter_comm.rank(), 0);
      EXPECT_EQ(intra_comm.rank(), 0);
      break;
    case 1:
      EXPECT_EQ(inter_comm.rank(), -1);
      EXPECT_EQ(intra_comm.rank(), 1);
      break;
    case 2:
      EXPECT_EQ(inter_comm.rank(), 1);
      EXPECT_EQ(intra_comm.rank(), 0);
      break;
    case 3:
      EXPECT_EQ(inter_comm.rank(), -1);
      EXPECT_EQ(intra_comm.rank(), 1);
      break;
    case 4:
      EXPECT_EQ(inter_comm.rank(), 2);
      EXPECT_EQ(intra_comm.rank(), 0);
      break;
    case 5:
      EXPECT_EQ(inter_comm.rank(), -1);
      EXPECT_EQ(intra_comm.rank(), 1);
      break;
    }
  } else if (world_comm.size() == 7) {
    switch (world_comm.rank()) {
    case 0:
      EXPECT_EQ(inter_comm.rank(), 0);
      EXPECT_EQ(intra_comm.rank(), 0);
      break;
    case 1:
      EXPECT_EQ(inter_comm.rank(), -1);
      EXPECT_EQ(intra_comm.rank(), 1);
      break;
    case 2:
      EXPECT_EQ(inter_comm.rank(), -1);
      EXPECT_EQ(intra_comm.rank(), 2);
      break;
    case 3:
      EXPECT_EQ(inter_comm.rank(), 1);
      EXPECT_EQ(intra_comm.rank(), 0);
      break;
    case 4:
      EXPECT_EQ(inter_comm.rank(), -1);
      EXPECT_EQ(intra_comm.rank(), 1);
      break;
    case 5:
      EXPECT_EQ(inter_comm.rank(), 2);
      EXPECT_EQ(intra_comm.rank(), 0);
      break;
    case 6:
      EXPECT_EQ(inter_comm.rank(), -1);
      EXPECT_EQ(intra_comm.rank(), 1);
      break;
    }
  }
}

TEST(mpi_comm_test, is_in_inter_comm) {
  const Communicator world_comm(MPI_COMM_STAN);
  const int n_chains = 3;
  if (world_comm.size() == 3) {
    switch (world_comm.rank()) {
    case 0:
      EXPECT_TRUE(Session::is_in_inter_chain_comm(n_chains));
      break;
    case 1:
      EXPECT_TRUE(Session::is_in_inter_chain_comm(n_chains));
      break;
    case 2:
      EXPECT_TRUE(Session::is_in_inter_chain_comm(n_chains));
      break;
    }
  } else if (world_comm.size() == 4) {
    switch (world_comm.rank()) {
    case 0:
      EXPECT_TRUE(Session::is_in_inter_chain_comm(n_chains));
      break;
    case 1:
      EXPECT_FALSE(Session::is_in_inter_chain_comm(n_chains));
      break;
    case 2:
      EXPECT_TRUE(Session::is_in_inter_chain_comm(n_chains));
      break;
    case 3:
      EXPECT_TRUE(Session::is_in_inter_chain_comm(n_chains));
      break;
    }
  } else if (world_comm.size() == 5) {
    switch (world_comm.rank()) {
    case 0:
      EXPECT_TRUE(Session::is_in_inter_chain_comm(n_chains));
      break;
    case 1:
      EXPECT_FALSE(Session::is_in_inter_chain_comm(n_chains));
      break;
    case 2:
      EXPECT_TRUE(Session::is_in_inter_chain_comm(n_chains));
      break;
    case 3:
      EXPECT_FALSE(Session::is_in_inter_chain_comm(n_chains));
      break;
    case 4:
      EXPECT_TRUE(Session::is_in_inter_chain_comm(n_chains));
      break;
    }
  } else if (world_comm.size() == 6) {
    switch (world_comm.rank()) {
    case 0:
      EXPECT_TRUE(Session::is_in_inter_chain_comm(n_chains));
      break;
    case 1:
      EXPECT_FALSE(Session::is_in_inter_chain_comm(n_chains));
      break;
    case 2:
      EXPECT_TRUE(Session::is_in_inter_chain_comm(n_chains));
      break;
    case 3:
      EXPECT_FALSE(Session::is_in_inter_chain_comm(n_chains));
      break;
    case 4:
      EXPECT_TRUE(Session::is_in_inter_chain_comm(n_chains));
      break;
    case 5:
      EXPECT_FALSE(Session::is_in_inter_chain_comm(n_chains));
      break;
    }
  } else if (world_comm.size() == 7) {
    switch (world_comm.rank()) {
    case 0:
      EXPECT_TRUE(Session::is_in_inter_chain_comm(n_chains));
      break;
    case 1:
      EXPECT_FALSE(Session::is_in_inter_chain_comm(n_chains));
      break;
    case 2:
      EXPECT_FALSE(Session::is_in_inter_chain_comm(n_chains));
      break;
    case 3:
      EXPECT_TRUE(Session::is_in_inter_chain_comm(n_chains));
      break;
    case 4:
      EXPECT_FALSE(Session::is_in_inter_chain_comm(n_chains));
      break;
    case 5:
      EXPECT_TRUE(Session::is_in_inter_chain_comm(n_chains));
      break;
    case 6:
      EXPECT_FALSE(Session::is_in_inter_chain_comm(n_chains));
      break;
    }
  }
}

#endif

ext: cpp


text:
/* Taken from:
   http://mail.python.org/pipermail/cplusplus-sig/2004-September/007756.html
*/

#include <boost/python/object.hpp>

namespace python_wrap{

template<typename T>
inline void set (boost::optional<T>& o, T x) {
  o = x;
}

template<typename T>
inline boost::python::object get(boost::optional<T>& o) {
  return o ? boost::python::object(o.get()) : boost::python::object() ;
}

template<typename T>
static void exposeOptional (const char* name) {
  class_<boost::optional<T> >(name)
    .def ("set", &set<T>)
    .def ("get", &get<T>)
    .def (!(self))
    ;
}

}

ext: hpp

max_stars_repo_name: academicRobot/mmstructlib

max_issues_repo_name: academicRobot/mmstructlib

max_forks_repo_name: academicRobot/mmstructlib


text:
/*
 * Copyright 2009-2021 The VOTCA Development Team (http://www.votca.org)
 *
 * 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.
 *
 */

#define BOOST_TEST_MAIN

#define BOOST_TEST_MODULE bondedstatistics_test

// Standard includes
#include <iostream>
#include <map>
#include <string>

// Third party includes
#include <boost/test/unit_test.hpp>

// Local VOTCA includes
#include "../csg_boltzmann/bondedstatistics.h"

using namespace std;
using namespace votca::csg;
using namespace votca::tools;

BOOST_AUTO_TEST_SUITE(bondedstatistics_test)

BOOST_AUTO_TEST_CASE(test_bondedstatistics_constructor) {
  BondedStatistics bonded_statistics;
}

BOOST_AUTO_TEST_CASE(test_bondedstatistics_begin) {
  Topology top;
  // Create two bonded interactions
  string interaction_group = "covalent_bond1";
  string interaction_group_compare = ":covalent_bond1";
  auto bond1 = new IBond(0, 1);
  bond1->setGroup(interaction_group);

  string interaction_group2 = "covalent_bond2";
  string interaction_group_compare2 = ":covalent_bond2";
  auto bond2 = new IBond(1, 2);
  bond2->setGroup(interaction_group2);

  top.AddBondedInteraction(bond1);
  top.AddBondedInteraction(bond2);

  BondedStatistics bonded_statistics;
  bonded_statistics.BeginCG(&top, nullptr);

  DataCollection<double> &data_collection = bonded_statistics.BondedValues();
  vector<DataCollection<double>::array *> &vector_of_arrays =
      data_collection.Data();
  BOOST_CHECK_EQUAL(vector_of_arrays.size(), 2);
  BOOST_CHECK_EQUAL(vector_of_arrays.at(0)->getName(),
                    interaction_group_compare);
  BOOST_CHECK_EQUAL(vector_of_arrays.at(1)->getName(),
                    interaction_group_compare2);
  // The arrays do not store any numbers at this point
  BOOST_CHECK_EQUAL(vector_of_arrays.at(0)->size(), 0);
  BOOST_CHECK_EQUAL(vector_of_arrays.at(1)->size(), 0);
  top.Cleanup();
}

BOOST_AUTO_TEST_CASE(test_evalconfiguration_begin) {
  Topology top;

  // Setup topology class
  {
    // Set the system size

    Eigen::Matrix3d box = 10 * Eigen::Matrix3d::Identity();
    top.setBox(box);

    string bead_type_name = "type1";
    top.RegisterBeadType(bead_type_name);

    votca::Index residue_number = 1;
    double mass = 1.1;
    double charge = 0.3;

    // Create 3 beads
    string bead_name = "bead_test";
    Eigen::Vector3d pos_bead1(5.0, 3.0, 5.0);
    auto bead_ptr = top.CreateBead(Bead::spherical, bead_name, bead_type_name,
                                   residue_number, mass, charge);
    bead_ptr->setId(0);
    bead_ptr->setPos(pos_bead1);

    string bead_name2 = "bead_test2";
    Eigen::Vector3d pos_bead2(5.0, 4.0, 5.0);
    auto bead_ptr2 = top.CreateBead(Bead::spherical, bead_name2, bead_type_name,
                                    residue_number, mass, charge);
    bead_ptr2->setId(1);
    bead_ptr2->setPos(pos_bead2);

    string bead_name3 = "bead_test3";
    Eigen::Vector3d pos_bead3(5.0, 6.0, 5.0);
    auto bead_ptr3 = top.CreateBead(Bead::spherical, bead_name3, bead_type_name,
                                    residue_number, mass, charge);
    bead_ptr3->setId(2);
    bead_ptr3->setPos(pos_bead3);

    // Create two bonded interactions
    string interaction_group = "covalent_bond1";
    auto bond1 = new IBond(0, 1);
    bond1->setGroup(interaction_group);
    string interaction_group2 = "covalent_bond2";
    auto bond2 = new IBond(1, 2);
    bond2->setGroup(interaction_group2);

    top.AddBondedInteraction(bond1);
    top.AddBondedInteraction(bond2);
  }

  BondedStatistics bonded_statistics;
  bonded_statistics.BeginCG(&top, nullptr);

  // Calling EvalConfiguration on IBond structures will store the distances
  // between the beads in the BondedStatitics class
  bonded_statistics.EvalConfiguration(&top, nullptr);

  DataCollection<double> &data_collection = bonded_statistics.BondedValues();
  vector<DataCollection<double>::array *> &vector_of_arrays =
      data_collection.Data();

  // Distance between bead 0 and bead 1
  BOOST_CHECK_EQUAL(vector_of_arrays.at(0)->at(0), 1.0);
  // Distance between bead 1 and bead 2
  BOOST_CHECK_EQUAL(vector_of_arrays.at(1)->at(0), 2.0);

  top.Cleanup();
}
BOOST_AUTO_TEST_SUITE_END()

ext: cc

max_stars_repo_name: BuildJet/csg

max_issues_repo_name: BuildJet/csg

max_forks_repo_name: BuildJet/csg


text:
//
//   Copyright 2014 QuarksLab
//
//   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.
//

#ifndef BINMAP_GRAPH_HPP
#define BINMAP_GRAPH_HPP

#include "binmap/hash.hpp"

#include <string>
#include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp>

#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>

#include <boost/graph/adj_list_serialize.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/map.hpp>
#include "boost_ex/filesystem/serialization.hpp"
#include "boost_ex/serialization/unordered_map.hpp"
#include "boost_ex/serialization/unordered_set.hpp"

/* define a new graph property to hold the hash of a node */
namespace boost {
enum vertex_hash_t {
  vertex_hash
};
BOOST_INSTALL_PROPERTY(vertex, hash);
}

class Graph {

  typedef boost::property<boost::vertex_name_t, boost::filesystem::path,
                          boost::property<boost::vertex_hash_t, Hash> >
  vertex_property;
  typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS,
                                vertex_property> graph_type;

  graph_type graph_;
  boost::unordered_map<boost::filesystem::path, graph_type::vertex_descriptor>
  mapping_;
  mutable std::vector<int> *distance_matrix_;

  boost::unordered_set<boost::filesystem::path> visited_path_;

public:
  Graph();
  ~Graph();

  typedef boost::unordered_set<boost::filesystem::path> successors_type;
  typedef boost::property_map<graph_type, boost::vertex_hash_t>::const_type
  const_hashes_t;
  typedef boost::graph_traits<graph_type>::vertex_iterator vertex_iterator;
  typedef vertex_iterator iterator;
  typedef graph_type::vertex_descriptor vertex_descriptor;
  typedef boost::graph_traits<graph_type>::out_edge_iterator edge_iterator;

  bool has_node(boost::filesystem::path const &path) const;

  bool has_path(boost::filesystem::path const &from,
                boost::filesystem::path const &to) const;

/**
*	if `input_file` is not found in the binary folder but has been parsed before
*		=> return path parsed before
*	if `input_file` is found but hasn't been found before
*		=> return `input_file` (and change the node's name)
**/
  boost::filesystem::path add_node(boost::filesystem::path const &input_file,
                Hash const &input_hash);

  graph_type const &graph() const;

  /** get the filename associated to a node descriptor */
  boost::filesystem::path const &key(graph_type::vertex_descriptor vd) const;

  /** get the hash associated to a node descriptor */
  Hash const &hash(graph_type::vertex_descriptor vd) const;

  /** get the hash associated to a filename */
  Hash const &hash(boost::filesystem::path const &key) const;

  /** collects all successors of a filename in succs */
  void successors(successors_type &succs,
                  boost::filesystem::path const &key) const;
  void predecessors(successors_type &preds,
                    boost::filesystem::path const &key) const;

  /** get internal filename to hash dict */
  const_hashes_t hashes() const;

  /** iterates over vertices */
  vertex_iterator begin() const;

  vertex_iterator end() const;

  /** iterates over successors of a node */
  edge_iterator edge_begin(boost::filesystem::path const &input_file) const;

  edge_iterator edge_end(boost::filesystem::path const &input_file) const;

  edge_iterator edge_begin(graph_type::vertex_descriptor input) const;

  edge_iterator edge_end(graph_type::vertex_descriptor input) const;

  /** add edge between from and to, pointing toward to*/
  void add_edge(boost::filesystem::path const &from,
                boost::filesystem::path const &to);

  /** dump the graph as a .dot file */
  void dot(boost::filesystem::path const &path) const;

  size_t size() const;

  template < class Archive >
  void serialize(Archive & ar, unsigned int) {
      ar& graph_ & mapping_;
  }

protected:
  void compute_distance_matrix() const;
};

/** Class resulting from the projection of a graph to a new dimension */

template <class T> class GraphProjection {

  typedef boost::property<boost::vertex_name_t, T> vertex_property;
  typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS,
                                vertex_property> graph_type;

  graph_type graph_;
  boost::unordered_map<T, typename graph_type::vertex_descriptor> mapping_;
  boost::unordered_set<boost::filesystem::path> visited_path_;

public:
  typedef typename boost::graph_traits<graph_type>::vertex_iterator
  vertex_iterator;
  bool has_node(T const &key) const {
    return mapping_.find(key) != mapping_.end();
  }

  boost::filesystem::path add_node(T const &key) {
    assert(not has_node(key));
    typename graph_type::vertex_descriptor v = boost::add_vertex(graph_);
    mapping_[key] = v;

    boost::put(boost::vertex_name_t(), graph_, v, key);
    return key;
  }

  vertex_iterator begin() const { return boost::vertices(graph_).first; }
  vertex_iterator end() const { return boost::vertices(graph_).second; }

  void add_edge(T const &from, T const &to) {
    assert(has_node(from));
    assert(has_node(to));
    boost::add_edge(mapping_[from], mapping_[to], graph_);
  }
  void dot(boost::filesystem::path const &path) const {
    std::ofstream dotfile(path.c_str());
    boost::write_graphviz(
        dotfile, graph_,
        boost::make_label_writer(boost::get(boost::vertex_name_t(), graph_)));
  }
};

#endif


text:
#include <CLI/CLI.hpp>

#include <Eigen/Dense>
#include <opencv2/highgui/highgui.hpp>
#include <sophus/se3.hpp>

#include <basalt/calibration/calibration.hpp>
#include <basalt/serialization/headers_serialization.h>

#include <basalt/utils/filesystem.h>

#include <nlohmann/json.hpp>

#include <sys/stat.h>

using json = nlohmann::json;

json se3ToJson(Sophus::SE3<double> se3) {
  auto tm = se3.matrix();
  json rows;
  for (int r = 0; r < tm.rows(); r++) {
    json row;
    for (int c = 0; c < tm.cols(); c++) {
      row.push_back(tm(r, c));
    }
    rows.push_back(row);
  }
  return rows;
}

int main(int argc, char **argv) {
  std::string calib_path;
  std::string output_path;

  CLI::App app{"Basalt calibration to standard calibration converter"};

  app.add_option("--calib-path", calib_path, "Path to Basalt calibration file")->required();
  app.add_option("--output-path", output_path, "Path to output file")->required();

  try {
    app.parse(argc, argv);
  } catch (const CLI::ParseError &e) {
    return app.exit(e);
  }

  if (!basalt::fs::exists(calib_path))
    std::cerr << "No file found " << calib_path << std::endl;

  basalt::Calibration<double> calib;
  std::ifstream is(calib_path, std::ios::binary);
  std::cout << std::setprecision(18);

  if (is.is_open()) {
    cereal::JSONInputArchive archive(is);
    archive(calib);
    for (size_t i = 0; i < calib.T_i_c.size(); i++) {
      std::cout << "T_i_c " << calib.T_i_c[i].matrix() << std::endl;
    }
    std::cout << "Loaded camera with " << calib.intrinsics.size() << " cameras"
              << std::endl;
  } else {
    std::cerr << "could not load camera calibration " << calib_path
              << std::endl;
    std::abort();
  }

  json calibJson;

  bool fisheye = false;
  for (size_t i = 0; i < calib.T_i_c.size(); i++) {
    auto params = calib.intrinsics[i].getParam();
    auto modelName = calib.intrinsics[i].getName();

    json cameraJson;

    if (modelName == "kb4") {
      fisheye = true;
      // fx, fy, cx, cy, k1, k2, k3, k4
      if (i == 0) {
        std::cout
          << "focalLengthX " << params(0) << ";" << std::endl
          << "focalLengthY " << params(1) << ";" << std::endl
          << "principalPointX " << params(2) << ";" << std::endl
          << "principalPointY " << params(3) << ";" << std::endl;
        std::cout
          << "distortionCoeffs ";
        for (int j = 4; j < 8; j++) {
          std::cout << params(j);
          if (j == 7) std::cout << ";" << std::endl;
          else std::cout << ",";
        }
      } else {
        std::cout
          << "secondFocalLengthX " << params(0) << ";" << std::endl
          << "secondFocalLengthY " << params(1) << ";" << std::endl
          << "secondPrincipalPointX " << params(2) << ";" << std::endl
          << "secondPrincipalPointY " << params(3) << ";" << std::endl;
        std::cout
          << "secondDistortionCoeffs ";
        for (int j = 4; j < 8; j++) {
          std::cout << params(j);
          if (j == 7) std::cout << ";" << std::endl;
          else std::cout << ",";
        }
      }
      cameraJson["model"] = "kannala-brandt4";
      cameraJson["focalLengthX"] = params(0);
      cameraJson["focalLengthY"] = params(1);
      cameraJson["principalPointX"] = params(2);
      cameraJson["principalPointY"] = params(3);
      cameraJson["distortionCoefficients"] = {params(4), params(5), params(6), params(7)};
    } else if (modelName == "ds") {
      cameraJson["model"] = "doublesphere";
      cameraJson["focalLengthX"] = params(0);
      cameraJson["focalLengthY"] = params(1);
      cameraJson["principalPointX"] = params(2);
      cameraJson["principalPointY"] = params(3);
      cameraJson["xi"] = params(4);
      cameraJson["alpha"] = params(5);
    }

    if (calib.vignette.size() > 0)
      for (size_t p = 0; p < calib.vignette[i].getKnots().size(); p++)
        cameraJson["vignette"].push_back(calib.vignette[i].getKnots()[p](0));

    if (i == 0)
      std::cout << "imuToCameraMatrix ";
    else
      std::cout << "secondImuToCameraMatrix ";
    auto tm = calib.T_i_c[i].inverse().matrix();
    for (int col = 0; col < tm.cols(); col++) {
      for (int row = 0; row < tm.rows(); row++) {
        std::cout << tm(row, col);
        if (row == 3 && col == 3) std::cout << ";" << std::endl;
        else std::cout << ",";
      }
    }
    cameraJson["imuToCamera"] = se3ToJson(calib.T_i_c[i].inverse());
    calibJson["cameras"].push_back(cameraJson);
  }
  if (fisheye)
    std::cout << "fisheyeCamera true;" << std::endl;

  json gyroJson;
  gyroJson["updateRate"] = calib.imu_update_rate;
  gyroJson["noiseStd"] = {calib.gyro_noise_std(0), calib.gyro_noise_std(1), calib.gyro_noise_std(2)};
  gyroJson["biasStd"] = {calib.gyro_bias_std(0), calib.gyro_bias_std(1), calib.gyro_bias_std(2)};
  for (int i = 0; i < 12; i++)
    gyroJson["calibrationBias"].push_back(calib.calib_gyro_bias.getParam()[i]);
  calibJson["gyroscope"] = gyroJson;

  json accJson;
  // accJson["updateRate"] = calib.imu_update_rate;
  accJson["noiseStd"] = {calib.accel_noise_std(0), calib.accel_noise_std(1), calib.accel_noise_std(2)};
  accJson["biasStd"] = {calib.accel_bias_std(0), calib.accel_bias_std(1), calib.accel_bias_std(2)};
  for (int i = 0; i < 9; i++)
    accJson["calibrationBias"].push_back(calib.calib_accel_bias.getParam()[i]);
  calibJson["accelerometer"] = accJson;

  std::ofstream os(output_path);
  os << calibJson.dump(4) << std::endl;

  return 0;
}


text:
#pragma once

#include <boost/aura/base/cuda/safecall.hpp>

#include <cuda.h>

namespace boost
{
namespace aura
{
namespace base_detail
{
namespace cuda
{

/// Initialize base.
inline void initialize() { AURA_CUDA_SAFE_CALL(cuInit(0)); }

/// Finalize base.
inline void finalize()
{
        // Pass
}

} // cuda
} // base_detail
} // aura
} // boost

max_stars_repo_name: sschaetz/aura

max_issues_repo_name: sschaetz/aura

max_forks_repo_name: sschaetz/aura


text:
#pragma once

#include "terminalpp/colour.hpp"
#include "terminalpp/effect.hpp"
#include <boost/container_hash/hash.hpp>
#include <boost/operators.hpp>
#include <iosfwd>

namespace terminalpp {

//* =========================================================================
/// \brief A structure that carries around the presentation attributes of
/// an ANSI element.
//* =========================================================================
struct attribute
  : private boost::less_than_comparable<attribute,
            boost::equality_comparable<attribute>>
{
    //* =====================================================================
    /// \brief Initialises the attribute with the colours and effects
    /// specified
    //* =====================================================================
    constexpr attribute(
        colour foreground_colour = colour(),
        colour background_colour = colour(),
        intensity intensity_effect = ansi::graphics::intensity::normal,
        underlining underlining_effect = ansi::graphics::underlining::not_underlined,
        polarity polarity_effect = ansi::graphics::polarity::positive,
        blinking blink_effect = ansi::graphics::blinking::steady)
      : foreground_colour_(foreground_colour),
        background_colour_(background_colour),
        intensity_(intensity_effect),
        underlining_(underlining_effect),
        polarity_(polarity_effect),
        blinking_(blink_effect)
    {
    }

    //* =====================================================================
    /// \brief Hash function
    //* =====================================================================
    friend std::size_t hash_value(attribute const &attr) noexcept
    {
        std::size_t seed = 0;
        boost::hash_combine(seed, attr.foreground_colour_);
        boost::hash_combine(seed, attr.background_colour_);
        boost::hash_combine(seed, attr.intensity_);
        boost::hash_combine(seed, attr.underlining_);
        boost::hash_combine(seed, attr.polarity_);
        boost::hash_combine(seed, attr.blinking_);

        return seed;
    }

    // Graphics Attributes
    colour      foreground_colour_;
    colour      background_colour_;
    intensity   intensity_;
    underlining underlining_;
    polarity    polarity_;
    blinking    blinking_;
};

//* =========================================================================
/// \brief Less-than operator for attributes.
//* =========================================================================
constexpr bool operator<(attribute const &lhs, attribute const &rhs)
{
    if (lhs.foreground_colour_ < rhs.foreground_colour_)
    {
        return true;
    }
    else if (lhs.foreground_colour_ == rhs.foreground_colour_)
    {
        if (lhs.background_colour_ < rhs.background_colour_)
        {
            return true;
        }
        else if (lhs.background_colour_ == rhs.background_colour_)
        {
            if (lhs.intensity_ < rhs.intensity_)
            {
                return true;
            }
            else if (lhs.intensity_ == rhs.intensity_)
            {
                if (lhs.underlining_ < rhs.underlining_)
                {
                    return true;
                }
                else if (lhs.underlining_ == rhs.underlining_)
                {
                    if (lhs.polarity_ < rhs.polarity_)
                    {
                        return true;
                    }
                    else if (lhs.polarity_ == rhs.polarity_)
                    {
                        if (lhs.blinking_ < rhs.blinking_)
                        {
                            return true;
                        }
                    }
                }
            }
        }
    }

    return false;
}

//* =========================================================================
/// \brief Equality operator for attributes.
//* =========================================================================
constexpr bool operator==(attribute const &lhs, attribute const &rhs)
{
    return lhs.foreground_colour_ == rhs.foreground_colour_
        && lhs.background_colour_ == rhs.background_colour_
        && lhs.intensity_         == rhs.intensity_
        && lhs.underlining_       == rhs.underlining_
        && lhs.polarity_          == rhs.polarity_
        && lhs.blinking_          == rhs.blinking_;
}

//* =========================================================================
/// \brief Streaming output operator for attribute.  Prints the text
/// equivalent of the attribute (e.g. "foreground_colour[red],bold")
//* =========================================================================
TERMINALPP_EXPORT
std::ostream &operator<<(std::ostream &out, attribute const &attr);

}

namespace std {

template <>
struct hash<terminalpp::attribute>
{
    using argument_type = terminalpp::attribute;
    using result_type = std::size_t;

    result_type operator()(argument_type const &attr) const noexcept
    {
        return hash_value(attr);
    }
};

}

max_stars_repo_name: ruszkait/terminalpp

max_issues_repo_name: p-ranav/terminalpp

max_forks_repo_name: p-ranav/terminalpp


text:
/*
 The MIT License (MIT)

 Copyright (c) [2016] [BTC.COM]

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

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

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

#include "StratumSessionEth.h"

#include "StratumMessageDispatcher.h"
#include "StratumMinerEth.h"
#include "DiffController.h"

#include <boost/make_unique.hpp>

// Remove the Ethereum address prefix from worker's full name
// 0x00d8c82Eb65124Ea3452CaC59B64aCC230AA3482.test.aaa -> test.aaa
static string stripEthAddrFromFullName(const string &fullNameStr) {
  const size_t pos = fullNameStr.find('.');
  // The Ethereum address is 42 bytes and starting with "0x" as normal
  // Example: 0x00d8c82Eb65124Ea3452CaC59B64aCC230AA3482
  if (pos == 42 && fullNameStr[0] == '0' && (fullNameStr[1] == 'x' || fullNameStr[1] == 'X')) {
    return fullNameStr.substr(pos + 1);
  }
  return fullNameStr;
}

StratumSessionEth::StratumSessionEth(ServerEth &server,
                                     struct bufferevent *bev,
                                     struct sockaddr *saddr,
                                     uint32_t extraNonce1)
    : StratumSessionBase(server, bev, saddr, extraNonce1)
    , ethProtocol_(StratumProtocolEth::ETHPROXY)
    , nicehashLastSentDiff_(0)
    , currentJobDiff_(0){
}

void StratumSessionEth::sendSetDifficulty(LocalJob &localJob, uint64_t difficulty) {
  // Some ETH stratum variants have no set difficulty method, but change the target directly
  currentJobDiff_ = difficulty;
}

void StratumSessionEth::sendMiningNotify(shared_ptr<StratumJobEx> exJobPtr, bool isFirstJob) {
  if (StratumProtocolEth::ETHPROXY == ethProtocol_) {
    // AntMiner E3 need id to be 0, otherwise it will not be able to mine.
    // It does not actively call `eth_getWork` like other ETHProxy miners.
    sendMiningNotifyWithId(exJobPtr, "0");
  } else {
    sendMiningNotifyWithId(exJobPtr, "null");
  }
}

void StratumSessionEth::sendMiningNotifyWithId(shared_ptr<StratumJobEx> exJobPtr, const string &idStr) {
  if (state_ < AUTHENTICATED || exJobPtr == nullptr) {
    LOG(ERROR) << "eth sendMiningNotify failed, state: " << state_;
    return;
  }

  StratumJobEth *ethJob = dynamic_cast<StratumJobEth *>(exJobPtr->sjob_);
  if (nullptr == ethJob) {
    return;
  }

  string header = ethJob->headerHash_;
  string seed = ethJob->seedHash_;

  // strip prefix "0x"
  if (66 == header.length()) {
    header = header.substr(2, 64);
  }
  if (66 == seed.length()) {
    seed = seed.substr(2, 64);
  }

  auto ljob = findLocalJob(header);
  // create a new LocalJobEth if not exists
  if (ljob == nullptr) {
    ljob = &addLocalJob(ethJob->jobId_, header);
  } else {
    dispatcher_->addLocalJob(*ljob);
  }

  string strShareTarget = Eth_DifficultyToTarget(currentJobDiff_);

  // extraNonce1_ == Session ID, 24 bits.
  // Miners will fills 0 after the prefix to 64 bits.
  uint32_t startNoncePrefix = extraNonce1_;

  // Tips: NICEHASH_STRATUM use an extrNnonce, it is really an extraNonce (not startNonce)
  // and is sent at the subscribe of the session.

  DLOG(INFO) << "new eth stratum job mining.notify: share difficulty=" << std::hex << currentJobDiff_
             << ", share target=" << strShareTarget << ", protocol=" << getProtocolString(ethProtocol_);
  string strNotify;

  switch (ethProtocol_) {
  case StratumProtocolEth::STRATUM: {
    //Etherminer mining.notify
    //{"id":6,"method":"mining.notify","params":
    //["dd159c7ec5b056ad9e95e7c997829f667bc8e34c6d43fcb9e0c440ed94a85d80",
    //"dd159c7ec5b056ad9e95e7c997829f667bc8e34c6d43fcb9e0c440ed94a85d80",
    //"a8784097a4d03c2d2ac6a3a2beebd0606aa30a8536a700446b40800841c0162c",
    //"0000000112e0be826d694b2e62d01511f12a6061fbaec8bc02357593e70e52ba",false]}
    strNotify = Strings::Format("{\"id\":%s,\"method\":\"mining.notify\","
                                "\"params\":[\"%s\",\"%s\",\"%s\",\"%s\",%s],"
                                "\"height\":%lu}\n",
                                idStr.c_str(),
                                header.c_str(),
                                header.c_str(),
                                seed.c_str(),
                                strShareTarget.c_str(),
                                exJobPtr->isClean_ ? "true" : "false",
                                ethJob->height_);
  }
    break;
  case StratumProtocolEth::ETHPROXY: {
    //Clymore eth_getWork
    //{"id":3,"jsonrpc":"2.0","result":
    //["0x599fffbc07777d4b6455c0e7ca479c9edbceef6c3fec956fecaaf4f2c727a492",
    //"0x1261dfe17d0bf58cb2861ae84734488b1463d282b7ee88ccfa18b7a92a7b77f7",
    //"0x0112e0be826d694b2e62d01511f12a6061fbaec8bc02357593e70e52ba","0x4ec6f5"]}
    strNotify = Strings::Format("{\"id\":%s,\"jsonrpc\":\"2.0\","
                                "\"result\":[\"0x%s\",\"0x%s\",\"0x%s\","
                                // nonce cannot start with 0x because of
                                // a compatibility issue with AntMiner E3.
                                "\"%06x\"],"
                                "\"height\":%lu}\n",
                                idStr.c_str(),
                                header.c_str(),
                                seed.c_str(),
        //Claymore use 58 bytes target
                                strShareTarget.substr(6, 58).c_str(),
                                startNoncePrefix,
                                ethJob->height_);
  }
    break;
  case StratumProtocolEth::NICEHASH_STRATUM: {
    // send new difficulty
    if (currentJobDiff_ != nicehashLastSentDiff_) {
      // NICEHASH_STRATUM mining.set_difficulty
      // {"id": null,
      //  "method": "mining.set_difficulty",
      //  "params": [ 0.5 ]
      // }
      strNotify += Strings::Format("{\"id\":%s,\"method\":\"mining.set_difficulty\","
                                   "\"params\":[%lf]}\n", idStr.c_str(), Eth_DiffToNicehashDiff(currentJobDiff_));
      nicehashLastSentDiff_ = currentJobDiff_;
    }

    // NICEHASH_STRATUM mining.notify
    // { "id": null,
    //   "method": "mining.notify",
    //   "params": [
    //     "bf0488aa",
    //     "abad8f99f3918bf903c6a909d9bbc0fdfa5a2f4b9cb1196175ec825c6610126c",
    //     "645cf20198c2f3861e947d4f67e3ab63b7b2e24dcc9095bd9123e7b33371f6cc",
    //     true
    //   ]}
    strNotify += Strings::Format("{\"id\":%s,\"method\":\"mining.notify\","
                                 "\"params\":[\"%s\",\"%s\",\"%s\",%s],"
                                 "\"height\":%lu}\n",
                                 idStr.c_str(),
                                 header.c_str(),
                                 seed.c_str(),
                                 header.c_str(),
                                 exJobPtr->isClean_ ? "true" : "false",
                                 ethJob->height_);
  }
    break;
  }

  DLOG(INFO) << strNotify;

  if (!strNotify.empty())
    sendData(strNotify); // send notify string
  else
    LOG(ERROR) << "Eth notify string is empty";

  // clear localEthJobs_
  clearLocalJobs();
}

void StratumSessionEth::handleRequest(const std::string &idStr,
                                      const std::string &method,
                                      const JsonNode &jparams,
                                      const JsonNode &jroot) {
  if (method == "mining.subscribe") {
    handleRequest_Subscribe(idStr, jparams, jroot);
  }
  else if (method == "mining.authorize" || method == "eth_submitLogin") {
    handleRequest_Authorize(idStr, jparams, jroot);
  }
  else if (dispatcher_) {
    dispatcher_->handleRequest(idStr, method, jparams, jroot);
  }
}

void StratumSessionEth::handleRequest_Subscribe(const string &idStr,
                                                const JsonNode &jparams,
                                                const JsonNode &jroot) {

  if (state_ != CONNECTED) {
    responseError(idStr, StratumStatus::UNKNOWN);
    return;
  }

  auto params = jparams.children();

  if (params->size() >= 1) {
    setClientAgent(params->at(0).str().substr(0, 30));  // 30 is max len
  }

  string protocolStr;
  if (params->size() >= 2) {
    protocolStr = params->at(1).str();
    // tolower
    std::transform(protocolStr.begin(), protocolStr.end(), protocolStr.begin(), ::tolower);
  }

  // session id and miner ip need to pass within params if working with stratum switcher
#ifdef WORK_WITH_STRATUM_SWITCHER
  //  params[0] = client version           [require]
    //  params[1] = protocol version         [require, can be empty]
    //  params[2] = session id / ExtraNonce1 [require]
    //  params[3] = miner's real IP (unit32) [optional]

    if (params->size() < 3) {
      responseError(idStr, StratumStatus::ILLEGAL_PARARMS);
      return;
    }

    string extraNonce1Str = params->at(2).str().substr(0, 8);  // 8 is max len
    sscanf(extraNonce1Str.c_str(), "%x", &extraNonce1_); // convert hex to int

    // receive miner's IP from stratumSwitcher
    if (params->size() >= 4) {
      clientIpInt_ = htonl(params->at(3).uint32());

      // ipv4
      clientIp_.resize(INET_ADDRSTRLEN);
      struct in_addr addr;
      addr.s_addr = clientIpInt_;
      clientIp_ = inet_ntop(AF_INET, &addr, (char *)clientIp_.data(), (socklen_t)clientIp_.size());
      LOG(INFO) << "client real IP: " << clientIp_;
    }
#endif // WORK_WITH_STRATUM_SWITCHER

  if (protocolStr.substr(0, 16) == "ethereumstratum/") {
    ethProtocol_ = StratumProtocolEth::NICEHASH_STRATUM;

    string noncePrefix = Strings::Format("%06x", extraNonce1_);
    if (isNiceHashClient_) {
      // NiceHash only accepts 2 bytes or shorter of extraNonce.
      noncePrefix = noncePrefix.substr(0, 4);
    }

    // mining.notify of NICEHASH_STRATUM's subscribe
    // {
    //   "id": 1,
    //   "result": [
    //     [
    //       "mining.notify",
    //       "ae6812eb4cd7735a302a8a9dd95cf71f",
    //       "EthereumStratum/1.0.0"
    //     ],
    //     "080c"
    //   ],
    //   "error": null
    // }
    const string s = Strings::Format("{\"id\":%s,\"result\":[["
                                     "\"mining.notify\","
                                     "\"%06x\","
                                     "\"EthereumStratum/1.0.0\""
                                     "],\"%s\"],\"error\":null}\n",
                                     idStr.c_str(), extraNonce1_, noncePrefix.c_str());
    sendData(s);
  }
#ifdef WORK_WITH_STRATUM_SWITCHER
    else if (protocolStr.substr(0, 9) == "ethproxy/") {
    // required for stratum switcher
    // Because ethproxy has no subscribe phase, switcher has no chance to set session id.
    // So deliberately added a subscribe phase of ethproxy here.
    ethProtocol_ = StratumProtocolEth::ETHPROXY;
    responseTrue(idStr);
  }
#endif // WORK_WITH_STRATUM_SWITCHER
  else {
    ethProtocol_ = StratumProtocolEth::STRATUM;
    responseTrue(idStr);
  }

  state_ = SUBSCRIBED;
}

void StratumSessionEth::handleRequest_Authorize(const string &idStr,
                                                const JsonNode &jparams,
                                                const JsonNode &jroot) {
  // const type cannot access string indexed object member
  JsonNode &jsonRoot = const_cast<JsonNode &>(jroot);

#ifndef WORK_WITH_STRATUM_SWITCHER
  if (StratumProtocolEth::ETHPROXY == ethProtocol_ && jsonRoot["method"].str() == "eth_submitLogin") {
    // Subscribe is not required for ETHPROXY (without stratum switcher).
    // But if WORK_WITH_STRATUM_SWITCHER enabled, subscribe for ETHProxy is required.
    state_ = SUBSCRIBED;
  }
#endif

  if (state_ != SUBSCRIBED) {
    responseError(idStr, StratumStatus::NOT_SUBSCRIBED);
    return;
  }

  // STRATUM / NICEHASH_STRATUM:        {"id":3, "method":"mining.authorize", "params":["test.aaa", "x"]}
  // ETH_PROXY (Claymore):              {"worker": "eth1.0", "jsonrpc": "2.0", "params": ["0x00d8c82Eb65124Ea3452CaC59B64aCC230AA3482.test.aaa", "x"], "id": 2, "method": "eth_submitLogin"}
  // ETH_PROXY (EthMiner, situation 1): {"id":1, "method":"eth_submitLogin", "params":["0x00d8c82Eb65124Ea3452CaC59B64aCC230AA3482"], "worker":"test.aaa"}
  // ETH_PROXY (EthMiner, situation 2): {"id":1, "method":"eth_submitLogin", "params":["test"], "worker":"aaa"}

  if (jparams.children()->size() < 1) {
    responseError(idStr, StratumStatus::INVALID_USERNAME);
    return;
  }

  string fullName, password;

  fullName = jparams.children()->at(0).str();
  if (jsonRoot["worker"].type() == Utilities::JS::type::Str) {
    fullName += '.';
    fullName += jsonRoot["worker"].str();
  }
  fullName = stripEthAddrFromFullName(fullName);

  if (jparams.children()->size() > 1) {
    password = jparams.children()->at(1).str();
  }

  checkUserAndPwd(idStr, fullName, password);
  return;
}

unique_ptr<StratumMiner> StratumSessionEth::createMiner(const std::string &clientAgent,
                                                        const std::string &workerName,
                                                        int64_t workerId) {
  return boost::make_unique<StratumMinerEth>(*this,
                                             *getServer().defaultDifficultyController_,
                                             clientAgent,
                                             workerName,
                                             workerId,
                                             ethProtocol_);
}

max_stars_repo_name: indimining/btcpool

max_issues_repo_name: indimining/btcpool

max_forks_repo_name: indimining/btcpool


text:
/**
    @author Laurens van Dam
    @date 19/02/2018
    @copyright 2018 All rights reserved.
**/

#ifndef PAIRHMM_DEBUG_VALUES_HPP
#define PAIRHMM_DEBUG_VALUES_HPP

#include <iostream>
#include <fstream>
#include <iomanip>
#include <vector>
#include <chrono>
#include <ctime>
#include <cstdarg>
#include <boost/multiprecision/cpp_dec_float.hpp>

#include "defines.hpp"

using namespace std;
using boost::multiprecision::cpp_dec_float_100;

template<class T>
class DebugValues {
public:
    std::vector<Entry> items;

    DebugValues() = default;

    void debugValue(T value, const char *format, ...) {
        char buf[1024];

        va_list arglist;
        va_start(arglist, format);
        vsprintf(buf, format, arglist);
        va_end(arglist);

        Entry entry;
        entry.name = string(buf);

        entry.value = static_cast<cpp_dec_float_100>(value);
        items.push_back(entry);
    }

    std::vector<std::string> getNames() {
        std::vector<std::string> result;
        for (auto el : items) {
            result.push_back(el.name);
        }
        return result;
    }

    std::vector<cpp_dec_float_100> getValues() {
        std::vector<cpp_dec_float_100> result;
        for (auto el : items) {
            result.push_back(el.value);
        }
        return result;
    }
};

#endif //PAIRHMM_DEBUG_VALUES_HPP


text:
#include <iostream>
///#include <io.h>
#include <math.h>
#include <Eigen/Core>
#include <opencv2/core/eigen.hpp>
#include <opencv2/opencv.hpp>

#include <math.h>

//add scene retrieving.
#include "scene_retrieve.h"
#include "LoopClosingManager.h"
#include "nlohmann/json.hpp"

using namespace std;
using namespace nlohmann;
//Scene Pointer
//Scene* pScene = NULL;

cv::Ptr<cv::ORB> orb;
void ExtractFeaturesFromCertainKeyPoints(const cv::Mat& img_in,const vector<cv::Point2f> kps_in,vector<cv::Mat>& desp_output)
{
    //reference loop closing manager,extract orb feature of these points.
    cv::Mat gray;
    cv::Mat desp;
    cv::cvtColor(img_in,gray,cv::COLOR_RGB2GRAY);
    vector<cv::KeyPoint> kp_vec;
    cv::KeyPoint::convert(kps_in,kp_vec);
    orb->compute(gray,kp_vec,desp);
    cout<<"kps_in.size():"<<kps_in.size()<<"\tdesp.rows:"<<desp.rows<<endl;
    desp_output.resize(desp.rows);
    for(int r=0;r<desp.rows;r++) desp_output[r]=desp.rowRange(r,r+1).clone();
    return;
}

std::shared_ptr<Scene> MakeSceneFromPath(const string& path)
{
    std::shared_ptr<Scene> pScene(new Scene());
    LoopClosingManager lcm();
    //step<1> parse json.
    string jsonpath(path.c_str());
    jsonpath += "/reconstruction.json";
    cout<<"Using json path: "<<jsonpath<<endl;

    std::ifstream ifstr_json( jsonpath);

//     std::ifstream ifstr_json( jsonpath.c_str() );

    json reconstruction_j;

    ifstr_json >> reconstruction_j;

    auto shots = reconstruction_j[0]["shots"];

    auto img2Rotation = new map<string, cv::Mat>;
    auto img2Translation = new map<string, cv::Mat>;

    for (json::iterator it = shots.begin(); it != shots.end(); ++it)
    {
        cv::Mat rotation_mat,translation_mat;
        string img_filename = it.key();
        cv::Mat rvec(1,3,CV_32F);
        rvec.at<float>(0,0) = (float)shots[img_filename]["rotation"][0].get<double>();
        rvec.at<float>(0,1) = (float)shots[img_filename]["rotation"][1].get<double>();
        rvec.at<float>(0,2) = (float)shots[img_filename]["rotation"][2].get<double>();
        cv::Rodrigues(rvec,rotation_mat); // get 3x3 rotation mat.

        //cv::Mat cur_image;
        //cv::imread(path+"images"+img_filename,cur_image);
        //ptr_frameinfo p = lcm.extractFeature(cur_image);
        (*img2Rotation)[img_filename] = rotation_mat;
        (*img2Translation)[img_filename] = translation_mat;
        //std::cout << it.key() << " : " << it.value() << "\n";
    }

    cout<<"??? 6"<<endl;

    //step<2> build graph,do triangulate via these features.Load "features/xxxnpz and get keypoints info."
    map<string, vector<cv::Mat> >* pMapdesp = new map<string, vector<cv::Mat> >;
    map<string, vector<cv::Mat> >& img2kpDesps = *pMapdesp;
    //map<string, vector<cv::Mat> > img2kpDesps;// = *pMapdesp;

    //map<string, vector<cv::KeyPoint> >* pMap2d = new map<string, vector<cv::KeyPoint> >;
    //map<string, vector<cv::KeyPoint> > &img2Kp2Ds = *pMap2d;
    map<string, vector<cv::KeyPoint> > img2Kp2Ds;

    map<string,vector<cv::Point3d> >* pMap3d = new map<string,vector<cv::Point3d> >;
    map<string,vector<cv::Point3d>> &img2Kp3ds = *pMap3d;
    for(json::iterator it = shots.begin();it!=shots.end();++it)
    {
        string img_filename = it.key();
        std::ifstream ifstr_img_keypoints_json((path+"/features/"+img_filename+".npz.json").c_str());
        json img_kp_json;
        ifstr_img_keypoints_json>> img_kp_json;
        vector<cv::Point2f> kps;
        vector<cv::Mat> current_img_desps;
        for(json::iterator it2 = img_kp_json.begin();it2!=img_kp_json.end();++it2)
        {
            string point_index = it2.key();//make keypoints.
            string keypoint_x_str,keypoint_y_str;
	    /*for(json::iterator it_inner = img_kp_json[point_index].begin();it_inner!=img_kp_json[point_index].end();++it_inner)
	    {
	      cout<<"Inner object:"<<*it_inner;
	    }*/
            keypoint_x_str = img_kp_json[point_index][0].get<string>();
            keypoint_y_str = img_kp_json[point_index][1].get<string>();
	    float kpx,kpy;
	    kpx = std::stof(keypoint_x_str);
	    kpy = std::stof(keypoint_y_str);
	    //cout<<"kpx,kpy:"<<kpx<<" "<<kpy<<endl;
            kps.push_back(cv::Point2f(kpx,kpy));
        }
        cv::Mat curr_img = cv::imread(path+"/images/"+img_filename);
        ExtractFeaturesFromCertainKeyPoints(curr_img,kps,current_img_desps);
        img2kpDesps[img_filename] = current_img_desps;
	/*
	std::vector<cv::KeyPoint> *kps_ = new vector<cv::KeyPoint>;
	cv::KeyPoint::convert(kps,*kps_);
        img2Kp2Ds[img_filename] = *kps_;*/
	std::vector<cv::KeyPoint> kps_;
	cv::KeyPoint::convert(kps,kps_);
        img2Kp2Ds[img_filename] = kps_;

        img2Kp3ds[img_filename] = vector<cv::Point3d>();
        img2Kp3ds[img_filename].resize(img2Kp2Ds[img_filename].size());
    }
    //step<3>.Get 3d position of these points,and make a frame of scene.
    //open undistorted_tracks.csv. actually it's a tsv file.
    ifstream track_ifstr((path+"/undistorted_tracks.csv").c_str());
    vector<vector <string> >fields;
    string line;
    while(getline(track_ifstr,line))
    {
        stringstream sep(line);
        string field;
        fields.push_back(vector<string>());
        while(getline(sep,field,'\t'))
        {
            fields.back().push_back(field);
        }
    }
    std::map<string,std::vector<int> > map_index_with_3d_pos;
    const auto &points_obj = reconstruction_j[0]["points"];
    for(int line_index=0;line_index<fields.size();line_index++) // traverse all tracks to find point 3d coordinate.
    {
        vector<string>& curr_line = fields[line_index];
        string img_filename,track_id_str,feature_id_str;
        int track_id,feature_id;
        img_filename = curr_line[0];
        track_id_str = curr_line[1];
        feature_id_str = curr_line[2];
        track_id = std::stoi(track_id_str);
        feature_id = std::stoi(feature_id_str);
	//string px,py,pz;
	cout<<endl;
	cout<<"curr_line[0]:"<<curr_line[0]<<endl;
        cout<<"at line_index:"<<line_index<<endl;
	cout<<"track_id:"<<track_id_str<<endl;
	cout<<"feature_id:"<<feature_id_str<<endl;
	//auto z = reconstruction_j[0];
	//auto a = reconstruction_j[0]["points"];
	cout <<"bb"<<endl;
	//auto b = reconstruction_j[0]["points"][track_id_str];
	cout <<"cc"<<endl;
	//auto c = reconstruction_j[0]["points"][track_id_str]["coordinates"];
        cout <<"0"<<endl;

	if(points_obj.find(track_id_str)==points_obj.end() )
	{
	  //is a outlier.
	  cout <<"is a outlier"<<endl;
	  continue;
	}
	else
	{
	  cout<<"is a inlier!"<<endl;
	}
	double px = reconstruction_j[0]["points"][track_id_str]["coordinates"][0].get<double>();
	cout<<"1"<<endl;
	double py = reconstruction_j[0]["points"][track_id_str]["coordinates"][1].get<double>();
	cout<<"2"<<endl;
	double pz = reconstruction_j[0]["points"][track_id_str]["coordinates"][2].get<double>();
	cout<<"3"<<endl;
	cout <<"img2Kp3ds[img_filename].size:"<<img2Kp3ds[img_filename].size()<<"\timg2Kp2Ds[img_filename].size():"<<img2Kp2Ds[img_filename].size()<<endl;
	if(img2Kp2Ds[img_filename].size() == 0)
	{
	  cout <<"this image is not inside of reconstruction[0],ignored!"<<endl;
	  continue;
	}
        img2Kp3ds[img_filename][feature_id] = cv::Point3d(px,py,pz);

	cout<<"point added!"<<endl;
	//map_index_with_3d_pos[img_filename].push_back(feature_id);//Unused now.
    }
    cout<<"3d points loaded."<<endl;
    for (json::iterator it = shots.begin(); it != shots.end(); ++it)
    {
        //cv::Mat rotation_mat,translation_mat;
        string img_filename = it.key();
        cv::Mat temp_desp_mat(img2kpDesps[img_filename].size(),//rows
                    32,//cols
                        0
        );
        cout<<"temp_desp_mat:"<<temp_desp_mat.cols<<"|"<<temp_desp_mat.rows<<endl;
        cout<<"Image:"<<img_filename<<img2kpDesps[img_filename].size()<<";"<<img2kpDesps[img_filename][0].rows<<","<<img2kpDesps[img_filename][0].cols<<endl;

        for(int index = 0;index< img2kpDesps[img_filename].size();index++)
        {
            cout<<"index:"<<index<<endl;
            cv::Mat& temp = img2kpDesps[img_filename][index];
            cout<<temp.cols<<"|"<<temp.rows<<endl;
            //temp_desp_mat.rowRange(index,index+1) = img2kpDesps[img_filename][index].row(0);//img2kpDesps[img_filename][index].rowRange(0,1);//.clone();
            temp_desp_mat.row(index) = img2kpDesps[img_filename][index].row(0);//img2kpDesps[img_filename][index].rowRange(0,1);//.clone();
        }

        //NOTE method 1, this will serialize kps, mps and desp;
        //pScene->addFrame(img2Kp2Ds[img_filename], img2Kp3ds[img_filename], temp_desp_mat.clone());

        //NOTE method 2, this will serialize kps, mps, desps, R and t
        cv::Mat R = (cv::Mat_<double>(3,3) << 0, -1.1, 0, -1.2, 5.3, -1.4, 0, -1.5, 0);
        cv::Mat T = (cv::Mat_<double>(1,3) << 0, -1.5, 0);
        cout<<"Current R and T are: "<<endl<<R<<endl<<T<<endl;

        pScene->addFrame(img2Kp2Ds[img_filename], img2Kp3ds[img_filename], temp_desp_mat.clone(), R, T);

    }
    //step<4>.See if this scene has scale factor.

    //pScene->hasScale = false;// for default.
    return pScene;
}

int main(int argc,char** argv)
{
    cout<<"CAUTION:Do not forget set opensfm config feature_type to 'ORB'."<<endl;
    if(argc<3)
    {
        cout<<"Usage: MakeSceneFromOpenSfMModel OpenSfM_project_dir voc_path"<<endl;
        return -1;
    }
    string project_path(argv[1]);
    string voc_path(argv[2]);
    orb = cv::ORB::create();
    std::shared_ptr<Scene>* pp;
    pp = new std::shared_ptr<Scene>;
    *pp= MakeSceneFromPath(project_path);
    (*pp)->saveFile("scene.scene");
    return 0;
}

max_stars_repo_name: mfkiwl/GAAS

max_issues_repo_name: Wayne-xixi/GAAS

max_forks_repo_name: Wayne-xixi/GAAS


text:
#include <stdio.h>
#include <string>
#include <boost/asio/io_service.hpp>
#include <boost/asio/deadline_timer.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

#include <ain/tcp/acceptor.hpp>
#include <ain/tcp/service_handler.hpp>

using ain::tcp::service_handler;
using ain::tcp::connection_ptr;

class echo_handler
	: public service_handler
{
public:
	void handle_open(connection_ptr c)
	{
		printf("%s - remote_endpoint(%s:%d)\n",
			__FUNCTION__,
			c->socket().remote_endpoint().address().to_string().c_str(),
			c->socket().remote_endpoint().port());

		char* buffer = (char*)malloc(8192);
		c->read(buffer, 8192);
	}

	void handle_close(connection_ptr c)
	{
		printf("%s - ... ^^\n", __FUNCTION__);
	}

	void handle_read(connection_ptr c,
		const boost::system::error_code& ec,
		std::size_t bytes_transferred,
		char* buffer)
	{
		printf("%s - remote_endpoint(%s:%d) ec(%s) bytes_transferred(%ld)\n",
			__FUNCTION__,
			c->socket().remote_endpoint().address().to_string().c_str(),
			c->socket().remote_endpoint().port(),
			ec.message().c_str(), bytes_transferred
			);

		buffer[bytes_transferred] = '\0';
		printf("%s - read data(%s)\n", __FUNCTION__, buffer);

		c->write(buffer, bytes_transferred);
		c->read(buffer, 8192);
	}

	void handle_write(connection_ptr c,
		const boost::system::error_code& ec,
		char* buffer)
	{
		printf("%s - remote_endpoint(%s:%d) ec(%s)\n",
			__FUNCTION__,
			c->socket().remote_endpoint().address().to_string().c_str(),
			c->socket().remote_endpoint().port(),
			ec.message().c_str()
			);
	}
};

int main(int argc, char** argv)
{
	printf("AIN START... :)\n");

	boost::asio::io_service io_service;
	echo_handler eh;

	ain::tcp::acceptor dark(io_service, eh);
	dark.open(7905);

	boost::asio::deadline_timer timer(io_service, boost::posix_time::seconds(1));
	timer.wait();

	printf("AIN RUN...\n");
	io_service.run();

	printf("AIN END...\n");

	return 0;
}

max_stars_repo_name: eggncider/ain

max_issues_repo_name: eggncider/ain

max_forks_repo_name: eggncider/ain