shortener-bot/main.cpp

156 lines
5.2 KiB
C++

#include <cstdlib>
#include <iostream>
#include <memory>
#include <string>
#include <spdlog/spdlog.h>
#include <uv.h>
#include "common.h"
#include "commands.h"
#include "td/telegram/td_api.h"
#include "td/telegram/td_api.hpp"
const char *APP_GREETING = "--------------------\n"\
"| shortener-bot v0 |\n"\
"--------------------\n\n";
void async_startup(uv_idle_t *h);
void configure_blocked_signals();
void configure_logging();
void configure_shutdown_signals(uv_loop_t *loop, context *ctx);
CommandLineParams parse_command_line(int argc, char **argv);
void print_greeting();
void print_usage(const char *programName);
void shutdown_signal_handler(uv_signal_t *h, int signum);
int main(int argc, char **argv) {
CommandLineParams cmdLineParams;
try {
cmdLineParams = parse_command_line(argc, argv);
} catch (CommandLineParamError e) {
switch (e) {
case CommandLineParamError::NoApiCreds:
print_usage(argv[0]);
return 1;
}
}
configure_logging();
configure_blocked_signals();
print_greeting();
uv_loop_t *defaultLoop = uv_default_loop();
context ctx;
ctx.apiCreds = cmdLineParams.apiCreds;
spdlog::info("Creating Telegram client");
TelegramClient tg(defaultLoop);
ctx.tg = &tg;
uv_idle_t startupHandle;
startupHandle.data = (void*)&ctx;
uv_idle_init(defaultLoop, &startupHandle);
uv_idle_start(&startupHandle, async_startup);
configure_shutdown_signals(defaultLoop, &ctx);
spdlog::info("Entering event loop");
uv_run(defaultLoop, UV_RUN_DEFAULT);
spdlog::info("Leaving event loop");
spdlog::info("Cleaning up");
return 0;
}
void async_startup(uv_idle_t *h) {
context *ctx = (context*)h->data;
spdlog::info("Starting telegram client (using api id {}, hash {})", ctx->apiCreds.id, ctx->apiCreds.hash);
ctx->tg->add_update_handler([ctx](void*, td_api::Object &update){
td_api::downcast_call(update, overloaded(
[ctx](td_api::updateAuthorizationState &upd) {
td_api::downcast_call(*upd.authorization_state_, overloaded(
[ctx](td_api::authorizationStateWaitTdlibParameters &state) {
auto request = td_api::make_object<td_api::setTdlibParameters>();
request->database_directory_ = "tdata";
request->use_message_database_ = false;
request->use_secret_chats_ = false;
request->api_id_ = ctx->apiCreds.id;
request->api_hash_ = ctx->apiCreds.hash;
request->system_language_code_ = "en";
request->device_model_ = "server";
request->application_version_ = "1.0.0";
ctx->tg->send_query(std::move(request), {});
},
[ctx](td_api::authorizationStateWaitPhoneNumber &state) {
ctx->tg->send_query(td_api::make_object<td_api::checkAuthenticationBotToken>(ctx->apiCreds.botToken), {}); // TODO add error handler
},
[ctx](td_api::authorizationStateReady &state) {
spdlog::info("Telegram ready");
},
[ctx,&upd](td_api::Object &obj){
spdlog::debug("unknown authorization state ID {}", upd.authorization_state_->get_id());
}
));
},
[ctx](td_api::updateNewMessage &upd) {
if (upd.message_->is_outgoing_) return;
cmd::handle_regular_message(ctx, *upd.message_);
},
[](td_api::Object &obj){}
));
}, nullptr);
ctx->tg->start();
uv_close((uv_handle_t*)h, nullptr);
}
void configure_logging() {
auto loggingSink = std::make_shared<spdlog::sinks::ansicolor_sink<spdlog::details::console_mutex>>(stdout, spdlog::color_mode::automatic);
loggingSink->set_color(spdlog::level::debug, "\033[38;5;61m");
auto logger = std::make_shared<spdlog::logger>("main", loggingSink);
spdlog::set_default_logger(logger);
spdlog::set_level(spdlog::level::debug);
}
void configure_blocked_signals() {
sigset_t signalSet;
sigemptyset(&signalSet);
sigaddset(&signalSet, SIGUSR1);
sigaddset(&signalSet, SIGUSR2);
sigaddset(&signalSet, SIGHUP);
sigprocmask(SIG_BLOCK, &signalSet, nullptr);
}
void register_signal_handle(uv_loop_t *loop, context *ctx, int signum, void(*signal_handler)(uv_signal_t*, int)) {
auto deleter = [](uv_signal_t *handle) {
uv_close((uv_handle_t*)handle, [](uv_handle_t *h){ delete h; });
};
std::unique_ptr<uv_signal_t, decltype(deleter)> handle(new uv_signal_t, deleter);
uv_signal_init(loop, handle.get());
uv_signal_start(handle.get(), signal_handler, signum);
}
void configure_shutdown_signals(uv_loop_t *loop, context *ctx) {
register_signal_handle(loop, ctx, SIGINT, shutdown_signal_handler);
}
void shutdown_signal_handler(uv_signal_t *h, int signum) {
spdlog::info("Stopping");
uv_stop(uv_default_loop());
}
CommandLineParams parse_command_line(int argc, char **argv) {
if (argc < 4) throw CommandLineParamError::NoApiCreds;
char *apiIdEnd = nullptr;
int apiId = strtol(argv[1], &apiIdEnd, 10);
if (apiIdEnd == argv[1]) throw CommandLineParamError::NoApiCreds;
return CommandLineParams {apiId, std::string(argv[2]), std::string(argv[3])};
}
void print_greeting() {
std::cout << APP_GREETING << std::flush;
}
void print_usage(const char *programName) {
std::cout << "usage: " << programName << " <api_id> <api_hash> <token>\n";
}