26#ifndef GOBY_MIDDLEWARE_APPLICATION_INTERFACE_H
27#define GOBY_MIDDLEWARE_APPLICATION_INTERFACE_H
36#include <boost/format.hpp>
54template <
typename App>
63template <
typename App,
64 typename Configurator = middleware::ProtobufConfigurator<typename App::ConfigType>>
65int run(
int argc,
char* argv[])
67 return run<App>(Configurator(argc, argv));
115 void quit(
int return_value = 0)
118 return_value_ = return_value;
130 throw(
goby::Exception(
"No lat_origin and lon_origin defined for requested UTMGeodesy"));
136 std::string
app_name() {
return app3_base_configuration_->name(); }
140 boost::units::quantity<boost::units::si::frequency>
143 if (app3_base_configuration_->has_loop_frequency())
144 return app3_base_configuration_->loop_frequency_with_units();
146 return compiled_loop_freq;
153 template <
typename App>
154 friend int ::goby::run(
162 void run_one() {
run(); }
164 void configure_logger();
165 void configure_glog_file();
166 void configure_intervehicle();
167 void check_rotate_glog_file();
171 static std::unique_ptr<Config> app_cfg_;
172 static std::unique_ptr<protobuf::AppConfig> app3_base_configuration_;
178 static std::unique_ptr<std::ofstream> fout_;
182 std::unique_ptr<goby::util::UTMGeodesy> geodesy_;
188template <
typename Config>
193template <
typename Config>
194std::unique_ptr<goby::middleware::protobuf::AppConfig>
202 if (app3_base_configuration_->has_geodesy())
204 app3_base_configuration_->geodesy().lon_origin_with_units()});
206 if (app3_base_configuration_->has_intervehicle_cfg())
207 configure_intervehicle();
209 if (!app3_base_configuration_->IsInitialized())
212 glog.
is_debug2() &&
glog <<
"Application: constructed with PID: " << getpid() << std::endl;
213 glog.
is_debug1() &&
glog <<
"App name is " << app3_base_configuration_->name() << std::endl;
214 glog.
is_debug2() &&
glog <<
"Configuration is: " << app_cfg_->DebugString() << std::endl;
224 app3_base_configuration_->glog_config().tty_verbosity()),
227 if (app3_base_configuration_->glog_config().show_gui())
230 if (app3_base_configuration_->glog_config().has_file_log())
231 configure_glog_file();
233 if (app3_base_configuration_->glog_config().show_dccl_log())
240 app3_base_configuration_->intervehicle_cfg();
252 if (app3_base_configuration_->glog_config().has_file_log() &&
253 app3_base_configuration_->glog_config().file_log().has_log_rotate_sec() &&
257 configure_glog_file();
263 const auto& file_log = app3_base_configuration_->glog_config().file_log();
264 std::string file_format_str;
266 std::string file_name_format = file_log.file_name();
268 if (!file_log.has_file_name() && file_log.omit().file_timestamp())
269 file_name_format =
"%2%.txt";
271 if (file_log.has_file_dir() && !file_log.file_dir().empty())
273 auto file_dir = file_log.file_dir();
274 if (file_dir.back() !=
'/')
276 file_format_str = file_dir + file_name_format;
280 file_format_str = file_name_format;
283 boost::format file_format(file_format_str);
285 if (!file_log.omit().file_timestamp())
287 if (file_format_str.find(
"%1") == std::string::npos)
289 glog <<
"file_name string must contain \"%1%\" which is expanded to the current "
290 "application start time (e.g. 20190201T184925), unless omit.file_timestamp "
291 "== true. Erroneous file_name is: "
292 << file_format_str << std::endl;
295 file_format.exceptions(boost::io::all_error_bits ^
296 (boost::io::too_many_args_bit | boost::io::too_few_args_bit));
298 std::string file_name =
302 fout_.reset(
new std::ofstream(file_name.c_str()));
304 if (!fout_->is_open())
305 glog.
is_die() &&
glog <<
"cannot write glog output to requested file: " << file_name
308 if (!file_log.omit().latest_symlink())
310 std::string file_symlink =
311 (file_format %
"latest" % app3_base_configuration_->name()).
str();
312 remove(file_symlink.c_str());
313 char* resolved = realpath(file_name.c_str(),
nullptr);
314 if (resolved !=
nullptr)
316 int result = symlink(resolved, file_symlink.c_str());
320 glog <<
"Cannot create symlink to latest file. Continuing onwards anyway"
327 if (file_log.has_log_rotate_sec())
328 next_log_rotate_time_ =
332template <
typename Config>
342 sigset_t signal_mask;
343 sigemptyset(&signal_mask);
344 sigaddset(&signal_mask, SIGWINCH);
345 pthread_sigmask(SIG_BLOCK, &signal_mask, NULL);
347 this->pre_initialize();
349 this->post_initialize();
354 this->check_rotate_glog_file();
356 this->pre_finalize();
358 this->post_finalize();
359 return return_value_;
362template <
typename App>
365 int return_value = 0;
381 std::cout << cfgtor.
str() << std::endl;
386 App::app_cfg_.reset(
new typename App::ConfigType(cfgtor.
cfg()));
387 App::app3_base_configuration_.reset(
391 if (App::app3_base_configuration_->simulation().time().use_sim_time())
395 App::app3_base_configuration_->simulation().time().warp_factor();
396 if (App::app3_base_configuration_->simulation().time().has_reference_microtime())
398 std::chrono::system_clock::time_point(std::chrono::microseconds(
399 App::app3_base_configuration_->simulation().time().reference_microtime()));
404 return_value = app.__run();
406 catch (std::exception& e)
409 std::cerr <<
"Application:: uncaught exception: " << e.what() << std::endl;
simple exception class for goby applications
Base class for Goby applications. Generally you will want to use SingleThreadApplication or MultiThre...
const util::UTMGeodesy & geodesy()
Accesses the geodetic conversion tool if lat_origin and lon_origin were provided.
virtual void pre_finalize()
Called just before finalize.
virtual void post_initialize()
Called just after initialize.
virtual void initialize()
Perform any initialize tasks that couldn't be done in the constructor.
virtual void pre_initialize()
Called just before initialize.
virtual void run()=0
Runs once.
bool has_geodesy()
Returns if the geodesy tool is configured with a datum.
virtual void finalize()
Perform any final cleanup actions just before the destructor is called.
void quit(int return_value=0)
Requests a clean exit.
void configure_geodesy(goby::util::UTMGeodesy::LatLonPoint datum)
boost::units::quantity< boost::units::si::frequency > choose_loop_freq(boost::units::quantity< boost::units::si::frequency > compiled_loop_freq)
virtual void post_finalize()
Called just after finalize.
const Config & app_cfg()
Accesses configuration object passed at launch.
indicates a problem with the runtime command line or .cfg file configuration (or –help was given)
Defines the interface to a "configurator", a class that can read command line parameters (argc,...
virtual void validate() const
Override to validate the configuration.
virtual void handle_config_error(middleware::ConfigException &e) const
Override to customize how ConfigException errors are handled.
virtual const protobuf::AppConfig & app_configuration() const
Subset of the configuration used to configure the Application itself.
const Config & cfg() const
The configuration object produced from the command line parameters.
virtual std::string str() const =0
Override to output the configuration object as a string.
const std::string & dccl_passphrase() const
bool has_dccl_passphrase() const
void remove_stream(std::ostream *os=nullptr)
void set_name(const std::string &s)
Set the name of the application that the logger is serving.
void add_stream(logger::Verbosity verbosity=logger::VERBOSE, std::ostream *os=nullptr)
Attach a stream object (e.g. std::cout, std::ofstream, ...) to the logger with desired verbosity.
std::string str(TimeType value=SystemClock::now< TimeType >())
Returns the provided time (or current time if omitted) as a human-readable string.
std::string file_str(TimeType value=SystemClock::now< TimeType >())
Returns the provided time (or current time if omitted) as an ISO string suitable for file names (no s...
The global namespace for the Goby project.
util::FlexOstream glog
Access the Goby logger through this object.
int run(const goby::middleware::ConfiguratorInterface< typename App::ConfigType > &cfgtor)
Run a Goby application using the provided Configurator.
static void set_crypto_passphrase(const std::string &passphrase, const std::set< dccl::int32 > &do_not_encrypt_ids=std::set< dccl::int32 >())
static void setup_dlog()
Enable dlog output to glog using same verbosity settings as glog.
static bool using_sim_time
Enables simulation time if true (if false, none of the remaining parameters are used)
static std::chrono::system_clock::time_point reference_time
Reference time when calculating SystemClock::now(). If this is unset, the default is 1 January of the...
static int warp_factor
Warp factor to speed up (or slow time) the time values returned by SteadyClock::now() and SystemClock...
std::chrono::time_point< SteadyClock > time_point
static time_point now() noexcept
Returns the current steady time unless SimulatorSettings::using_sim_time == true in which case a simu...