text:
// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
The MIT License

Copyright (c) 2008, 2009 Flusspferd contributors (see "CONTRIBUTORS" or
                                       http://flusspferd.org/contributors.txt)

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.
*/

#ifndef FLUSSPFERD_CREATE_FUNCTION_HPP
#define FLUSSPFERD_CREATE_FUNCTION_HPP

#include "native_function.hpp"
#include "../create.hpp"
#include "../string.hpp"
#include "../local_root_scope.hpp"
#include <boost/static_assert.hpp>

namespace flusspferd {

/**
 * Tag class for flusspferd::create.
 *
 * Used as an alternative to flusspferd::method when the first C++ parameter
 * should <b>not</b> be the Javascript 'this' object.
 *
 * @ingroup create
 */
struct function {};

/**
 * Tag class for flusspferd::create.
 *
 * Used as an alternative to flusspferd::function when the first C++
 * parameter should be the Javascript 'this' object.
 *
 * @ingroup create
 */
struct method {};

#ifndef IN_DOXYGEN

namespace detail {
  object create_source_function(
    flusspferd::string const &name,
    std::vector<flusspferd::string> const &argnames,
    flusspferd::string const &body,
    flusspferd::string const &file,
    unsigned line);

  template<bool Method, typename ArgPack>
  struct create_function_helper {
    typedef object result_type;

    typedef typename boost::parameter::value_type<
        ArgPack,
        param::tag::argument_names,
        std::vector<flusspferd::string>
      >::type ArgumentsRange;

    static result_type create(ArgPack const &arg, flusspferd::string const &func) {
      local_root_scope scope;
      ArgumentsRange const &r =
        arg[param::_argument_names | std::vector<flusspferd::string>()];
      std::vector<flusspferd::string> arg_names(boost::begin(r), boost::end(r));

      return create_source_function(
        flusspferd::string(arg[param::_name | flusspferd::string()]),
        arg_names,
        func,
        arg[param::_file | flusspferd::string()],
        arg[param::_line | 0]);
    }

    static result_type create(ArgPack const &arg, char const *func) {
      return create(arg, flusspferd::string(func));
    }

    static result_type create(
      ArgPack const &arg,
      boost::function<void (call_context&)> const &fun)
    {
      return flusspferd::create<native_function<void> >(
          boost::fusion::vector1<boost::function<void (call_context &)> >(fun),
          param::_name = arg[param::_name | flusspferd::string()],
          param::_arity = arg[param::_arity | 0]);
    }

    template<typename T>
    static result_type create(
      ArgPack const &arg,
      boost::function<T> const &fun)
    {
      return flusspferd::create<native_function<T, Method> >(
          boost::fusion::vector1<boost::function<T> >(fun),
          param::_name = arg[param::_name | flusspferd::string()],
          param::_arity = arg[param::_arity | 0]);
    }

    template<typename T>
    static result_type create(
      ArgPack const &arg,
      T *fnptr,
      typename boost::enable_if<boost::is_function<T> >::type* = 0)
    {
      return create(arg, boost::function<T>(fnptr));
    }

    template<typename T>
    static result_type create(
      ArgPack const &arg,
      void (T::*memfnptr)(call_context &))
    {
      BOOST_STATIC_ASSERT(Method);
      return flusspferd::create<native_member_function<void, T> >(
          boost::fusion::vector1<void (T::*)(call_context&)>(memfnptr),
          param::_name = arg[param::_name | flusspferd::string()],
          param::_arity = arg[param::_arity | 0]);
    }

    template<typename R, typename T>
    static result_type create(
      ArgPack const &arg,
      R T::*memfnptr)
    {
      BOOST_STATIC_ASSERT(Method);
      return flusspferd::create<native_member_function<R, T> >(
          boost::fusion::vector1<R T::*>(memfnptr),
          param::_name = arg[param::_name | flusspferd::string()],
          param::_arity = arg[param::_arity | 0]);
    }
  };

  template<bool Method>
  struct create_function_traits {
    typedef object result_type;

    typedef boost::parameter::parameters<
        param::tag::name,
        param::tag::function,
        param::tag::argument_names,
        param::tag::file,
        param::tag::line,
        param::tag::signature,
        param::tag::arity,
        container_spec,
        attributes_spec
      > parameters;

    typedef boost::parameter::parameters<
        boost::parameter::required<param::tag::name>,
        param::tag::function,
        param::tag::argument_names,
        param::tag::file,
        param::tag::line,
        param::tag::signature,
        param::tag::arity,
        attributes_spec
      > create_on_parameters;

    static result_type create() {
      flusspferd::root_string empty((flusspferd::string()));
      return create_source_function(
        empty,
        std::vector<flusspferd::string>(),
        empty,
        empty,
        0);
    }

    template<typename ArgPack>
    static
    typename boost::enable_if<
      boost::is_same<
        typename boost::parameter::binding<
          ArgPack, param::tag::signature, void
        >::type,
        void
      >,
      result_type
    >::type
    create(ArgPack const &arg) {
      typedef create_function_helper<Method, ArgPack> helper;
      return helper::create(arg, arg[param::_function]);
    }

    template<typename ArgPack>
    static
    typename boost::disable_if<
      boost::is_same<
        typename boost::parameter::binding<
          ArgPack, param::tag::signature, void
        >::type,
        void
      >,
      result_type
    >::type
    create(ArgPack const &arg) {
      typedef create_function_helper<Method, ArgPack> helper;
      typedef typename boost::parameter::value_type<
          ArgPack,
          param::tag::signature
        >::type::parameter sig;
      return helper::create(arg, boost::function<sig>(arg[param::_function]));
    }
  };

  template<>
  struct create_traits<function, void>
  : create_function_traits<false>
  {};

  template<>
  struct create_traits<method, void>
  : create_function_traits<true>
  {};
}

#endif //IN_DOXYGEN

}

#endif

ext: hpp

max_stars_repo_name: Flusspferd/flusspferd

max_issues_repo_name: Flusspferd/flusspferd

max_forks_repo_name: Flusspferd/flusspferd


text:
//-------------------------------------------------------------------
//  Nano RPC
//  https://github.com/tdv/nanorpc
//  Created:     05.2018
//  Copyright (C) 2018 tdv
//-------------------------------------------------------------------

// NANORPC

// STD
#include <cstdlib>
#include <memory>
#include <optional>
#include <stdexcept>
#include <string>
#include <thread>
#include <vector>

// BOOST
#include <boost/asio.hpp>
#include <boost/beast.hpp>

// NANORPC
#include "nanorpc/core/detail/config.h"
#include "nanorpc/http/server.h"

#ifdef NANORPC_WITH_SSL

// BOOST
#include <boost/asio/ssl.hpp>

// NANORPC
#include "nanorpc/https/server.h"

#endif  // !NANORPC_WITH_SSL

// THIS
#include "detail/constants.h"
#include "detail/utility.h"

namespace nanorpc::http
{
namespace detail
{
namespace
{

class session
    : public std::enable_shared_from_this<session>
{
public:
    session(boost::asio::ip::tcp::socket socket, core::type::executor_map const &executors,
                core::type::error_handler const &error_handler)
        : executors_{executors}
        , error_handler_{error_handler}
        , socket_{std::move(socket)}
        , strand_{socket_.get_executor()}
    {
    }

    virtual ~session() noexcept = default;

    void run() noexcept
    {
        auto self = shared_from_this();

        auto on_handshake = [self] (boost::system::error_code const &ec)
            {
                if (!ec)
                {
                    utility::post(self->socket_.get_io_context(), [self] { self->read(); }, self->error_handler_ );
                }
                else
                {
                    utility::handle_error<exception::server>(self->error_handler_,
                    std::make_exception_ptr(std::runtime_error{ec.message()}),
                    "[nanorpc::http::detail::server::session::run] ",
                    "Failed to do handshake.");

                    self->close();
                }
            };

        utility::post(socket_.get_io_context(), [self, func = std::move(on_handshake)]
                { self->handshake(std::move(func)); }, error_handler_ );

    }

protected:
    using socket_type = boost::asio::ip::tcp::socket;
    using strand_type = boost::asio::strand<boost::asio::io_context::executor_type>;

    using buffer_type = boost::beast::flat_buffer;
    using buffer_ptr = std::shared_ptr<buffer_type>;

    using request_type = boost::beast::http::request<boost::beast::http::string_body>;
    using request_ptr = std::shared_ptr<request_type>;

    using response_type = boost::beast::http::response<boost::beast::http::string_body>;
    using response_ptr = std::shared_ptr<response_type>;

    using on_completed_func = std::function<void (boost::system::error_code const &)>;

    socket_type& get_socket()
    {
        return socket_;
    }

    strand_type& get_strand()
    {
        return strand_;
    }

    virtual void handshake(on_completed_func on_handshake) = 0;
    virtual void close(boost::system::error_code &ec) = 0;
    virtual void read(buffer_ptr, request_ptr, on_completed_func on_read) = 0;
    virtual void write(response_ptr response, on_completed_func on_write) = 0;

private:
    core::type::executor_map const &executors_;
    core::type::error_handler const &error_handler_;

    socket_type socket_;
    strand_type strand_;

    void read()
    {
        auto buffer = std::make_shared<buffer_type>();
        auto request = std::make_shared<request_type>();

        auto on_read = [self = shared_from_this(), request] (boost::system::error_code const &ec) noexcept
            {
                try
                {
                    if (ec == boost::asio::error::operation_aborted)
                        return;

                    if (ec == boost::beast::http::error::end_of_stream)
                    {
                        self->close();
                        return;
                    }

                    auto const keep_alive = request->keep_alive();
                    auto const need_eof = request->need_eof();

                    self->handle_request(std::move(request));

                    if (keep_alive && self->get_socket().is_open())
                        self->read();

                    if ((need_eof || !keep_alive) && self->get_socket().is_open())
                        self->close();
                }
                catch (std::exception const &e)
                {
                    utility::handle_error<exception::server>(self->error_handler_, e,
                            "[nanorpc::http::detail::server::session::read] ",
                            "Failed to handle request.");
                    self->close();
                }
            };

        read(buffer, request, std::move(on_read));
    }

    void close()
    {
        if (!get_socket().is_open())
            return;

        utility::post(socket_.get_io_context(),
                [self = shared_from_this()]
                {
                    boost::system::error_code ec;
                    self->close(ec);
                    if (ec)
                    {
                        if (ec != boost::asio::error::operation_aborted)
                        {
                            utility::handle_error<exception::server>(self->error_handler_,
                                    std::make_exception_ptr(std::runtime_error{ec.message()}),
                                    "[nanorpc::http::detail::server::session::close] ",
                                    "Failed to close socket.");
                        }
                    }
                },
                error_handler_
            );
    }

    void handle_request(request_ptr req)
    {
        auto const target = req->target().to_string();
        auto const need_eof = req->need_eof();

        auto reply = [self = shared_from_this()] (auto resp)
            {
                auto response = std::make_shared<response_type>(std::move(resp));

                auto on_write = [self] (boost::system::error_code const &ec)
                    {
                        if (ec == boost::asio::error::operation_aborted || ec == boost::asio::error::broken_pipe)
                            return;

                        if (!ec)
                            return;

                        utility::handle_error<exception::server>(self->error_handler_,
                                std::make_exception_ptr(std::runtime_error{ec.message()}),
                                "[nanorpc::http::detail::server::session::on_write] ",
                                "Failed to write data.");

                        self->close();
                    };

                self->write(response, std::move(on_write) );
            };

        auto const ok =
            [&req](core::type::buffer buffer)
            {
                response_type res{boost::beast::http::status::ok, req->version()};
                res.set(boost::beast::http::field::server, constants::server_name);
                res.set(boost::beast::http::field::content_type, constants::content_type);
                res.keep_alive(req->keep_alive() && !req->need_eof());
                res.body().assign({begin(buffer), end(buffer)});
                res.prepare_payload();
                return res;
            };

        auto const not_found = [&req, &target]
            {
                response_type res{boost::beast::http::status::not_found, req->version()};
                res.set(boost::beast::http::field::server, constants::server_name);
                res.set(boost::beast::http::field::content_type, constants::content_type);
                res.keep_alive(req->keep_alive() && !req->need_eof());
                res.body() = "The resource \"" + target + "\" was not found.";
                res.prepare_payload();
                return res;
            };

        auto const server_error =
            [&req](boost::beast::string_view what)
            {
                response_type res{boost::beast::http::status::internal_server_error, req->version()};
                res.set(boost::beast::http::field::server, constants::server_name);
                res.set(boost::beast::http::field::content_type, constants::content_type);
                res.keep_alive(req->keep_alive() && !req->need_eof());
                res.body() = "An error occurred: \"" + what.to_string() + "\"";
                res.prepare_payload();
                return res;
            };

        auto const bad_request =
        [&req](boost::beast::string_view why)
            {
                response_type res{boost::beast::http::status::bad_request, req->version()};
                res.set(boost::beast::http::field::server, constants::server_name);
                res.set(boost::beast::http::field::content_type, constants::content_type);
                res.keep_alive(req->keep_alive() && !req->need_eof());
                res.body() = why.to_string();
                res.prepare_payload();
                return res;
            };

        if (target.empty())
        {
            reply(not_found());
            return;
        }

        auto const iter = executors_.find(target);
        if (iter == end(executors_))
        {
            utility::handle_error<exception::server>(error_handler_,
                    "[nanorpc::http::detail::server::session::handle_request] ",
                    "Resource \"", target, "\" not found.");

            reply(not_found());

            return;
        }

        auto &executor = iter->second;
        if (!executor)
        {
            utility::handle_error<exception::server>(error_handler_,
                    "[nanorpc::http::detail::server::session::handle_request] ",
                    "No exicutor.");

            reply(server_error("Empty exicutor."));

            return;
        }

        auto const &content = req->body();
        if (content.empty())
        {
            utility::handle_error<exception::server>(error_handler_,
                    "[nanorpc::http::detail::server::session::handle_request] ",
                    "The request has no a content.");

            reply(bad_request("No content."));

            return;
        }

        try
        {
            auto response_data = executor({begin(content), end(content)});
            reply(ok(std::move(response_data)));

            if (need_eof)
                close();
        }
        catch (std::exception const &e)
        {
            reply(server_error("Handling error."));

            utility::handle_error<exception::server>(error_handler_, e,
                    "[nanorpc::http::detail::server::session::handle_request] ",
                    "Failed to handler request.");

            return;
        }
    }
};

class listener final
    : public std::enable_shared_from_this<listener>
{
public:
    using session_ptr = std::shared_ptr<session>;
    using session_factory  = std::function<session_ptr (boost::asio::ip::tcp::socket,
            core::type::executor_map const &, core::type::error_handler const &)>;

    listener(boost::asio::io_context &context, boost::asio::ip::tcp::endpoint const &endpoint,
            session_factory make_session,
            core::type::executor_map &executors, core::type::error_handler &error_handler)
        : make_session_{std::move(make_session)}
        , executors_{executors}
        , error_handler_{error_handler}
        , context_{context}
        , acceptor_{context_}
        , socket_{context_}
    {
        boost::system::error_code ec;

        acceptor_.open(endpoint.protocol(), ec);
        if (ec)
            throw std::runtime_error{"Failed to open acceptor. Message: " + ec.message()};

        acceptor_.set_option(boost::asio::socket_base::reuse_address{true}, ec);
        if (ec)
            throw std::runtime_error{"Failed to set option \"reuse_address\". Message: " + ec.message()};

        acceptor_.bind(endpoint, ec);
        if (ec)
            throw std::runtime_error{"Failed to bind acceptor. Message: " + ec.message()};

        acceptor_.listen(boost::asio::socket_base::max_listen_connections, ec);
        if (ec)
            throw std::runtime_error{"Failed to start listen. Message: " + ec.message()};
    }

    void run()
    {
        utility::post(context_, [self = shared_from_this()] { self->accept(); }, error_handler_ );
    }

private:
    session_factory make_session_;
    core::type::executor_map const &executors_;
    core::type::error_handler const &error_handler_;

    boost::asio::io_context &context_;
    boost::asio::ip::tcp::acceptor acceptor_;
    boost::asio::ip::tcp::socket socket_;

    void accept() noexcept
    {
        try
        {
            acceptor_.async_accept(socket_,
                    [self = this] (boost::system::error_code const &ec)
                    {
                        try
                        {
                            if (ec)
                            {
                                if (ec != boost::asio::error::operation_aborted)
                                {
                                    utility::handle_error<exception::server>(self->error_handler_,
                                            std::make_exception_ptr(std::runtime_error{ec.message()}),
                                            "[nanorpc::http::detail::listener::accept] ",
                                            "Failed to accept connection.");
                                }
                            }
                            else
                            {
                                self->make_session_(std::move(self->socket_),
                                        self->executors_, self->error_handler_)->run();
                            }
                        }
                        catch (std::exception const &e)
                        {
                            utility::handle_error<exception::server>(self->error_handler_, e,
                                    "[nanorpc::http::detail::listener::accept] ",
                                    "Failed to process the accept method.");
                        }
                        utility::post(self->context_, [self] { self->accept(); }, self->error_handler_ );
                    }
                );
        }
        catch (std::exception const &e)
        {
            utility::handle_error<exception::server>(error_handler_, e,
                    "[nanorpc::http::detail::listener::accept] ",
                    "Failed to call asynk_accept.");
        }
    }
};

class server
    : public std::enable_shared_from_this<server>
{
public:
    server(server const &) = delete;
    server& operator = (server const &) = delete;

    server(std::string_view address, std::string_view port, std::size_t workers,
            core::type::executor_map executors, core::type::error_handler error_handler)
        : executors_{std::move(executors)}
        , error_handler_{std::move(error_handler)}
        , workers_count_{std::max<int>(1, workers)}
        , context_{workers_count_}
        , endpoint_{boost::asio::ip::make_address(address),
                static_cast<unsigned short>(std::stol(port.data()))}
    {
    }

    virtual ~server() noexcept
    {
        if (stopped())
            return;

        try
        {
            stop();
        }
        catch (std::exception const &e)
        {
            utility::handle_error<exception::server>(error_handler_, e,
                    "[nanorpc::http::server::~sserver] ",
                    "Failed to stop server.");
        }
    }

    void run()
    {
        if (!stopped())
            throw std::runtime_error{"[" + std::string{__func__ } + "] Already running."};

        auto factory = std::bind(&server::make_session, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
        auto new_listener = std::make_shared<listener>(context_, endpoint_, std::move(factory), executors_, error_handler_);
        new_listener->run();

        threads_type workers;
        workers.reserve(workers_count_);

        for (auto i = workers_count_ ; i ; --i)
        {
            workers.emplace_back(
                    [self = this]
                    {
                        try
                        {
                            self->context_.run();
                        }
                        catch (std::exception const &e)
                        {
                            utility::handle_error<exception::server>(self->error_handler_, e,
                                    "[nanorpc::http::server::run] ",
                                    "Failed to run server.");

                            std::exit(EXIT_FAILURE);
                        }
                    }
                );
        }

        listener_ = std::move(new_listener);
        workers_ = std::move(workers);
    }

    void stop()
    {
        if (stopped())
            throw std::runtime_error{"[" + std::string{__func__ } + "] Not runned."};

        listener_.reset();
        context_.stop();
        for_each(begin(workers_), end(workers_), [&] (std::thread &t)
                {
                    try
                    {
                        t.join();
                    }
                    catch (std::exception const &e)
                    {
                        utility::handle_error<exception::server>(error_handler_, e,
                                "[nanorpc::http::server::stop] ",
                                "Failed to stop server.");

                        std::exit(EXIT_FAILURE);
                    }
                }
            );

        workers_.clear();
    }

    bool stopped() const noexcept
    {
        return !listener_;
    }

protected:
    using session_ptr = listener::session_ptr;

    virtual session_ptr make_session(boost::asio::ip::tcp::socket socket,
            core::type::executor_map const &executors,
            core::type::error_handler const &error_handler) = 0;

private:
    using threads_type = std::vector<std::thread>;

    core::type::executor_map executors_;
    core::type::error_handler error_handler_;

    int workers_count_;
    boost::asio::io_context context_;
    boost::asio::ip::tcp::endpoint endpoint_;
    std::shared_ptr<listener> listener_;
    threads_type workers_;
};

}   // namespace
}   // namespace detail

class server::impl final
    : public detail::server
{
public:
    using server::server;

private:
    virtual session_ptr make_session(boost::asio::ip::tcp::socket socket,
            core::type::executor_map const &executors,
            core::type::error_handler const &error_handler) override final
    {
        return std::make_shared<session>(std::move(socket), executors, error_handler);
    }

    class session final
        : public detail::session
    {
    public:
        using detail::session::session;

    private:
        virtual void handshake(on_completed_func on_handshake) override final
        {
            on_handshake(boost::system::error_code{});
        }

        virtual void close(boost::system::error_code &ec) override final
        {
            get_socket().shutdown(boost::asio::ip::tcp::socket::shutdown_send, ec);
        }

        virtual void read(buffer_ptr buffer, request_ptr request, on_completed_func on_read) override final
        {
            boost::beast::http::async_read(get_socket(), *buffer, *request,
                    boost::asio::bind_executor(get_strand(),
                            [func = std::move(on_read), buffer, request]
                            (boost::system::error_code const &ec, auto)
                            { func(ec); }
                        )
                    );
        }

        virtual void write(response_ptr response, on_completed_func on_write) override final
        {
            boost::beast::http::async_write(get_socket(), *response,
                    boost::asio::bind_executor(get_strand(),
                            [func = std::move(on_write), response]
                            (boost::system::error_code const &ec, auto) { func(ec); }
                        )
                );
        }
    };
};

server::server(std::string_view address, std::string_view port, std::size_t workers,
        core::type::executor_map executors, core::type::error_handler error_handler)
    : impl_{std::make_shared<impl>(std::move(address), std::move(port), workers,
            std::move(executors), std::move(error_handler))}
{
}

server::~server() noexcept
{
}

void server::run()
{
    impl_->run();
}

void server::stop()
{
    impl_->stop();
}

bool server::stopped() const noexcept
{
    return impl_->stopped();
}

}   // namespace nanorpc::http

#ifdef NANORPC_WITH_SSL

namespace nanorpc::https
{

class server::impl final
    : public http::detail::server
{
public:
    impl(boost::asio::ssl::context ssl_context, std::string_view address, std::string_view port,
            std::size_t workers, core::type::executor_map executors, core::type::error_handler error_handler)
        : server{std::move(address), std::move(port), workers, std::map(executors), std::move(error_handler)}
        , ssl_context_{std::move(ssl_context)}
    {
    }

private:
    boost::asio::ssl::context ssl_context_;

    virtual session_ptr make_session(boost::asio::ip::tcp::socket socket,
            core::type::executor_map const &executors,
            core::type::error_handler const &error_handler) override final
    {
        return std::make_shared<session>(ssl_context_, std::move(socket), executors, error_handler);
    }

    class session final
        : public http::detail::session
    {
    public:
        session(boost::asio::ssl::context &ssl_context, boost::asio::ip::tcp::socket socket,
                core::type::executor_map const &executors, core::type::error_handler const &error_handler)
            : http::detail::session{std::move(socket), executors, error_handler}
            , stream_{std::in_place, get_socket(), ssl_context}
        {
        }

        virtual ~session() noexcept override
        {
            stream_.reset();
        }

    private:
        std::optional<boost::asio::ssl::stream<boost::asio::ip::tcp::socket&>> stream_;

        virtual void handshake(on_completed_func on_handshake) override final
        {
            stream_->async_handshake(boost::asio::ssl::stream_base::server, boost::asio::bind_executor(get_strand(),
                    [func = std::move(on_handshake)] (boost::system::error_code const &ec) { func(ec); } ));
        }

        virtual void close(boost::system::error_code &ec) override final
        {
            boost::ignore_unused(ec);
            stream_->async_shutdown([] (boost::system::error_code const &ec)
                    { boost::ignore_unused(ec); } );
        }

        virtual void read(buffer_ptr buffer, request_ptr request, on_completed_func on_read) override final
        {
            boost::beast::http::async_read(*stream_, *buffer, *request,
                    boost::asio::bind_executor(get_strand(),
                            [func = std::move(on_read), buffer, request]
                            (boost::system::error_code const &ec, auto)
                            { func(ec); }
                        )
                    );
        }

        virtual void write(response_ptr response, on_completed_func on_write) override final
        {
            boost::beast::http::async_write(*stream_, *response,
                    boost::asio::bind_executor(get_strand(),
                            [func = std::move(on_write), response]
                            (boost::system::error_code const &ec, auto) { func(ec); }
                        )
                );
        }
    };
};

server::server(boost::asio::ssl::context context, std::string_view address, std::string_view port,
        std::size_t workers, core::type::executor_map executors, core::type::error_handler error_handler)
    : impl_{std::make_shared<impl>(std::move(context), std::move(address), std::move(port),
            workers, std::move(executors), std::move(error_handler))}
{
}

server::~server() noexcept
{
}

void server::run()
{
    impl_->run();
}

void server::stop()
{
    impl_->stop();
}

bool server::stopped() const noexcept
{
    return impl_->stopped();
}

}   // namespace nanorpc::https

#endif  // !NANORPC_WITH_SSL

ext: cpp

max_stars_repo_name: kondratyev-nv/nanorpc

max_issues_repo_name: kondratyev-nv/nanorpc

max_forks_repo_name: kondratyev-nv/nanorpc


text:
/*
 * ElevationMap.hpp
 *
 *  Created on: Feb 5, 2014
 *      Author: Péter Fankhauser
 *	 Institute: ETH Zurich, ANYbotics
 */

#pragma once

// Grid Map
#include <grid_map_ros/grid_map_ros.hpp>
#include <grid_map_pcl/grid_map_pcl.hpp>

// Eigen
#include <Eigen/Core>
#include <Eigen/Geometry>

// Kindr
#include <kindr/Core>

// Boost
#include <boost/thread/recursive_mutex.hpp>

// ROS
#include <ros/ros.h>

// Elevation Mapping
#include "elevation_mapping/PointXYZRGBConfidenceRatio.hpp"
#include "elevation_mapping/postprocessing/PostprocessorPool.hpp"

namespace elevation_mapping {

/*!
 * Elevation map stored as grid map handling elevation height, variance, color etc.
 */
class ElevationMap {
 public:
  /*!
   * Constructor.
   */
  explicit ElevationMap(ros::NodeHandle nodeHandle);

  /*!
   * Destructor.
   */
  virtual ~ElevationMap();

  /*!
   * Set the geometry of the elevation map. Clears all the data.
   * @param length the side lengths in x, and y-direction of the elevation map [m].
   * @param resolution the cell size in [m/cell].
   * @param position the 2d position of the elevation map in the elevation map frame [m].
   * @return true if successful.
   */
  void setGeometry(const grid_map::Length& length, const double& resolution, const grid_map::Position& position);

  /*!
   * Add new measurements to the elevation map.
   * @param pointCloud the point cloud data.
   * @param pointCloudVariances the corresponding variances of the point cloud data.
   * @param timeStamp the time of the input point cloud.
   * @param transformationSensorToMap
   * @return true if successful.
   */
  bool add(const PointCloudType::Ptr pointCloud, Eigen::VectorXf& pointCloudVariances, const ros::Time& timeStamp,
           const Eigen::Affine3d& transformationSensorToMap);

  /*!
   * Update the elevation map with variance update data.
   * @param varianceUpdate the variance update in vertical direction.
   * @param horizontalVarianceUpdateX the variance update in horizontal x-direction.
   * @param horizontalVarianceUpdateY the variance update in horizontal y-direction.
   * @param horizontalVarianceUpdateXY the correlated variance update in horizontal xy-direction.
   * @param time the time of the update.
   * @return true if successful.
   */
  bool update(const grid_map::Matrix& varianceUpdate, const grid_map::Matrix& horizontalVarianceUpdateX,
              const grid_map::Matrix& horizontalVarianceUpdateY, const grid_map::Matrix& horizontalVarianceUpdateXY, const ros::Time& time);

  /*!
   * Triggers the fusion of the entire elevation map.
   * @return true if successful.
   */
  bool fuseAll();

  /*!
   * Fuses the elevation map for a certain rectangular area.
   * @param position the center position of the area to fuse.
   * @param length the sides lengths of the area to fuse.
   * @return true if successful.
   */
  bool fuseArea(const Eigen::Vector2d& position, const Eigen::Array2d& length);

  /*!
   * Clears all data of the elevation map (data and time).
   * @return true if successful.
   */
  bool clear();

  /*!
   * Removes parts of the map based on visibility criterion with ray tracing.
   * @param transformationSensorToMap
   * @param updatedTime
   */
  void visibilityCleanup(const ros::Time& updatedTime);

  /*!
   * Move the grid map w.r.t. to the grid map frame.
   * @param position the new location of the elevation map in the map frame.
   */
  void move(const Eigen::Vector2d& position);

  /*!
   * Publishes the (latest) raw elevation map. Optionally, if a postprocessing pipeline was configured,
   * the map is postprocessed before publishing.
   * @return true if successful.
   */
  // TODO (magnus) rename? E.g. adapt for postprocessing structure.
  bool publishRawElevationMap();

  /*!
   * Publishes the fused elevation map. Takes the latest available fused elevation
   * map, does not trigger the fusion process.
   * @return true if successful.
   */
  bool publishFusedElevationMap();

  /*!
   * Publishes the (latest) visibility cleanup map.
   * @return true if successful.
   */
  bool publishVisibilityCleanupMap();

  /*!
   * Gets a reference to the raw grid map.
   * @return the raw grid map.
   */
  grid_map::GridMap& getRawGridMap();

  /*!
   * Sets a raw grid map.
   * @param map The input raw grid map to set.
   */
  void setRawGridMap(const grid_map::GridMap& map);

  /*!
   * Gets a reference to the fused grid map.
   * @return the fused grid map.
   */
  grid_map::GridMap& getFusedGridMap();

  /*!
   * Sets a fused grid map.
   * @param map The input fused grid map to set.
   */
  void setFusedGridMap(const grid_map::GridMap& map);

  /*!
   * Gets the time of last map update.
   * @return time of the last map update.
   */
  ros::Time getTimeOfLastUpdate();

  /*!
   * Gets the time of last map fusion.
   * @return time of the last map fusion.
   */
  ros::Time getTimeOfLastFusion();

  /*!
   * Get the pose of the elevation map frame w.r.t. the inertial parent frame of the robot (e.g. world, map etc.).
   * @return pose of the elevation map frame w.r.t. the parent frame of the robot.
   */
  const kindr::HomTransformQuatD& getPose();

  /*!
   * Gets the position of a raw data point (x, y of cell position & height of cell value) in
   * the parent frame of the robot.
   * @param index the index of the requested cell.
   * @param position the position of the data point in the parent frame of the robot.
   * @return true if successful, false if no valid data available.
   */
  bool getPosition3dInRobotParentFrame(const Eigen::Array2i& index, kindr::Position3D& position);

  /*!
   * Gets the fused data mutex.
   * @return reference to the fused data mutex.
   */
  boost::recursive_mutex& getFusedDataMutex();

  /*!
   * Gets the raw data mutex.
   * @return reference to the raw data mutex.
   */
  boost::recursive_mutex& getRawDataMutex();

  /*!
   * Set the frame id.
   * @param frameId the frame id.
   */
  void setFrameId(const std::string& frameId);

  /*!
   * Get the frame id.
   * @return the frameId.
   */
  const std::string& getFrameId();

  /*!
   * Set the timestamp of the raw and fused elevation map.
   * @param timestmap to set.
   */
  void setTimestamp(ros::Time timestamp);

  /*!
   * If the raw elevation map has subscribers.
   * @return true if number of subscribers bigger then 0.
   */
  bool hasRawMapSubscribers() const;

  /*!
   * If the fused elevation map has subscribers.
   * @return true if number of subscribers bigger then 0.
   */
  bool hasFusedMapSubscribers() const;

  /*!
   * Callback method for the updates of the underlying map.
   * Updates the internal underlying map.
   * @param underlyingMap the underlying map.
   */
  void underlyingMapCallback(const grid_map_msgs::GridMap& underlyingMap);

  /*!
   * Method to set the height value around the center of the robot, can be used for initialization.
   * @param initPosition Position to calculate inner rectangle.
   * @param mapHeight The height that gets set uniformly.
   * @param lengthInXSubmap Length of the submap in X direction.
   * @param lengthInYSubmap Length of the submap in Y direction.
   * @param margin Extra margin that gets added to the submap boundaries.
   */
  void setRawSubmapHeight(const grid_map::Position& initPosition, float mapHeight, double lengthInXSubmap, double lengthInYSubmap,
                          double margin);

  friend class ElevationMapping;

 private:
  /*!
   * Fuses a region of the map.
   * @param topLeftIndex the top left index of the region.
   * @param size the size (in number of cells) of the region.
   * @return true if successful.
   */
  bool fuse(const grid_map::Index& topLeftIndex, const grid_map::Index& size);

  /*!
   * Cleans the elevation map data to stay within the specified bounds.
   * @return true if successful.
   */
  bool clean();

  /*!
   * Resets the fused map data.
   * @return true if successful.
   */
  void resetFusedData();

  /*!
   * Cumulative distribution function.
   * @param x the argument value.
   * @param mean the mean of the distribution.
   * @param standardDeviation the standardDeviation of the distribution.
   * @return the function value.
   */
  float cumulativeDistributionFunction(float x, float mean, float standardDeviation);

  //! ROS nodehandle.
  ros::NodeHandle nodeHandle_;

  //! Raw elevation map as grid map.
  grid_map::GridMap rawMap_;

  //! Fused elevation map as grid map.
  grid_map::GridMap fusedMap_;

  //! Visibility cleanup debug map.
  grid_map::GridMap visibilityCleanupMap_;

  //! Underlying map, used for ground truth maps, multi-robot mapping etc.
  grid_map::GridMap underlyingMap_;

  //! Thread Pool to handle raw map postprocessing filter pipelines.
  PostprocessorPool postprocessorPool_;

  //! True if underlying map has been set, false otherwise.
  bool hasUnderlyingMap_;

  //! Pose of the elevation map frame w.r.t. the inertial parent frame of the robot (e.g. world, map etc.).
  kindr::HomTransformQuatD pose_;

  //! ROS publishers. Publishing of the raw elevation map is handled by the postprocessing pool.
  ros::Publisher elevationMapFusedPublisher_;
  ros::Publisher elevationMapFusedPublisher_pcl_;
  ros::Publisher visibilityCleanupMapPublisher_;

  //! Mutex lock for fused map.
  boost::recursive_mutex fusedMapMutex_;

  //! Mutex lock for raw map.
  boost::recursive_mutex rawMapMutex_;

  //! Mutex lock for visibility cleanup map.
  boost::recursive_mutex visibilityCleanupMapMutex_;

  //! Underlying map subscriber.
  ros::Subscriber underlyingMapSubscriber_;

  //! Initial ros time
  ros::Time initialTime_;

  //! Parameters. Are set through the ElevationMapping class.
  double minVariance_;
  double maxVariance_;
  double mahalanobisDistanceThreshold_;
  double multiHeightNoise_;
  double minHorizontalVariance_;
  double maxHorizontalVariance_;
  std::string underlyingMapTopic_;
  bool enableVisibilityCleanup_;
  bool enableContinuousCleanup_;
  double visibilityCleanupDuration_;
  double scanningDuration_;
};

}  // namespace elevation_mapping


text:
#include "stdafx.h"
#include <boost/format.hpp>
#include <vosvideocommon/ComHelper.h>
#include <vosvideocommon/StringUtil.h>
#include <vosvideocommon/NativeErrorsManager.h>
#include <Codecapi.h>
#include "NetCredentialManager.h"
#include "MfTopologyHelper.h"
#include "IpCameraTopology.h"

using namespace std;
using namespace util;
using namespace concurrency;
using boost::wformat;
using namespace vosvideo::cameraplayer;
using namespace vosvideo::data;

IpCameraTopology::IpCameraTopology()
{
}

IpCameraTopology::~IpCameraTopology()
{
}

HRESULT IpCameraTopology::RenderUrlAsync(const CameraConfMsg& conf, boost::signals2::signal<void(HRESULT, shared_ptr<SendData>)>::slot_function_type subscriber)
{
	conf_ = conf;
	openCompletedSignal_.connect(subscriber);

	wstring audiouri;
	wstring videouri;
	conf_.GetUris(audiouri, videouri);

	wstring username, pass;
	conf_.GetCredentials(username, pass);

	HRESULT hr = CreateMediaSource(videouri, username, pass);

	return hr;
}

HRESULT IpCameraTopology::CreateMediaSource(wstring& sURL, wstring& username, wstring& pass)
{
	HRESULT hr = S_OK;
	MF_OBJECT_TYPE objectType = MF_OBJECT_INVALID;

	do
	{
		// Create the source resolver.
		if (pSourceResolver_ == nullptr)
		{
			hr = MFCreateSourceResolver(&pSourceResolver_);
			BREAK_ON_FAIL(hr);
		}

		CComPtr<IPropertyStore> pPropStore;
		NetCredentialManager *pCredentials = new (std::nothrow) NetCredentialManager(username, pass);
		// Configure the property store.
		hr = PSCreateMemoryPropertyStore(IID_PPV_ARGS(&pPropStore));
		if (SUCCEEDED(hr))
		{
			PROPERTYKEY key;
			key.fmtid =  MFNETSOURCE_CREDENTIAL_MANAGER;
			key.pid = 0;

			PROPVARIANT var;
			var.vt = VT_UNKNOWN;
			pCredentials->QueryInterface(IID_PPV_ARGS(&var.punkVal));

			hr = pPropStore->SetValue(key, var);

			PropVariantClear(&var);
		}

		CComPtr<IUnknown> pCancelCookie;
		LOG_TRACE("Try to open URL: " << StringUtil::ToString(sURL));

		hr = pSourceResolver_->BeginCreateObjectFromURL(
			sURL.c_str(),               // URL of the source.
			MF_RESOLUTION_MEDIASOURCE |
			MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE,
			pPropStore,                 // Optional property store for extra parameters
			&pCancelCookie,
			this,
			NULL);
		BREAK_ON_FAIL(hr);

		pCancelCookie_ = pCancelCookie.Detach();

		// Open source cancellation, PPL async timer executes Cancel routine after timeout
		auto callback = new call<CameraTopology*>([this](CameraTopology*)
		{
			// If after 5 sec camera source was not created cancel it
			if (this->pSource_ == nullptr)
			{
				int cameraId = -1;
				wstring cameraName;
				conf_.GetCameraIds(cameraId, cameraName);
				wstring errMsg = str(wformat(L"Timeout %1% ms for camera %2%. Cancel connection creation.") % openConnTimeout_ % cameraName);
				LOG_ERROR(StringUtil::ToString(errMsg));
				HRESULT hr = this->pSourceResolver_->CancelObjectCreation(this->pCancelCookie_);
				LOG_DEBUG("CancelObjectCreation returned HR=" << hr);
			}
		});
		// Connect the timer to the callback and start the timer.
		fireCancelTimer_ = new Concurrency::timer<CameraTopology*>(openConnTimeout_, 0, nullptr, false);
		fireCancelTimer_->link_target(callback);
		fireCancelTimer_->start();
	}
	while(false);

	return hr;
}

HRESULT IpCameraTopology::Invoke(IMFAsyncResult* pAsyncResult)
{
	HRESULT hr = S_OK;
	shared_ptr<RtbcDeviceErrorOutMsg> errMsg;
	MF_OBJECT_TYPE objType;

	// In case error will use this info
	int cameraId;
	wstring cameraName;
	wstring failedComponent;
	conf_.GetCameraIds(cameraId, cameraName);

	do
	{
		CComPtr<IUnknown> pSource;
		hr = pSourceResolver_->EndCreateObjectFromURL(pAsyncResult, &objType, &pSource);
		// Get the IMFMediaSource interface from the media source.
		pSource_ = pSource.Detach();

		if (hr != S_OK || pSource_ == nullptr)
		{
			// Too generic, here is timeout I know for sure
			if (hr == E_ABORT)
			{
				hr = WAIT_TIMEOUT;
			}
			break;
		}

		if (conf_.GetVideoFormat() == CameraVideoFormat::MPEG4)
		{
			hr = MfTopologyHelper::CreateMpeg4Decoder(&pDecoder_);
			if (hr != S_OK)
			{
				failedComponent = L"Failed to create Mpeg4 decoder.";
			}
			BREAK_ON_FAIL(hr);
		}
		else if (conf_.GetVideoFormat() == CameraVideoFormat::MJPEG)
		{
			hr = MfTopologyHelper::CreateMjpegDecoder(&pDecoder_);
			if (hr != S_OK)
			{
				failedComponent = L"Failed to create MJPEG decoder.";
			}
			BREAK_ON_FAIL(hr);
		}
		else if (conf_.GetVideoFormat() == CameraVideoFormat::H264)
		{
			hr = MfTopologyHelper::CreateH264Decoder(&pDecoder_);
			if (hr != S_OK)
			{
				failedComponent = L"Failed to create h264 decoder.";
			}
			// Make sure that acceleration is ON
			CComPtr<IMFAttributes> attr;
			pDecoder_->GetAttributes(&attr);
			hr = attr->SetUINT32(CODECAPI_AVDecVideoAcceleration_H264, TRUE);
			BREAK_ON_FAIL(hr);
		}
		else
		{
			hr = S_FALSE;
			break;
		}

		hr = MfTopologyHelper::NegotiateSourceToMft(pSource_, pDecoder_);
		BREAK_ON_FAIL(hr);

		hr = MfTopologyHelper::CreateVP8Encoder(&pVP8Encoder_);
		if (hr != S_OK)
		{
			failedComponent = L"Failed to create VP8 encoder.";
		}
		BREAK_ON_FAIL(hr);

		hr = MfTopologyHelper::CreateYuYtoI420ColorTransf(&pYuYtoI420_);
		if (hr != S_OK)
		{
			failedComponent = L"Failed to create color transformer.";
		}
		BREAK_ON_FAIL(hr);

		hr = MfTopologyHelper::NegotiateYUY2ToI420(pDecoder_, pYuYtoI420_);
		BREAK_ON_FAIL(hr);

		hr = MfTopologyHelper::NegotiateMftToVP8(pYuYtoI420_, pVP8Encoder_, webRtcCapability_);
		BREAK_ON_FAIL(hr);

		wstring outFolder;
		uint32_t recordLen;
		CameraVideoRecording recordingType;
		conf_.GetFileSinkParameters(outFolder, recordLen, recordingType);

		if (recordingType != CameraVideoRecording::DISABLED)
		{
			hr = MfTopologyHelper::CreateVP8FileSink(&pVP8FileSink_);
			if (hr != S_OK)
			{
				failedComponent = L"Failed to create VP8 file sink.";
			}
			BREAK_ON_FAIL(hr);

			if (hr = SetFileSinkParameters(conf_) != S_OK)
			{
				if (hr != S_OK)
				{
					failedComponent = L"Failed to set file sink parameters.";
				}
				BREAK_ON_FAIL(hr);
			}
		}

		hr = MfTopologyHelper::CreateVP8CallbackSink(&pVP8CallbackSink_);
		if (hr != S_OK)
		{
			failedComponent = L"Failed to create VP8 callback sink.";
		}
		BREAK_ON_FAIL(hr);

		hr = CreateTopology(recordingType);

		if (hr == S_OK)
		{
			LOG_TRACE("Successfully created Media Foundation topology for IP Camera: " << StringUtil::ToString(cameraName));
		}
	}
	while(false);

	if (hr != S_OK)
	{
		wstring nativeErrMsg = NativeErrorsManager::ToString(hr);
		wstring msg = str(wformat(L"Failed to create media source for camera named: %1%. %2% %3%") % cameraName % failedComponent % nativeErrMsg);
		errMsg.reset(new RtbcDeviceErrorOutMsg(cameraId, msg, hr));
		LOG_ERROR(StringUtil::ToString(msg));
	}

	// Notify player that we are done
	openCompletedSignal_(hr, errMsg);

	SetEvent(invokeCompleteEvent_);
	return hr;
}

//
//  Creates a playback topology from the media source by extracting presentation
//  and stream descriptors from the source, and creating a sink for each of them.
//
HRESULT IpCameraTopology::CreateTopology(CameraVideoRecording recordingType)
{
	HRESULT hr = S_OK;
	CComQIPtr<IMFPresentationDescriptor> pPresDescriptor;
	DWORD nSourceStreams = 0;

	do
	{
		// release the old topology if there was one
		pTopology_.Release();

		// Create a new topology.
		hr = MFCreateTopology(&pTopology_);
		BREAK_ON_FAIL(hr);

		// Create the presentation descriptor for the media source - a container object that
		// holds a list of the streams and allows selection of streams that will be used.
		hr = pSource_->CreatePresentationDescriptor(&pPresDescriptor);
		BREAK_ON_FAIL(hr);

		// Get the number of streams in the media source
		hr = pPresDescriptor->GetStreamDescriptorCount(&nSourceStreams);
		BREAK_ON_FAIL(hr);

		// Get the stream descriptor for this stream (information about stream).
		BOOL streamSelected = FALSE;
		CComPtr<IMFStreamDescriptor> pStreamDescriptor;
		hr = pPresDescriptor->GetStreamDescriptorByIndex(0, &streamSelected, &pStreamDescriptor);
		BREAK_ON_FAIL(hr);
		CComPtr<IMFTopologyNode> pSourceNode;
		hr = MfTopologyHelper::CreateSourceStreamNode(pSource_, pPresDescriptor, pStreamDescriptor, pSourceNode);
		BREAK_ON_FAIL(hr);
		pTopology_->AddNode(pSourceNode);

		// Create node for MJPEG/MPEG4/H264 decoder
		CComPtr<IMFTopologyNode> pDecoderNode;
		hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &pDecoderNode);
		BREAK_ON_FAIL(hr);
		// set the output stream ID on the stream sink topology node
		hr = pDecoderNode->SetObject(pDecoder_);
		BREAK_ON_FAIL(hr);
		pTopology_->AddNode(pDecoderNode);

		// Create node for color converter
		CComPtr<IMFTopologyNode> pYuYtoI420Node;
		hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &pYuYtoI420Node);
		BREAK_ON_FAIL(hr);
		// set the output stream ID on the stream sink topology node
		hr = pYuYtoI420Node->SetObject(pYuYtoI420_);
		BREAK_ON_FAIL(hr);
		pTopology_->AddNode(pYuYtoI420Node);

		// Create node for VP8 encoder
		CComPtr<IMFTopologyNode> pEncoderNode;
		hr = MFCreateTopologyNode(MF_TOPOLOGY_TRANSFORM_NODE, &pEncoderNode);
		BREAK_ON_FAIL(hr);
		// set the output stream ID on the stream sink topology node
		hr = pEncoderNode->SetObject(pVP8Encoder_);
		BREAK_ON_FAIL(hr);
		pTopology_->AddNode(pEncoderNode);

		// Create the topology Tee node
		CComPtr<IMFTopologyNode> pTeeNode;
		hr = MFCreateTopologyNode(MF_TOPOLOGY_TEE_NODE, &pTeeNode);
		BREAK_ON_FAIL(hr);
		pTopology_->AddNode(pTeeNode);

		DWORD streamId = 0;
		// get the stream ID
		hr = pStreamDescriptor->GetStreamIdentifier(&streamId);
		BREAK_ON_FAIL(hr);

		// create the output topology node for one of the streams on the file sink
		CComPtr<IMFTopologyNode> pFileOutputNode;

		if (recordingType != CameraVideoRecording::DISABLED)
		{
			hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &pFileOutputNode);
			// set the output stream ID on the stream sink topology node
			hr = pFileOutputNode->SetUINT32(MF_TOPONODE_STREAMID, streamId);
			CComPtr<IMFStreamSink> pStream1;
			hr = pVP8FileSink_->GetStreamSinkById(0, &pStream1);
			BREAK_ON_FAIL(hr);
			hr = pFileOutputNode->SetObject(pStream1);
			BREAK_ON_FAIL(hr);
			// add the network output topology node to the topology
			pTopology_->AddNode(pFileOutputNode);
			BREAK_ON_FAIL(hr);
		}

		// create the output topology node for one of the streams on the callback sink
		CComPtr<IMFTopologyNode> pCallbackOutputNode;
		hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &pCallbackOutputNode);
		// set the output stream ID on the stream sink topology node
		hr = pCallbackOutputNode->SetUINT32(MF_TOPONODE_STREAMID, streamId);
		CComPtr<IMFStreamSink> pStream2;
		hr = pVP8CallbackSink_->GetStreamSinkById(0, &pStream2);
		BREAK_ON_FAIL(hr);
		hr = pCallbackOutputNode->SetObject(pStream2);
		BREAK_ON_FAIL(hr);
		// add the network output topology node to the topology
		pTopology_->AddNode(pCallbackOutputNode);
		BREAK_ON_FAIL(hr);

		// Connect components
		// CameraSource->MJPEG/MPEG4/H264 decoder
		pSourceNode->ConnectOutput(0, pDecoderNode, 0);
		// MPEG4 decoder -> YuYtoI420 color converter
		pDecoderNode->ConnectOutput(0, pYuYtoI420Node, 0);
		// I420 image to VP8 encoder
		pYuYtoI420Node->ConnectOutput(0, pEncoderNode, 0);
		// VP8 encoder -> TEE
		pEncoderNode->ConnectOutput(0, pTeeNode, 0);
		if (recordingType != CameraVideoRecording::DISABLED)
		{
			// TEE -> File sink
			pTeeNode->ConnectOutput(0, pFileOutputNode, 0);
			// TEE -> Callback sink
			pTeeNode->ConnectOutput(1, pCallbackOutputNode, 0);
		}
		else
		{
			// TEE -> Callback sink
			pTeeNode->ConnectOutput(0, pCallbackOutputNode, 0);
		}

		// Connect callback for remote requests
		SetFrameCallback();
	}
	while(false);

	return hr;
}

