#include #include #include #include #include #include #include #include #include // clang-format off constexpr auto ToString(spdlog::level::level_enum e) { switch (e) { case spdlog::level::trace: return "TRACE"; case spdlog::level::debug: return "DEBUG"; case spdlog::level::info: return "INFO"; case spdlog::level::warn: return "WARNING"; case spdlog::level::err: return "ERROR"; case spdlog::level::critical: return "CRITICAL"; case spdlog::level::off: return "OFF"; default: return "INVALID"; } } // clang-format on namespace iq = larra::xmpp::iq; auto Coroutine() -> boost::asio::awaitable { SPDLOG_INFO("Connecting client..."); try { auto client = co_await larra::xmpp::client::CreateClient>( larra::xmpp::PlainUserAccount{.jid = {.username = "test1", .server = "localhost"}, .password = "test1"}, {.useTls = larra::xmpp::client::Options::kNever}); // rfc6120 7.1 // After a client authenticates with a server, // it MUST bind a specific resource to the stream so that the server can properly address the client. co_await std::visit( [](auto& client) -> boost::asio::awaitable { co_await client.CreateResourceBind(); }, client); co_await std::visit( [](auto& client) -> boost::asio::awaitable { co_await client.UpdateListOfContacts(); }, client); // rfc6120 2.2 // Upon authenticating with a server and binding a resource (thus becoming a connected resource as defined in [XMPP‑CORE]), // a client SHOULD request the roster before sending initial presence co_await std::visit( [](auto& client) -> boost::asio::awaitable { SPDLOG_INFO("Send presence: Available"); co_await client.Send(larra::xmpp::presence::c2s::Available{}); }, client); } catch(const std::exception& err) { SPDLOG_ERROR("{}", err.what()); co_return; } SPDLOG_INFO("Done connecting client!"); } namespace po = boost::program_options; auto main(int argc, char** argv) -> int { // Define options po::options_description desc("Allowed options"); desc.add_options()("help,h", "Print help message")("log_level,l", po::value()->default_value(SPDLOG_LEVEL_INFO), "Set log level: 0=TRACE, 1=DEBUG, 2=INFO, 3=WARN, 4=ERROR, 5=CRITICAL, 6=OFF"); // Parse command-line arguments po::variables_map vm; try { po::store(po::parse_command_line(argc, argv, desc), vm); po::notify(vm); if(vm["log_level"].as() < spdlog::level::level_enum::trace || vm["log_level"].as() > spdlog::level::level_enum::off) { throw std::invalid_argument{ std::format("Invalid argument value for '--log_level' option. Check option description for more details")}; } if(vm["log_level"].as() < SPDLOG_ACTIVE_LEVEL) { SPDLOG_WARN("Specified log_level '{}' is lower than max available one '{}'. Log level will be changed according to the maximum one", vm["log_level"].as(), SPDLOG_ACTIVE_LEVEL); } } catch(const std::exception& e) { SPDLOG_CRITICAL("Cmd parse error: {}", e.what()); return 1; } // Cmd options handling spdlog::set_level(static_cast(vm["log_level"].as())); std::println("\nEnvironment setup:\n\tCurrently set log level: {}\n", ToString(spdlog::get_level())); boost::asio::io_context io_context; boost::asio::co_spawn(io_context, Coroutine(), boost::asio::detached); io_context.run(); }