Last active
May 24, 2021 17:23
-
-
Save sambatyon/09e4580830c50701110c to your computer and use it in GitHub Desktop.
A simple example of how to write actors in C++ with Asio
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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