max_stars_repo_name: lcmftianci/licodeanalysis

max_issues_repo_name: lcmftianci/licodeanalysis

max_forks_repo_name: lcmftianci/licodeanalysis


text:
/// MIT License
///
/// Copyright (c) 2017 Arkadiusz Netczuk <dev.arnet@gmail.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 "ias/Analysis.h"

#include <boost/test/unit_test.hpp>

using namespace ias;

BOOST_AUTO_TEST_SUITE( AnalysisSuite )

    BOOST_AUTO_TEST_CASE( loadImage_not_found ) {
        Analysis object;

        const bool loaded = object.loadImage("not_found.png");
        BOOST_CHECK_EQUAL( loaded, false );
    }

    BOOST_AUTO_TEST_CASE( loadImage_valid ) {
        Analysis object;

        const bool loaded = object.loadImage("data/test1.png");
        BOOST_CHECK_EQUAL( loaded, true );
    }

    BOOST_AUTO_TEST_CASE( loadImage_corrupt ) {
        Analysis object;

        const bool loaded = object.loadImage("data/corrupt.png");
        BOOST_CHECK_EQUAL( loaded, false );
    }

    BOOST_AUTO_TEST_CASE( color_invalid ) {
        Analysis object;

        const cv::Vec3b color = object.color( 0, 0 );
        BOOST_CHECK_EQUAL( color, cv::Vec3b(0, 0, 0) );
    }

    BOOST_AUTO_TEST_CASE( color_valid ) {
        Analysis object;

        const bool loaded = object.loadImage("data/test1.png");
        BOOST_REQUIRE_EQUAL( loaded, true );

        const cv::Vec3b color1 = object.color( 45, 0 );
        BOOST_CHECK_EQUAL( color1, cv::Vec3b(0, 0, 255) );          /// red

        const cv::Vec3b color2 = object.color( 0, 45 );
        BOOST_CHECK_EQUAL( color2, cv::Vec3b(255, 255, 255) );      /// white
    }

    BOOST_AUTO_TEST_CASE( color_valid2 ) {
        Analysis object;

        const bool loaded = object.loadImage("data/test1.png");
        BOOST_REQUIRE_EQUAL( loaded, true );

        const cv::Vec3b color1 = object.color( cv::Point(0, 45) );
        BOOST_CHECK_EQUAL( color1, cv::Vec3b(0, 0, 255) );                  /// red

        const cv::Vec3b color2 = object.color( cv::Point(45, 0) );
        BOOST_CHECK_EQUAL( color2, cv::Vec3b(255, 255, 255) );              /// white
    }

    BOOST_AUTO_TEST_CASE( findRegion_invalid ) {
        Analysis object;

        object.findRegion( cv::Point(0, 0), cv::Vec3b(255, 0, 0) );
        const cv::Mat& region = object.result();
        BOOST_CHECK_EQUAL( region.empty(), true );
    }

    BOOST_AUTO_TEST_CASE( findRegion_valid ) {
        Analysis object;

        const bool loaded = object.loadImage("data/test1.png");
        BOOST_REQUIRE_EQUAL( loaded, true );

        const cv::Point point(0, 30);
        const cv::Vec3b color(0, 0, 255);
        object.findRegion( point, color, 20 );

        const cv::Mat& region = object.result();
        BOOST_REQUIRE_EQUAL( region.empty(), false );
        BOOST_CHECK_EQUAL( region.channels(), 1 );
        BOOST_CHECK_EQUAL( region.rows, object.image().rows );
        BOOST_CHECK_EQUAL( region.cols, object.image().cols );

        BOOST_CHECK_EQUAL( region.at<uchar>(0, 0), 0 );          /// green RGB(5, 249, 37) background
        BOOST_CHECK_EQUAL( region.at<uchar>(40, 10), 255 );      /// first red RGB(249, 37, 7) rectangle
        BOOST_CHECK_EQUAL( region.at<uchar>(50, 100), 0 );       /// second red rectangle
    }

    BOOST_AUTO_TEST_CASE( findRegion_valid2 ) {
        Analysis object;

        const bool loaded = object.loadImage("data/test1.png");
        BOOST_REQUIRE_EQUAL( loaded, true );

        const cv::Point point(200, 200);
        const cv::Vec3b color(0, 0, 255);
        object.findRegion( point, color, 20 );

        const cv::Mat& region = object.result();
        BOOST_REQUIRE_EQUAL( region.empty(), false );
        BOOST_CHECK_EQUAL( region.channels(), 1 );
        BOOST_CHECK_EQUAL( region.rows, object.image().rows );
        BOOST_CHECK_EQUAL( region.cols, object.image().cols );

        BOOST_CHECK_EQUAL( region.at<uchar>(0, 0), 0 );             /// white RGB(255, 255, 255) background
        BOOST_CHECK_EQUAL( region.at<uchar>(40, 10), 0 );           /// first red RGB(255, 0, 0) rectangle
        BOOST_CHECK_EQUAL( region.at<uchar>(220, 220), 255 );       /// second red rectangle
    }

    BOOST_AUTO_TEST_CASE( findPerimeter_invalid_image ) {
        Analysis object;

        const cv::Mat region;
        object.findPerimeter( region );

        const cv::Mat& perimeter = object.result();
        BOOST_CHECK_EQUAL( perimeter.empty(), true );
    }

    BOOST_AUTO_TEST_CASE( findPerimeter_empty_region ) {
        Analysis object;

        const bool loaded = object.loadImage("data/test1.png");
        BOOST_REQUIRE_EQUAL( loaded, true );

        const cv::Mat region;
        object.findPerimeter( region );

        const cv::Mat& perimeter = object.result();
        BOOST_CHECK_EQUAL( perimeter.empty(), true );
    }

    BOOST_AUTO_TEST_CASE( findPerimeter_region_bad_size ) {
        Analysis object;

        const bool loaded = object.loadImage("data/test1.png");
        BOOST_REQUIRE_EQUAL( loaded, true );

        const cv::Mat region( 10, 10, CV_8UC1 );
        object.findPerimeter( region );

        const cv::Mat& perimeter = object.result();
        BOOST_CHECK_EQUAL( perimeter.empty(), true );
    }

    BOOST_AUTO_TEST_CASE( findPerimeter_valid ) {
        Analysis object;

        const bool loaded = object.loadImage("data/test1.png");
        BOOST_REQUIRE_EQUAL( loaded, true );

        object.findRegion( cv::Point(0, 30), cv::Vec3b(0, 0, 255), 20 );
        const cv::Mat& region = object.result();
        object.findPerimeter( region );

        const cv::Mat& perimeter = object.result();
        BOOST_REQUIRE_EQUAL( perimeter.empty(), false );
        BOOST_CHECK_EQUAL( perimeter.channels(), 1 );
        BOOST_CHECK_EQUAL( perimeter.rows, object.image().rows );
        BOOST_CHECK_EQUAL( perimeter.cols, object.image().cols );

        BOOST_CHECK_EQUAL( perimeter.at<uchar>(0, 0), 0 );         /// green RGB(5, 249, 37) background
        BOOST_CHECK_EQUAL( perimeter.at<uchar>(30, 0), 255 );      /// red RGB(249, 37, 7) rectangle
    }

    BOOST_AUTO_TEST_CASE( findPerimeter_valid2 ) {
        Analysis object;

        const bool loaded = object.loadImage("data/test1.png");
        BOOST_REQUIRE_EQUAL( loaded, true );

        const cv::Point point(100, 50);
        const cv::Vec3b color(7, 37, 249);
        object.findRegion( point, color, 20 );
        const cv::Mat& region = object.result();
        object.findPerimeter( region );

        const cv::Mat& perimeter = object.result();
        BOOST_REQUIRE_EQUAL( perimeter.empty(), false );
        BOOST_CHECK_EQUAL( perimeter.channels(), 1 );
        BOOST_CHECK_EQUAL( perimeter.rows, object.image().rows );
        BOOST_CHECK_EQUAL( perimeter.cols, object.image().cols );

        BOOST_CHECK_EQUAL( perimeter.at<uchar>(0, 0), 0 );         /// green RGB(5, 249, 37) background
        BOOST_CHECK_EQUAL( perimeter.at<uchar>(30, 0), 0 );        /// red RGB(249, 37, 7) rectangle
    }

    BOOST_AUTO_TEST_CASE( findSmoothPerimeter_invalid_image ) {
        Analysis object;

        const cv::Mat region;
        object.findSmoothPerimeter( region );

        const cv::Mat& perimeter = object.result();
        BOOST_CHECK_EQUAL( perimeter.empty(), true );
    }

    BOOST_AUTO_TEST_CASE( findSmoothPerimeter_empty_region ) {
        Analysis object;

        const bool loaded = object.loadImage("data/test1.png");
        BOOST_REQUIRE_EQUAL( loaded, true );

        const cv::Mat region;
        object.findSmoothPerimeter( region );

        const cv::Mat& perimeter = object.result();
        BOOST_CHECK_EQUAL( perimeter.empty(), true );
    }

    BOOST_AUTO_TEST_CASE( findSmoothPerimeter_region_bad_size ) {
        Analysis object;

        const bool loaded = object.loadImage("data/test1.png");
        BOOST_REQUIRE_EQUAL( loaded, true );

        const cv::Mat region( 10, 10, CV_8UC1 );
        object.findSmoothPerimeter( region );

        const cv::Mat& perimeter = object.result();
        BOOST_CHECK_EQUAL( perimeter.empty(), true );
    }

    BOOST_AUTO_TEST_CASE( findSmoothPerimeter_valid ) {
        Analysis object;

        const bool loaded = object.loadImage("data/test1.png");
        BOOST_REQUIRE_EQUAL( loaded, true );

        object.findRegion( cv::Point(0, 30), cv::Vec3b(7, 37, 249), 20 );
        const cv::Mat& region = object.result();
        object.findPerimeter( region );

        const cv::Mat& perimeter = object.result();
        BOOST_REQUIRE_EQUAL( perimeter.empty(), false );
//        BOOST_CHECK_EQUAL( perimeter.channels(), 1 );
//        BOOST_CHECK_EQUAL( perimeter.rows, object.image().rows );
//        BOOST_CHECK_EQUAL( perimeter.cols, object.image().cols );
//
//        BOOST_CHECK_EQUAL( perimeter.at<uchar>(0, 0), 0 );         /// green RGB(5, 249, 37) background
//        BOOST_CHECK_EQUAL( perimeter.at<uchar>(30, 0), 255 );      /// red RGB(249, 37, 7) rectangle
    }

