Skip to content

Instantly share code, notes, and snippets.

@sambatyon
Last active May 24, 2021 17:23
Show Gist options
  • Save sambatyon/09e4580830c50701110c to your computer and use it in GitHub Desktop.
Save sambatyon/09e4580830c50701110c to your computer and use it in GitHub Desktop.
A simple example of how to write actors in C++ with Asio
#include <boost/noncopyable.hpp>
#include <boost/thread/thread.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
// The following macros are vs only
//#pragma push_macro("UNICODE")
//#pragma push_macro("_UNICODE")
#undef UNICODE
#undef _UNICODE
#include <log4cplus/logger.h>
#include <log4cplus/appender.h>
#include <log4cplus/loglevel.h>
#include <log4cplus/configurator.h>
#include <log4cplus/loggingmacros.h>
#include <log4cplus/consoleappender.h>
//#pragma pop_macro("_UNICODE")
//#pragma pop_macro("UNICODE")
#include <string>
#include <memory>
#include <cassert>
#include <iostream>
#if defined(WIN32)
# if !defined(NOMINMAX)
# define NOMINMAX
# endif // NOMINMAX
# define WIN32_MEAN_AND_LEAN
# include <Windows.h>
#elif defined(__APPLE__)
# include <mach-o/dyld.h>
#else // Assuming linux
# include <unistd.h>
#endif // WIN32
class GreetActor : protected boost::noncopyable
{
public:
GreetActor(const std::shared_ptr<boost::asio::io_service> &threadpool)
: threadpool_(threadpool)
, logger_(log4cplus::Logger::getInstance("greetactor.logger")) {
assert(threadpool_);
}
~GreetActor() {}
void Greet(const std::string &str, std::function<void(boost::system::error_code err)> callback) {
LOG4CPLUS_TRACE(logger_, "Scheduling greeing");
threadpool_->post([=]() {this->DoGreet(str, callback);});
}
private:
std::shared_ptr<boost::asio::io_service> threadpool_;
log4cplus::Logger logger_;
void DoGreet(const std::string &str, std::function<void(boost::system::error_code err)> callback) {
LOG4CPLUS_TRACE(logger_, "Processing greet.");
std::cout << "Hello, " << str << '\n';
callback(boost::system::errc::make_error_code(boost::system::errc::success));
}
};
void ConfigureLogger();
int main(int argc, char **argv) {
ConfigureLogger();
static auto logger = log4cplus::Logger::getInstance("logger.main");
LOG4CPLUS_TRACE(logger, "Initializing io");
std::shared_ptr<boost::asio::io_service> io_service = std::make_shared<boost::asio::io_service>();
std::unique_ptr<boost::asio::io_service::work> worker(new boost::asio::io_service::work(*io_service));
boost::thread io_service_thread([=]() {io_service->run();});
LOG4CPLUS_TRACE(logger, "Creating actor");
GreetActor actor(io_service);
actor.Greet("Alex", [](boost::system::error_code){
static auto logger = log4cplus::Logger::getInstance("logger.callback");
LOG4CPLUS_TRACE(logger, "Callback called");
std::cout << "Callback called\n";
});
// io_service->post([=](){io_service->stop();});
LOG4CPLUS_TRACE(logger, "Resetting the worker");
worker.reset();
io_service_thread.join();
return 0;
}
void ConfigureLogger() {
#if defined(_WIN32)
TCHAR path_buffer[MAX_PATH];
DWORD buffer_size = GetModuleFileName(NULL, path_buffer, MAX_PATH);
// if buffer_size == MAX_PATH the buffer was truncated and GetLastError() returns ERROR_INSUFFICIENT_BUFFER
// TODO: if buffer_size == 0 check GetLastError()
boost::filesystem::path log_path(path_buffer);
#elif defined(__APPLE__)
char path_buffer[MAXPATHLEN];
std::uint32_t buffer_size = sizeof(path_buffer);
int got_path = _NSGetExecutablePath(path_buffer, &buffer_size);
// TODO: check if got_path != 0, in which case the call failed.
boost::filesystem::path log_path(path_buffer);
#else // Assuming linux
# if defined(DEBUG)
// On debug the configuration file is in the same directory as the executable
char path_buffer[8192];
std::uint32_t buffer_size = sizeof(path_buffer);
ssize_t path_size = readlink("/proc/self/exe", path_buffer, buffer_size);
// TODO: if path_size == -1 check errno
path_buffer[path_size] = '\0';
boost::filesystem::path log_path(path_buffer);
# else
// On release mode, it should be in a common directory
boost::filesystem::path log_path(L"/var/log/actor/logging.conf");
# endif
#endif
log_path.remove_filename();
log_path /= "logging.conf";
// only in version 1.1.1 and beyond
// log4cplus::initialize();
if (boost::filesystem::exists(log_path) && boost::filesystem::is_regular_file(log_path)) {
log4cplus::PropertyConfigurator configurator(log_path.string());
configurator.configure();
} else {
log4cplus::BasicConfigurator configurator;
configurator.configure();
// TODO: make this code work
/*log4cplus::SharedAppenderPtr appender(new log4cplus::ConsoleAppender(false, false));
appender->setName("RootAppender");
std::auto_ptr<log4cplus::Layout> layout(
new log4cplus::PatternLayout("%D{%d.%m.%Y %H:%M:%S.%q} [%8t] %-5p - %c{2} - %m%n"));
appender->setLayout(layout);
auto logger = log4cplus::Logger::getRoot();
logger.addAppender(appender);
logger.setLogLevel(log4cplus::TRACE_LOG_LEVEL);*/
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment