Skip to content

Commit

Permalink
Encapsulate agent's instantiation in a singleton class. (#176)
Browse files Browse the repository at this point in the history
* Encapsulate agent instantiation. Fix some warnings

* Fix compilation for Windows.
  • Loading branch information
jamoralp authored Aug 4, 2020
1 parent ef12912 commit ac29889
Show file tree
Hide file tree
Showing 6 changed files with 303 additions and 144 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ endif()
# Set source files
set(SRCS
src/cpp/Agent.cpp
src/cpp/AgentInstance.cpp
src/cpp/Root.cpp
src/cpp/processor/Processor.cpp
src/cpp/client/ProxyClient.cpp
Expand Down
102 changes: 102 additions & 0 deletions include/uxr/agent/AgentInstance.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Copyright 2020 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// 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 UXR_AGENT_AGENT_INSTANCE_HPP_
#define UXR_AGENT_AGENT_INSTANCE_HPP_

#include <uxr/agent/config.hpp>

#ifdef UAGENT_CLI_PROFILE
#include <uxr/agent/utils/CLI.hpp>
#else
#include <uxr/agent/utils/ArgumentParser.hpp>
#endif // UAGENT_CLI_PROFILE

#include <csignal>

namespace eprosima {
namespace uxr {

/**
* @brief Singleton class to manage the launch process of a MicroXRCE-DDS Agent.
*/
class AgentInstance
{
public:
/**
* @brief Default constructor.
*/
UXR_AGENT_EXPORT AgentInstance();
/**
* @brief AgentInstance class shall not be copy constructible.
*/
UXR_AGENT_EXPORT AgentInstance(
const AgentInstance &) = delete;

UXR_AGENT_EXPORT AgentInstance(
AgentInstance &&) = delete;

/**
* @brief AgentInstance class shall not be copy assignable.
*/
UXR_AGENT_EXPORT AgentInstance& operator =(
const AgentInstance &) = delete;

UXR_AGENT_EXPORT AgentInstance& operator =(
AgentInstance &&) = delete;

/**
* @brief Get instance associated to this class.
* @return Static reference to the singleton AgentInstance object.
*/
UXR_AGENT_EXPORT static AgentInstance& getInstance();

/**
* @brief Create an Agent instance, based on provided input parameters from user.
* @param[in] argc Number of available parameters introduced by the user.
* @param[in] argv List of parameters to be parsed to instantiate an Agent.
* @return Boolean value indicating if a Micro XRCE-DDS Agent was instantiated successfully.
*/
UXR_AGENT_EXPORT bool create(
int argc,
char** argv);

/**
* @brief Run the created agent until finished via user interrupt or process error.
*/
UXR_AGENT_EXPORT void run();

private:
#ifdef UAGENT_CLI_PROFILE
CLI::App app_;
cli::UDPv4Subcommand udpv4_subcmd_;
cli::UDPv6Subcommand udpv6_subcmd_;
cli::TCPv4Subcommand tcpv4_subcmd_;
cli::TCPv6Subcommand tcpv6_subcmd_;
#ifndef _WIN32
cli::TermiosSubcommand termios_subcmd_;
cli::PseudoTerminalSubcommand pseudo_serial_subcmd_;
#endif // _WIN32
cli::ExitSubcommand exit_subcmd_;
#else
std::thread agent_thread_;
#endif // UAGENT_CLI_PROFILE
#ifndef _WIN32
sigset_t signals_;
#endif // _WIN32
};
} // uxr
} // eprosima

#endif // UXR_AGENT_AGENT_INSTANCE_HPP_
24 changes: 18 additions & 6 deletions include/uxr/agent/utils/ArgumentParser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ class Argument
int argc,
char** argv)
{
for (size_t position = 0; position < argc; ++position)
for (int position = 0; position < argc; ++position)
{
if (0 == strcmp(argv[position], short_alias_.c_str()) ||
0 == strcmp(argv[position], long_alias_.c_str()))
Expand Down Expand Up @@ -226,9 +226,9 @@ class Argument

private:
ArgumentKind argument_kind_;
T value_;
std::string short_alias_;
std::string long_alias_;
T value_;
bool parse_found_;
std::set<T> allowed_values_;
};
Expand Down Expand Up @@ -282,7 +282,7 @@ ParseResult parse_argument(
int argc,
char** argv)
{
for (size_t position = 0; position < argc; ++position)
for (int position = 0; position < argc; ++position)
{
if (0 == strcmp(argv[position], short_alias_.c_str()) ||
0 == strcmp(argv[position], long_alias_.c_str()))
Expand Down Expand Up @@ -346,9 +346,9 @@ ParseResult parse_argument(

private:
ArgumentKind argument_kind_;
std::string value_;
std::string short_alias_;
std::string long_alias_;
std::string value_;
bool parse_found_;
std::set<std::string> allowed_values_;
};
Expand Down Expand Up @@ -564,7 +564,10 @@ class SerialArgs : public PseudoTerminalArgs<AgentType>
int argc,
char** argv)
{
bool result = PseudoTerminalArgs<AgentType>::parse(argc, argv);
if (!PseudoTerminalArgs<AgentType>::parse(argc, argv))
{
return false;
}
ParseResult parse_dev = dev_.parse_argument(argc, argv);
if (ParseResult::VALID != parse_dev)
{
Expand Down Expand Up @@ -650,6 +653,12 @@ class ArgumentParser
break;
}
#endif // _WIN32
case TransportKind::INVALID:
default:
{
result = false;
break;
}
}
return (result ? ParseResult::VALID : ParseResult::INVALID);
}
Expand All @@ -672,7 +681,7 @@ class ArgumentParser
#ifndef _WIN32
bool launch_termios_agent()
{
struct termios attr;
struct termios attr = {};

/* Setting CONTROL OPTIONS. */
attr.c_cflag |= unsigned(CREAD); // Enable read.
Expand Down Expand Up @@ -858,6 +867,7 @@ inline std::thread create_agent_thread(
switch (parser.parse_arguments())
{
case parser::ParseResult::INVALID:
case parser::ParseResult::NOT_FOUND:
{
parser::utils::usage();
break;
Expand Down Expand Up @@ -909,6 +919,7 @@ inline std::thread create_agent_thread<eprosima::uxr::TermiosAgent>(
switch (parser.parse_arguments())
{
case parser::ParseResult::INVALID:
case parser::ParseResult::NOT_FOUND:
{
parser::utils::usage();
break;
Expand Down Expand Up @@ -948,6 +959,7 @@ inline std::thread create_agent_thread<eprosima::uxr::PseudoTerminalAgent>(
switch (parser.parse_arguments())
{
case parser::ParseResult::INVALID:
case parser::ParseResult::NOT_FOUND:
{
parser::utils::usage();
break;
Expand Down
2 changes: 1 addition & 1 deletion include/uxr/agent/utils/CLI.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,7 @@ class TermiosSubcommand : public ServerSubcommand
private:
void launch_server() final
{
struct termios attr;
struct termios attr = {};

/* Setting CONTROL OPTIONS. */
attr.c_cflag |= unsigned(CREAD); // Enable read.
Expand Down
142 changes: 5 additions & 137 deletions microxrce_agent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,149 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.

#include <uxr/agent/config.hpp>

#ifdef UAGENT_CLI_PROFILE
#include <uxr/agent/utils/CLI.hpp>
#else
#include <uxr/agent/utils/ArgumentParser.hpp>
#endif

#include <csignal>

#include <uxr/agent/AgentInstance.hpp>

int main(int argc, char** argv)
{
#ifndef _WIN32
sigset_t signals;
sigemptyset(&signals);
if(sigaddset(&signals, SIGINT) && sigaddset(&signals, SIGTERM))
{
std::cerr << "Wrong signalset" << std::endl;
std::exit(EXIT_FAILURE);
}
sigprocmask( SIG_BLOCK, &signals, nullptr );
#endif // _WIN32

#ifdef UAGENT_CLI_PROFILE
/* CLI application. */
CLI::App app("eProsima Micro XRCE-DDS Agent");
app.require_subcommand(1, 1);
app.get_formatter()->column_width(42);
eprosima::uxr::AgentInstance& agent_instance = agent_instance.getInstance();

/* CLI subcommands. */
eprosima::uxr::cli::UDPv4Subcommand udpv4_subcommand(app);
eprosima::uxr::cli::UDPv6Subcommand udpv6_subcommand(app);
eprosima::uxr::cli::TCPv4Subcommand tcpv4_subcommand(app);
eprosima::uxr::cli::TCPv6Subcommand tcpv6_subcommand(app);
#ifndef _WIN32
eprosima::uxr::cli::TermiosSubcommand termios_subcommand(app);
eprosima::uxr::cli::PseudoTerminalSubcommand pseudo_serial_subcommand(app);
#endif // _WIN32
eprosima::uxr::cli::ExitSubcommand exit_subcommand(app);

/* CLI parse. */
std::string cli_input{};
for (int i = 1; i < argc; ++i)
{
cli_input.append(argv[i]);
cli_input.append(" ");
}

while (true)
if (!agent_instance.create(argc, argv))
{
try
{
app.parse(cli_input);
break;
}
catch (const CLI::ParseError& e)
{
app.exit(e);
std::cin.clear();
std::cout << std::endl;
std::cout << "Enter command: ";
std::getline(std::cin, cli_input);
}
}

#ifdef _WIN32
/* Waiting until exit. */
std::cin.clear();
char exit_flag = 0;
while ('q' != exit_flag)
{
std::cin >> exit_flag;
}
#else
/* Wait for SIGTERM/SIGINT instead, as reading from stdin may be redirected to /dev/null. */
int n_signal = 0;
sigwait(&signals, &n_signal);
#endif // _WIN32
return 0;

#else
/* Use built-in argument parser */
if (2 > argc)
{
eprosima::uxr::agent::parser::utils::usage();
return 1;
}
std::string chosen_transport(argv[1]);
auto valid_transport = eprosima::uxr::agent::parser::utils::check_transport(chosen_transport);
std::thread agent_thread;
if (eprosima::uxr::agent::TransportKind::INVALID != valid_transport)
{
switch (valid_transport)
{
case eprosima::uxr::agent::TransportKind::UDP4:
{
agent_thread = std::move(eprosima::uxr::agent::create_agent_thread<
eprosima::uxr::UDPv4Agent>(argc, argv, valid_transport, &signals));
break;
}
case eprosima::uxr::agent::TransportKind::UDP6:
{
agent_thread = std::move(eprosima::uxr::agent::create_agent_thread<
eprosima::uxr::UDPv6Agent>(argc, argv, valid_transport, &signals));
break;
}
case eprosima::uxr::agent::TransportKind::TCP4:
{
agent_thread = std::move(eprosima::uxr::agent::create_agent_thread<
eprosima::uxr::TCPv4Agent>(argc, argv, valid_transport, &signals));
break;
}
case eprosima::uxr::agent::TransportKind::TCP6:
{
agent_thread = std::move(eprosima::uxr::agent::create_agent_thread<
eprosima::uxr::TCPv6Agent>(argc, argv, valid_transport, &signals));
break;
}
#ifndef _WIN32
case eprosima::uxr::agent::TransportKind::SERIAL:
{
agent_thread = std::move(eprosima::uxr::agent::create_agent_thread<
eprosima::uxr::TermiosAgent>(argc, argv, valid_transport, &signals));
break;
}
case eprosima::uxr::agent::TransportKind::PSEUDOTERMINAL:
{
agent_thread = std::move(eprosima::uxr::agent::create_agent_thread<
eprosima::uxr::PseudoTerminalAgent>(argc, argv, valid_transport, &signals));
break;
}
}
agent_thread.join();
return 0;
}
else
{
std::cerr << "Error: chosen transport '" << chosen_transport << "' is invalid!" << std::endl;
eprosima::uxr::agent::parser::utils::usage();
return 1;
}
agent_instance.run();

#endif // _WIN32
#endif // UAGENT_CLI_PROFILE
return 0;
}
Loading

0 comments on commit ac29889

Please sign in to comment.