2020-11-03 17:34:10 +01:00
//
2022-12-31 22:31:16 +01:00
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2023
2020-11-03 17:34:10 +01:00
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
# include "telegram-bot-api/ClientManager.h"
# include "telegram-bot-api/ClientParameters.h"
# include "telegram-bot-api/HttpConnection.h"
# include "telegram-bot-api/HttpServer.h"
# include "telegram-bot-api/HttpStatConnection.h"
# include "telegram-bot-api/Stats.h"
2022-08-22 01:26:36 +02:00
# include "telegram-bot-api/Watchdog.h"
2020-11-03 17:34:10 +01:00
# include "td/db/binlog/Binlog.h"
# include "td/net/GetHostByNameActor.h"
# include "td/net/HttpInboundConnection.h"
# include "td/actor/actor.h"
2020-11-24 01:12:39 +01:00
# include "td/actor/ConcurrentScheduler.h"
2020-11-03 17:34:10 +01:00
2022-10-09 19:16:45 +02:00
# include "td/utils/AsyncFileLog.h"
2021-05-20 22:51:37 +02:00
# include "td/utils/CombinedLog.h"
2020-11-03 17:34:10 +01:00
# include "td/utils/common.h"
# include "td/utils/crypto.h"
# include "td/utils/ExitGuard.h"
//#include "td/utils/GitInfo.h"
# include "td/utils/logging.h"
# include "td/utils/MemoryLog.h"
# include "td/utils/misc.h"
# include "td/utils/OptionParser.h"
2021-06-22 20:26:41 +02:00
# include "td/utils/PathView.h"
2021-11-17 11:24:19 +01:00
# include "td/utils/port/detail/ThreadIdGuard.h"
2020-11-10 00:15:40 +01:00
# include "td/utils/port/IPAddress.h"
2020-11-03 17:34:10 +01:00
# include "td/utils/port/path.h"
# include "td/utils/port/rlimit.h"
# include "td/utils/port/signals.h"
# include "td/utils/port/stacktrace.h"
2022-09-17 23:20:41 +02:00
# include "td/utils/port/thread.h"
2020-11-03 17:34:10 +01:00
# include "td/utils/port/user.h"
2022-06-30 19:27:08 +02:00
# include "td/utils/Promise.h"
2020-11-03 17:34:10 +01:00
# include "td/utils/Slice.h"
2021-05-20 22:51:37 +02:00
# include "td/utils/SliceBuilder.h"
2020-11-03 17:34:10 +01:00
# include "td/utils/Status.h"
# include "td/utils/Time.h"
# include <atomic>
# include <cstdlib>
# include <memory>
# include <tuple>
namespace telegram_bot_api {
2021-05-20 22:51:37 +02:00
static std : : atomic_flag need_reopen_log ;
2020-11-03 17:34:10 +01:00
2021-05-20 22:51:37 +02:00
static void after_log_rotation_signal_handler ( int sig ) {
need_reopen_log . clear ( ) ;
2020-11-03 17:34:10 +01:00
}
static std : : atomic_flag need_quit ;
static void quit_signal_handler ( int sig ) {
need_quit . clear ( ) ;
}
static td : : MemoryLog < 1 < < 20 > memory_log ;
void print_log ( ) {
2022-11-12 09:15:33 +01:00
td : : LogGuard log_guard ;
2020-11-03 17:34:10 +01:00
auto buf = memory_log . get_buffer ( ) ;
auto pos = memory_log . get_pos ( ) ;
2022-09-18 00:17:09 +02:00
size_t tail_length = buf . size ( ) - pos ;
while ( tail_length > 0 & & buf [ pos + tail_length - 1 ] = = ' ' ) {
tail_length - - ;
}
if ( tail_length + 100 > = buf . size ( ) - pos ) {
tail_length = buf . size ( ) - pos ;
}
2020-11-03 17:34:10 +01:00
td : : signal_safe_write ( " ------- Log dump ------- \n " ) ;
2022-09-18 00:17:09 +02:00
td : : signal_safe_write ( buf . substr ( pos , tail_length ) , false ) ;
2020-11-03 17:34:10 +01:00
td : : signal_safe_write ( buf . substr ( 0 , pos ) , false ) ;
td : : signal_safe_write ( " \n " , false ) ;
td : : signal_safe_write ( " ------------------------ \n " ) ;
}
2022-10-21 12:39:32 +02:00
static std : : atomic_bool has_failed { false } ;
2022-12-29 14:59:38 +01:00
static std : : atomic_flag need_dump_statistics ;
2021-09-12 12:51:22 +02:00
static void dump_stacktrace_signal_handler ( int sig ) {
2022-10-21 12:39:32 +02:00
if ( has_failed ) {
return ;
}
2022-11-12 09:15:33 +01:00
td : : LogGuard log_guard ;
if ( LOG_TAG ! = nullptr & & * LOG_TAG ) {
td : : signal_safe_write ( td : : Slice ( LOG_TAG ) ) ;
td : : signal_safe_write ( td : : Slice ( " \n " ) , false ) ;
}
2021-09-12 12:51:22 +02:00
td : : Stacktrace : : print_to_stderr ( ) ;
2022-12-29 14:59:38 +01:00
need_dump_statistics . clear ( ) ;
2021-09-12 12:51:22 +02:00
}
2020-11-03 17:34:10 +01:00
static void fail_signal_handler ( int sig ) {
2022-10-21 12:39:32 +02:00
has_failed = true ;
2022-11-12 09:15:33 +01:00
{
td : : LogGuard log_guard ;
td : : signal_safe_write_signal_number ( sig ) ;
td : : Stacktrace : : PrintOptions options ;
options . use_gdb = true ;
td : : Stacktrace : : print_to_stderr ( options ) ;
}
2020-11-03 17:34:10 +01:00
print_log ( ) ;
_Exit ( EXIT_FAILURE ) ;
}
static std : : atomic_flag need_change_verbosity_level ;
static void change_verbosity_level_signal_handler ( int sig ) {
need_change_verbosity_level . clear ( ) ;
}
static std : : atomic_flag need_dump_log ;
static void dump_log_signal_handler ( int sig ) {
2022-10-21 12:39:32 +02:00
if ( has_failed ) {
return ;
}
2020-11-03 17:34:10 +01:00
need_dump_log . clear ( ) ;
}
static void sigsegv_signal_handler ( int signum , void * addr ) {
td : : signal_safe_write_pointer ( addr ) ;
fail_signal_handler ( signum ) ;
}
int main ( int argc , char * argv [ ] ) {
SET_VERBOSITY_LEVEL ( VERBOSITY_NAME ( FATAL ) ) ;
td : : ExitGuard exit_guard ;
2021-11-17 11:24:19 +01:00
td : : detail : : ThreadIdGuard thread_id_guard ;
2020-11-03 17:34:10 +01:00
2021-05-20 22:51:37 +02:00
need_reopen_log . test_and_set ( ) ;
2020-11-03 17:34:10 +01:00
need_quit . test_and_set ( ) ;
need_change_verbosity_level . test_and_set ( ) ;
2022-12-29 14:59:38 +01:00
need_dump_statistics . test_and_set ( ) ;
2020-11-03 17:34:10 +01:00
need_dump_log . test_and_set ( ) ;
td : : Stacktrace : : init ( ) ;
td : : setup_signals_alt_stack ( ) . ensure ( ) ;
2021-05-20 22:51:37 +02:00
td : : set_signal_handler ( td : : SignalType : : User , after_log_rotation_signal_handler ) . ensure ( ) ;
2020-11-03 17:34:10 +01:00
td : : ignore_signal ( td : : SignalType : : HangUp ) . ensure ( ) ;
td : : ignore_signal ( td : : SignalType : : Pipe ) . ensure ( ) ;
td : : set_signal_handler ( td : : SignalType : : Quit , quit_signal_handler ) . ensure ( ) ;
td : : set_signal_handler ( td : : SignalType : : Abort , fail_signal_handler ) . ensure ( ) ;
td : : set_signal_handler ( td : : SignalType : : Other , fail_signal_handler ) . ensure ( ) ;
td : : set_extended_signal_handler ( td : : SignalType : : Error , sigsegv_signal_handler ) . ensure ( ) ;
2022-08-21 13:44:57 +02:00
td : : set_real_time_signal_handler ( 0 , change_verbosity_level_signal_handler ) . ensure ( ) ;
td : : set_real_time_signal_handler ( 1 , dump_log_signal_handler ) . ensure ( ) ;
td : : set_real_time_signal_handler ( 2 , dump_stacktrace_signal_handler ) . ensure ( ) ;
2020-11-03 17:34:10 +01:00
td : : init_openssl_threads ( ) ;
auto start_time = td : : Time : : now ( ) ;
auto shared_data = std : : make_shared < SharedData > ( ) ;
auto parameters = std : : make_unique < ClientParameters > ( ) ;
2023-04-21 15:08:20 +02:00
parameters - > version_ = " 6.7.1 " ;
2020-11-03 17:34:10 +01:00
parameters - > shared_data_ = shared_data ;
2020-11-21 15:38:11 +01:00
parameters - > start_time_ = start_time ;
2020-11-03 17:34:10 +01:00
auto net_query_stats = td : : create_net_query_stats ( ) ;
parameters - > net_query_stats_ = net_query_stats ;
td : : OptionParser options ;
bool need_print_usage = false ;
2021-05-10 17:49:50 +02:00
bool need_print_version = false ;
2020-11-03 17:34:10 +01:00
int http_port = 8081 ;
int http_stat_port = 0 ;
2020-11-10 00:15:40 +01:00
td : : string http_ip_address = " 0.0.0.0 " ;
td : : string http_stat_ip_address = " 0.0.0.0 " ;
2020-11-03 17:34:10 +01:00
td : : string log_file_path ;
2021-02-14 23:23:18 +01:00
int default_verbosity_level = 0 ;
int memory_verbosity_level = VERBOSITY_NAME ( INFO ) ;
2020-11-03 17:34:10 +01:00
td : : int64 log_max_file_size = 2000000000 ;
2021-06-22 20:26:41 +02:00
td : : string working_directory = PSTRING ( ) < < " . " < < TD_DIR_SLASH ;
2020-11-03 17:34:10 +01:00
td : : string temporary_directory ;
td : : string username ;
td : : string groupname ;
td : : uint64 max_connections = 0 ;
2022-09-17 23:20:41 +02:00
td : : uint64 cpu_affinity = 0 ;
td : : uint64 main_thread_affinity = 0 ;
2020-11-03 17:34:10 +01:00
ClientManager : : TokenRange token_range { 0 , 1 } ;
parameters - > api_id_ = [ ] ( auto x ) - > td : : int32 {
if ( x ) {
return td : : to_integer < td : : int32 > ( td : : Slice ( x ) ) ;
}
return 0 ;
} ( std : : getenv ( " TELEGRAM_API_ID " ) ) ;
2022-03-16 10:52:34 +01:00
parameters - > api_hash_ = [ ] ( auto x ) - > td : : string {
2020-11-03 17:34:10 +01:00
if ( x ) {
return x ;
}
2022-03-16 10:52:34 +01:00
return td : : string ( ) ;
2020-11-03 17:34:10 +01:00
} ( std : : getenv ( " TELEGRAM_API_HASH " ) ) ;
2020-11-05 15:47:21 +01:00
options . set_usage ( td : : Slice ( argv [ 0 ] ) , " --api-id=<arg> --api-hash=<arg> [--local] [OPTION]... " ) ;
2020-11-03 17:34:10 +01:00
options . set_description ( " Telegram Bot API server " ) ;
options . add_option ( ' h ' , " help " , " display this help text and exit " , [ & ] { need_print_usage = true ; } ) ;
2021-05-10 17:49:50 +02:00
options . add_option ( ' \0 ' , " version " , " display version number and exit " , [ & ] { need_print_version = true ; } ) ;
2020-11-03 17:34:10 +01:00
options . add_option ( ' \0 ' , " local " , " allow the Bot API server to serve local requests " ,
[ & ] { parameters - > local_mode_ = true ; } ) ;
2020-11-12 23:15:49 +01:00
options . add_option ( ' \0 ' , " no-file-limit " , " disable the file limits " ,
[ & ] { parameters - > no_file_limit_ = true ; } ) ;
2020-11-10 16:14:44 +01:00
options . add_option ( ' \0 ' , " insecure " , " allow the Bot API to send request via insecure HTTP " , [ & ] { parameters - > allow_http_ = true ; } ) ;
options . add_option ( ' \0 ' , " relative " , " use relative file path in local mode " , [ & ] { parameters - > use_relative_path_ = true ; } ) ;
2020-12-12 00:45:36 +01:00
options . add_option ( ' \0 ' , " allow-users " , " allow user accounts to use the API " , [ & ] { parameters - > allow_users_ = true ; } ) ;
options . add_option ( ' \0 ' , " allow-users-registration " , " allow user accounts to be registered on the API " ,
[ & ] { parameters - > allow_users_registration_ = true ; } ) ;
2020-11-10 16:14:44 +01:00
2020-12-15 17:43:20 +01:00
options . add_option ( ' \0 ' , " stats-hide-sensible-data " , " in the stats hide sensible data like bot token and webhook url " , [ & ] { parameters - > stats_hide_sensible_data_ = true ; } ) ;
2020-11-03 17:34:10 +01:00
options . add_checked_option (
' \0 ' , " api-id " ,
" application identifier for Telegram API access, which can be obtained at https://my.telegram.org (defaults to "
" the value of the TELEGRAM_API_ID environment variable) " ,
td : : OptionParser : : parse_integer ( parameters - > api_id_ ) ) ;
options . add_option ( ' \0 ' , " api-hash " ,
" application identifier hash for Telegram API access, which can be obtained at "
" https://my.telegram.org (defaults to the value of the TELEGRAM_API_HASH environment variable) " ,
td : : OptionParser : : parse_string ( parameters - > api_hash_ ) ) ;
options . add_checked_option ( ' p ' , " http-port " , PSLICE ( ) < < " HTTP listening port (default is " < < http_port < < " ) " ,
td : : OptionParser : : parse_integer ( http_port ) ) ;
options . add_checked_option ( ' s ' , " http-stat-port " , " HTTP statistics port " ,
td : : OptionParser : : parse_integer ( http_stat_port ) ) ;
options . add_option ( ' d ' , " dir " , " server working directory " , td : : OptionParser : : parse_string ( working_directory ) ) ;
options . add_option ( ' t ' , " temp-dir " , " directory for storing HTTP server temporary files " ,
td : : OptionParser : : parse_string ( temporary_directory ) ) ;
2020-11-10 00:15:40 +01:00
options . add_checked_option ( ' \0 ' , " filter " ,
" \" <remainder>/<modulo> \" . Allow only bots with 'bot_user_id % modulo == remainder' " ,
[ & ] ( td : : Slice rem_mod ) {
td : : Slice rem ;
td : : Slice mod ;
std : : tie ( rem , mod ) = td : : split ( rem_mod , ' / ' ) ;
TRY_RESULT ( rem_i , td : : to_integer_safe < td : : uint64 > ( rem ) ) ;
TRY_RESULT ( mod_i , td : : to_integer_safe < td : : uint64 > ( mod ) ) ;
if ( rem_i > = mod_i ) {
return td : : Status : : Error ( " Wrong argument specified: ensure that remainder < modulo " ) ;
}
token_range = { rem_i , mod_i } ;
return td : : Status : : OK ( ) ;
} ) ;
2020-11-03 17:34:10 +01:00
options . add_checked_option ( ' \0 ' , " max-webhook-connections " ,
" default value of the maximum webhook connections per bot " ,
td : : OptionParser : : parse_integer ( parameters - > default_max_webhook_connections_ ) ) ;
2020-11-10 00:15:40 +01:00
options . add_checked_option ( ' \0 ' , " http-ip-address " ,
" local IP address, HTTP connections to which will be accepted. By default, connections to "
" any local IPv4 address are accepted " ,
[ & ] ( td : : Slice ip_address ) {
TRY_STATUS ( td : : IPAddress : : get_ip_address ( ip_address . str ( ) ) ) ;
http_ip_address = ip_address . str ( ) ;
return td : : Status : : OK ( ) ;
} ) ;
options . add_checked_option ( ' \0 ' , " http-stat-ip-address " ,
" local IP address, HTTP statistics connections to which will be accepted. By default, "
" statistics connections to any local IPv4 address are accepted " ,
[ & ] ( td : : Slice ip_address ) {
TRY_STATUS ( td : : IPAddress : : get_ip_address ( ip_address . str ( ) ) ) ;
http_stat_ip_address = ip_address . str ( ) ;
return td : : Status : : OK ( ) ;
} ) ;
2020-11-03 17:34:10 +01:00
options . add_option ( ' l ' , " log " , " path to the file where the log will be written " ,
td : : OptionParser : : parse_string ( log_file_path ) ) ;
2021-02-14 23:23:18 +01:00
options . add_checked_option ( ' v ' , " verbosity " , " log verbosity level " ,
td : : OptionParser : : parse_integer ( default_verbosity_level ) ) ;
options . add_checked_option ( ' \0 ' , " memory-verbosity " , " memory log verbosity level; defaults to 3 " ,
td : : OptionParser : : parse_integer ( memory_verbosity_level ) ) ;
2020-11-03 17:34:10 +01:00
options . add_checked_option (
' \0 ' , " log-max-file-size " ,
PSLICE ( ) < < " maximum size of the log file in bytes before it will be auto-rotated (default is "
< < log_max_file_size < < " ) " ,
td : : OptionParser : : parse_integer ( log_max_file_size ) ) ;
options . add_option ( ' u ' , " username " , " effective user name to switch to " , td : : OptionParser : : parse_string ( username ) ) ;
options . add_option ( ' g ' , " groupname " , " effective group name to switch to " , td : : OptionParser : : parse_string ( groupname ) ) ;
options . add_checked_option ( ' c ' , " max-connections " , " maximum number of open file descriptors " ,
td : : OptionParser : : parse_integer ( max_connections ) ) ;
2022-09-17 23:20:41 +02:00
# if TD_HAVE_THREAD_AFFINITY
options . add_checked_option ( ' \0 ' , " cpu-affinity " , " CPU affinity as 64-bit mask (defaults to all available CPUs) " ,
td : : OptionParser : : parse_integer ( cpu_affinity ) ) ;
options . add_checked_option (
' \0 ' , " main-thread-affinity " ,
" CPU affinity of the main thread as 64-bit mask (defaults to the value of the option --cpu-affinity) " ,
td : : OptionParser : : parse_integer ( main_thread_affinity ) ) ;
# else
( void ) cpu_affinity ;
( void ) main_thread_affinity ;
# endif
2020-11-03 17:34:10 +01:00
2022-02-01 18:28:35 +01:00
2020-11-11 19:45:15 +01:00
options . add_checked_option ( ' \0 ' , " max-batch-operations " , PSLICE ( ) < < " maximum number of batch operations (default: " < < parameters - > max_batch_operations < < " ) " ,
2022-02-01 18:28:35 +01:00
td : : OptionParser : : parse_integer ( parameters - > max_batch_operations ) ) ;
2021-06-17 21:36:46 +02:00
options . add_checked_option ( ' \0 ' , " file-expiration-time " ,
PSLICE ( ) < < " downloaded files expire after this amount of seconds of not being used (defaults to " < < parameters - > file_expiration_timeout_seconds_ < < " ) " ,
td : : OptionParser : : parse_integer ( parameters - > file_expiration_timeout_seconds_ ) ) ;
2023-02-04 15:31:24 +01:00
2022-01-25 16:18:44 +01:00
options . add_checked_option ( ' \0 ' , " proxy " ,
" HTTP proxy server for outgoing webhook requests in the format http://host:port " ,
[ & ] ( td : : Slice address ) {
if ( td : : begins_with ( address , " http:// " ) ) {
address . remove_prefix ( 7 ) ;
} else if ( td : : begins_with ( address , " https:// " ) ) {
address . remove_prefix ( 8 ) ;
}
return parameters - > webhook_proxy_ip_address_ . init_host_port ( address . str ( ) ) ;
} ) ;
2020-11-03 17:34:10 +01:00
options . add_check ( [ & ] {
if ( parameters - > api_id_ < = 0 | | parameters - > api_hash_ . empty ( ) ) {
return td : : Status : : Error ( " You must provide valid api-id and api-hash obtained at https://my.telegram.org " ) ;
}
return td : : Status : : OK ( ) ;
} ) ;
options . add_check ( [ & ] {
2021-02-14 23:23:18 +01:00
if ( default_verbosity_level < 0 ) {
2020-11-03 17:34:10 +01:00
return td : : Status : : Error ( " Wrong verbosity level specified " ) ;
}
return td : : Status : : OK ( ) ;
} ) ;
2021-02-14 23:23:18 +01:00
options . add_check ( [ & ] {
if ( memory_verbosity_level < 0 ) {
return td : : Status : : Error ( " Wrong memory verbosity level specified " ) ;
}
return td : : Status : : OK ( ) ;
} ) ;
2020-11-03 17:34:10 +01:00
auto r_non_options = options . run ( argc , argv , 0 ) ;
if ( need_print_usage ) {
LOG ( PLAIN ) < < options ;
return 0 ;
}
2021-05-10 17:49:50 +02:00
if ( need_print_version ) {
LOG ( PLAIN ) < < " Bot API " < < parameters - > version_ ;
return 0 ;
}
2020-11-03 17:34:10 +01:00
if ( r_non_options . is_error ( ) ) {
2021-06-14 20:24:20 +02:00
LOG ( PLAIN ) < < argv [ 0 ] < < " : " < < r_non_options . error ( ) . message ( ) ;
2020-11-03 17:34:10 +01:00
LOG ( PLAIN ) < < options ;
return 1 ;
}
2021-05-20 22:51:37 +02:00
td : : CombinedLog log ;
2020-11-03 17:34:10 +01:00
log . set_first ( td : : default_log_interface ) ;
log . set_second ( & memory_log ) ;
td : : log_interface = & log ;
2022-10-09 19:16:45 +02:00
td : : AsyncFileLog file_log ;
2020-11-03 17:34:10 +01:00
auto init_status = [ & ] {
2022-09-17 23:20:41 +02:00
# if TD_HAVE_THREAD_AFFINITY
if ( main_thread_affinity = = 0 ) {
main_thread_affinity = cpu_affinity ;
}
if ( main_thread_affinity ! = 0 ) {
auto initial_mask = td : : thread : : get_affinity_mask ( td : : this_thread : : get_id ( ) ) ;
if ( initial_mask = = 0 ) {
return td : : Status : : Error ( " Failed to get current thread affinity " ) ;
}
if ( cpu_affinity ! = 0 ) {
TRY_STATUS_PREFIX ( td : : thread : : set_affinity_mask ( td : : this_thread : : get_id ( ) , cpu_affinity ) ,
" Can't set CPU affinity mask: " ) ;
} else {
cpu_affinity = initial_mask ;
}
TRY_STATUS_PREFIX ( td : : thread : : set_affinity_mask ( td : : this_thread : : get_id ( ) , main_thread_affinity ) ,
" Can't set main thread CPU affinity mask: " ) ;
}
# endif
2020-11-03 17:34:10 +01:00
if ( max_connections ! = 0 ) {
TRY_STATUS_PREFIX ( td : : set_resource_limit ( td : : ResourceLimitType : : NoFile , max_connections ) ,
" Can't set file descriptor limit: " ) ;
}
if ( ! username . empty ( ) ) {
TRY_STATUS_PREFIX ( td : : change_user ( username , groupname ) , " Can't change effective user: " ) ;
}
2021-06-22 20:26:41 +02:00
{
TRY_RESULT_PREFIX_ASSIGN ( working_directory , td : : realpath ( working_directory , true ) ,
" Invalid working directory specified: " ) ;
if ( working_directory . empty ( ) ) {
2022-10-06 21:18:36 +02:00
return td : : Status : : Error ( " Empty path specified as working directory " ) ;
2021-06-22 20:26:41 +02:00
}
if ( working_directory . back ( ) ! = TD_DIR_SLASH ) {
working_directory + = TD_DIR_SLASH ;
}
TRY_STATUS_PREFIX ( td : : mkpath ( working_directory , 0750 ) , " Failed to create working directory: " ) ;
auto r_temp_file = td : : mkstemp ( working_directory ) ;
if ( r_temp_file . is_error ( ) ) {
return td : : Status : : Error ( PSLICE ( ) < < " Can't create files in the directory \" " < < working_directory
< < " \" . Use --dir option to specify a writable working directory " ) ;
}
r_temp_file . ok_ref ( ) . first . close ( ) ;
td : : unlink ( r_temp_file . ok ( ) . second ) . ensure ( ) ;
2021-06-23 01:03:22 +02:00
auto r_temp_dir = td : : mkdtemp ( working_directory , " 1:a " ) ;
if ( r_temp_dir . is_error ( ) ) {
parameters - > allow_colon_in_filenames_ = false ;
r_temp_dir = td : : mkdtemp ( working_directory , " 1~a " ) ;
if ( r_temp_dir . is_error ( ) ) {
return td : : Status : : Error ( PSLICE ( ) < < " Can't create directories in the directory \" " < < working_directory
< < " \" . Use --dir option to specify a writable working directory " ) ;
}
}
td : : rmdir ( r_temp_dir . ok ( ) ) . ensure ( ) ;
2020-11-03 17:34:10 +01:00
}
if ( ! temporary_directory . empty ( ) ) {
2021-06-22 20:26:41 +02:00
if ( td : : PathView ( temporary_directory ) . is_relative ( ) ) {
temporary_directory = working_directory + temporary_directory ;
}
2020-11-03 17:34:10 +01:00
TRY_STATUS_PREFIX ( td : : set_temporary_dir ( temporary_directory ) , " Can't set temporary directory: " ) ;
}
2021-06-22 20:26:41 +02:00
{ // check temporary directory
auto temp_dir = td : : get_temporary_dir ( ) ;
if ( temp_dir . empty ( ) ) {
return td : : Status : : Error ( " Can't find directory for temporary files. Use --temp-dir option to specify it " ) ;
}
2021-06-14 20:24:20 +02:00
2021-06-22 20:26:41 +02:00
auto r_temp_file = td : : mkstemp ( temp_dir ) ;
if ( r_temp_file . is_error ( ) ) {
return td : : Status : : Error ( PSLICE ( )
< < " Can't create files in the directory \" " < < temp_dir
< < " \" . Use --temp-dir option to specify another directory for temporary files " ) ;
}
r_temp_file . ok_ref ( ) . first . close ( ) ;
td : : unlink ( r_temp_file . ok ( ) . second ) . ensure ( ) ;
2021-06-14 20:24:20 +02:00
}
2020-11-03 17:34:10 +01:00
if ( ! log_file_path . empty ( ) ) {
2021-06-22 20:26:41 +02:00
if ( td : : PathView ( log_file_path ) . is_relative ( ) ) {
log_file_path = working_directory + log_file_path ;
}
2020-11-03 17:34:10 +01:00
TRY_STATUS_PREFIX ( file_log . init ( log_file_path , log_max_file_size ) , " Can't open log file: " ) ;
2022-10-09 19:16:45 +02:00
log . set_first ( & file_log ) ;
2020-11-03 17:34:10 +01:00
}
return td : : Status : : OK ( ) ;
} ( ) ;
if ( init_status . is_error ( ) ) {
2022-10-09 19:16:45 +02:00
LOG ( PLAIN ) < < init_status . message ( ) ;
2020-11-03 17:34:10 +01:00
LOG ( PLAIN ) < < options ;
return 1 ;
}
2021-06-22 20:26:41 +02:00
parameters - > working_directory_ = std : : move ( working_directory ) ;
2020-11-03 17:34:10 +01:00
if ( parameters - > default_max_webhook_connections_ < = 0 ) {
parameters - > default_max_webhook_connections_ = parameters - > local_mode_ ? 100 : 40 ;
}
: : td : : VERBOSITY_NAME ( dns_resolver ) = VERBOSITY_NAME ( WARNING ) ;
log . set_second_verbosity_level ( memory_verbosity_level ) ;
2021-02-14 23:23:18 +01:00
auto set_verbosity_level = [ & log , memory_verbosity_level ] ( int new_verbosity_level ) {
SET_VERBOSITY_LEVEL ( td : : max ( memory_verbosity_level , new_verbosity_level ) ) ;
2020-12-30 15:28:44 +01:00
log . set_first_verbosity_level ( new_verbosity_level ) ;
} ;
2021-02-14 23:23:18 +01:00
set_verbosity_level ( default_verbosity_level ) ;
2020-11-03 17:34:10 +01:00
// LOG(WARNING) << "Bot API server with commit " << td::GitInfo::commit() << ' '
// << (td::GitInfo::is_dirty() ? "(dirty)" : "") << " started";
2023-02-04 15:31:24 +01:00
LOG ( WARNING ) < < " TDLight Bot API " < < parameters - > version_ < < " server started " ;
2020-11-03 17:34:10 +01:00
2022-10-04 17:27:50 +02:00
// +3 threads for Td
// one thread for ClientManager and all Clients
2022-10-04 23:06:48 +02:00
// one thread for watchdogs
2022-10-04 17:27:50 +02:00
// one thread for slow HTTP connections
// one thread for DNS resolving
const int thread_count = 7 ;
2022-09-17 23:20:41 +02:00
td : : ConcurrentScheduler sched ( thread_count , cpu_affinity ) ;
2020-11-03 17:34:10 +01:00
td : : GetHostByNameActor : : Options get_host_by_name_options ;
2022-09-17 23:20:41 +02:00
get_host_by_name_options . scheduler_id = thread_count ;
2020-11-03 17:34:10 +01:00
parameters - > get_host_by_name_actor_id_ =
sched . create_actor_unsafe < td : : GetHostByNameActor > ( 0 , " GetHostByName " , std : : move ( get_host_by_name_options ) )
. release ( ) ;
auto client_manager =
2022-10-04 17:27:50 +02:00
sched . create_actor_unsafe < ClientManager > ( thread_count - 3 , " ClientManager " , std : : move ( parameters ) , token_range )
. release ( ) ;
2022-08-22 01:26:36 +02:00
2020-11-03 17:34:10 +01:00
sched
. create_actor_unsafe < HttpServer > (
2022-10-04 17:27:50 +02:00
thread_count - 3 , " HttpServer " , http_ip_address , http_port ,
2020-11-03 17:34:10 +01:00
[ client_manager , shared_data ] {
return td : : ActorOwn < td : : HttpInboundConnection : : Callback > (
td : : create_actor < HttpConnection > ( " HttpConnection " , client_manager , shared_data ) ) ;
} )
. release ( ) ;
2022-08-22 01:26:36 +02:00
2020-11-03 17:34:10 +01:00
if ( http_stat_port ! = 0 ) {
sched
. create_actor_unsafe < HttpServer > (
2022-10-04 17:27:50 +02:00
thread_count - 3 , " HttpStatsServer " , http_stat_ip_address , http_stat_port ,
2020-11-03 17:34:10 +01:00
[ client_manager ] {
return td : : ActorOwn < td : : HttpInboundConnection : : Callback > (
td : : create_actor < HttpStatConnection > ( " HttpStatConnection " , client_manager ) ) ;
} )
. release ( ) ;
}
2022-08-22 01:26:36 +02:00
2023-01-06 14:30:12 +01:00
constexpr double WATCHDOG_TIMEOUT = 0.25 ;
2022-08-22 01:26:36 +02:00
auto watchdog_id =
2022-09-17 23:20:41 +02:00
sched . create_actor_unsafe < Watchdog > ( thread_count - 2 , " Watchdog " , td : : this_thread : : get_id ( ) , WATCHDOG_TIMEOUT ) ;
2022-08-22 01:26:36 +02:00
2020-11-03 17:34:10 +01:00
sched . start ( ) ;
2022-08-22 01:26:36 +02:00
double next_watchdog_kick_time = start_time ;
2020-11-10 00:27:18 +01:00
double next_cron_time = start_time ;
2020-11-03 17:34:10 +01:00
double last_dump_time = start_time - 1000.0 ;
bool close_flag = false ;
std : : atomic_bool can_quit { false } ;
ServerCpuStat : : instance ( ) ; // create ServerCpuStat instance
while ( true ) {
2022-08-22 01:26:36 +02:00
sched . run_main ( td : : min ( next_cron_time , next_watchdog_kick_time ) - td : : Time : : now ( ) ) ;
2020-11-03 17:34:10 +01:00
2021-05-20 22:51:37 +02:00
if ( ! need_reopen_log . test_and_set ( ) ) {
td : : log_interface - > after_rotation ( ) ;
2020-11-03 17:34:10 +01:00
}
if ( ! need_quit . test_and_set ( ) ) {
if ( close_flag ) {
LOG ( WARNING ) < < " Receive stop signal again. Exit immediately... " ;
std : : _Exit ( 0 ) ;
}
2021-06-04 16:43:04 +02:00
LOG ( WARNING ) < < " Stopping engine with uptime " < < ( td : : Time : : now ( ) - start_time ) < < " seconds by a signal " ;
2020-11-03 17:34:10 +01:00
close_flag = true ;
auto guard = sched . get_main_guard ( ) ;
2022-08-22 01:26:36 +02:00
watchdog_id . reset ( ) ;
2020-11-03 17:34:10 +01:00
send_closure ( client_manager , & ClientManager : : close , td : : PromiseCreator : : lambda ( [ & can_quit ] ( td : : Unit ) {
can_quit . store ( true ) ;
td : : Scheduler : : instance ( ) - > yield ( ) ;
} ) ) ;
}
if ( can_quit . exchange ( false ) ) {
break ;
}
if ( ! need_change_verbosity_level . test_and_set ( ) ) {
2021-02-14 23:23:18 +01:00
if ( log . get_first_verbosity_level ( ) = = default_verbosity_level ) {
2020-12-30 15:28:44 +01:00
// increase default log verbosity level
set_verbosity_level ( 100 ) ;
} else {
// return back verbosity level
2021-02-14 23:23:18 +01:00
set_verbosity_level ( default_verbosity_level ) ;
2020-12-30 15:28:44 +01:00
}
2020-11-03 17:34:10 +01:00
}
auto next_verbosity_level = shared_data - > next_verbosity_level_ . exchange ( - 1 ) ;
if ( next_verbosity_level ! = - 1 ) {
2020-12-30 15:28:44 +01:00
set_verbosity_level ( next_verbosity_level ) ;
2020-11-03 17:34:10 +01:00
}
if ( ! need_dump_log . test_and_set ( ) ) {
print_log ( ) ;
2022-12-29 14:59:38 +01:00
need_dump_statistics . clear ( ) ;
2020-11-03 17:34:10 +01:00
}
double now = td : : Time : : now ( ) ;
2020-11-10 00:27:18 +01:00
if ( now > = next_cron_time ) {
2020-11-28 19:10:19 +01:00
if ( now > = next_cron_time + 1.0 ) {
next_cron_time = now ;
}
2020-11-10 00:27:18 +01:00
next_cron_time + = 1.0 ;
2020-11-03 17:34:10 +01:00
ServerCpuStat : : update ( now ) ;
}
2022-08-22 01:26:36 +02:00
if ( now > = start_time + 600 ) {
2020-11-03 17:34:10 +01:00
auto guard = sched . get_main_guard ( ) ;
2022-08-22 01:26:36 +02:00
send_closure ( watchdog_id , & Watchdog : : kick ) ;
next_watchdog_kick_time = now + WATCHDOG_TIMEOUT / 2 ;
2020-11-03 17:34:10 +01:00
}
2022-12-29 14:59:38 +01:00
if ( ! need_dump_statistics . test_and_set ( ) | | now > last_dump_time + 300.0 ) {
2020-11-03 17:34:10 +01:00
last_dump_time = now ;
2022-10-06 21:18:36 +02:00
auto guard = sched . get_main_guard ( ) ;
send_closure ( client_manager , & ClientManager : : dump_statistics ) ;
2020-11-03 17:34:10 +01:00
}
}
LOG ( WARNING ) < < " --------------------FINISH ENGINE-------------------- " ;
2022-10-06 21:18:36 +02:00
if ( net_query_stats . use_count ( ) ! = 1 ) {
LOG ( ERROR ) < < " NetQueryStats have leaked " ;
}
2020-11-03 17:34:10 +01:00
net_query_stats = nullptr ;
sched . finish ( ) ;
SET_VERBOSITY_LEVEL ( VERBOSITY_NAME ( FATAL ) ) ;
td : : log_interface = td : : default_log_interface ;
return 0 ;
}
} // namespace telegram_bot_api
int main ( int argc , char * argv [ ] ) {
return telegram_bot_api : : main ( argc , argv ) ;
}