BOOST_AUTO_TEST_SUITE_END()

max_stars_repo_name: anetczuk/ImageProcessingService

max_issues_repo_name: anetczuk/ImageProcessingService

max_forks_repo_name: anetczuk/ImageProcessingService


text:
#include "cmake_project/test/fixtures/cprj_test_includes_parser_fixture.hpp"

#include <boost/test/unit_test.hpp>

#include <string>

/*------------------------------------------------------------------------------

TEST PLAN
1. Without include parameter
2. Parameter in name
3. One parameter
4. Several parameters
5. Parameter in end of string
6. File name with space
7. Include with space
8. Double spaces

------------------------------------------------------------------------------*/

namespace cmake_project::test
{
//------------------------------------------------------------------------------
// clazy:excludeall=non-pod-global-static
// NOLINTNEXTLINE(fuchsia-statically-constructed-objects,cert-err58-cpp)
BOOST_FIXTURE_TEST_SUITE( IncldesParserTests, IncldesParserFixture )

//------------------------------------------------------------------------------

// NOLINTNEXTLINE(fuchsia-statically-constructed-objects,cert-err58-cpp)
BOOST_AUTO_TEST_CASE( t1_without_include_paramter )
{
	// Run
	auto actualResult =
		parseString( "/usr/bin/c++ -o file2.cpp.o -c file2.cpp" );
	Strings exceptedResult{};

	// Check
	BOOST_CHECK_EQUAL_COLLECTIONS(
		actualResult.begin(), actualResult.end(), exceptedResult.begin(),
		exceptedResult.end() );
}

//------------------------------------------------------------------------------

// NOLINTNEXTLINE(fuchsia-statically-constructed-objects,cert-err58-cpp)
BOOST_AUTO_TEST_CASE( t2_paramter_in_name )
{
	// Run
	auto actualResult = parseString( "/bin/c++ -o f-I.cpp.o -c f-I.cpp" );
	Strings exceptedResult{};

	// Check
	BOOST_CHECK_EQUAL_COLLECTIONS(
		actualResult.begin(), actualResult.end(), exceptedResult.begin(),
		exceptedResult.end() );
}

//------------------------------------------------------------------------------

// NOLINTNEXTLINE(fuchsia-statically-constructed-objects,cert-err58-cpp)
BOOST_AUTO_TEST_CASE( t3_one_paramter )
{
	// Run
	auto actualResult =
		parseString( "/bin/c++ -o f.cpp.o -I./include -c f.cpp" );
	Strings exceptedResult = toPathStrings( { "./include" } );

	// Check
	BOOST_CHECK_EQUAL_COLLECTIONS(
		actualResult.begin(), actualResult.end(), exceptedResult.begin(),
		exceptedResult.end() );
}

//------------------------------------------------------------------------------

// NOLINTNEXTLINE(fuchsia-statically-constructed-objects,cert-err58-cpp)
BOOST_AUTO_TEST_CASE( t4_several_parameters )
{
	// Run
	auto actualResult =
		parseString( "/bin/c++ -o f.cpp.o -I./lib1 -I./lib2 -c f.cpp" );
	Strings exceptedResult = toPathStrings( { "./lib1", "./lib2" } );

	// Check
	BOOST_CHECK_EQUAL_COLLECTIONS(
		actualResult.begin(), actualResult.end(), exceptedResult.begin(),
		exceptedResult.end() );
}

//------------------------------------------------------------------------------

// NOLINTNEXTLINE(fuchsia-statically-constructed-objects,cert-err58-cpp)
BOOST_AUTO_TEST_CASE( t5_paramter_in_end_of_string )
{
	// Run
	auto actualResult =
		parseString( "/bin/c++ -o f.cpp.o -c f.cpp -I./include" );
	Strings exceptedResult = toPathStrings( { "./include" } );

	// Check
	BOOST_CHECK_EQUAL_COLLECTIONS(
		actualResult.begin(), actualResult.end(), exceptedResult.begin(),
		exceptedResult.end() );
}

//------------------------------------------------------------------------------

// NOLINTNEXTLINE(fuchsia-statically-constructed-objects,cert-err58-cpp)
BOOST_AUTO_TEST_CASE( t6_file_with_space )
{
	// Run
	auto actualResult =
		parseString( R"(/bin/c++ -o f.cpp.o -c \"space in file\".cpp)" );
	Strings exceptedResult;

	// Check
	BOOST_CHECK_EQUAL_COLLECTIONS(
		actualResult.begin(), actualResult.end(), exceptedResult.begin(),
		exceptedResult.end() );
}

//------------------------------------------------------------------------------

// NOLINTNEXTLINE(fuchsia-statically-constructed-objects,cert-err58-cpp)
BOOST_AUTO_TEST_CASE( t7_include_with_space )
{
	// Run
	auto actualResult = parseString(
		R"(/bin/c++ -o f.cpp.o -I\"./include with space\" -c f.cpp)" );
	Strings exceptedResult = toPathStrings( { "./include with space" } );

	// Check
	BOOST_CHECK_EQUAL_COLLECTIONS(
		actualResult.begin(), actualResult.end(), exceptedResult.begin(),
		exceptedResult.end() );
}

//------------------------------------------------------------------------------

// NOLINTNEXTLINE(fuchsia-statically-constructed-objects,cert-err58-cpp)
BOOST_AUTO_TEST_CASE( t8_double_spaces )
{
	// Run
	auto actualResult =
		parseString( "/bin/c++  -I./include -o f.cpp.o -c f.cpp" );
	Strings exceptedResult = toPathStrings( { "./include" } );

	// Check
	BOOST_CHECK_EQUAL_COLLECTIONS(
		actualResult.begin(), actualResult.end(), exceptedResult.begin(),
		exceptedResult.end() );
}

//------------------------------------------------------------------------------

// NOLINTNEXTLINE(fuchsia-statically-constructed-objects,cert-err58-cpp)
BOOST_AUTO_TEST_SUITE_END()

//------------------------------------------------------------------------------

}

max_stars_repo_name: lpea/cppinclude

max_issues_repo_name: lpea/cppinclude

max_forks_repo_name: lpea/cppinclude


text: #include <boost/metaparse/util/is_whitespace.hpp>

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino