38 voice_connections_map voiceConnectionMap{};
39 sound_cloud_apimap soundCloudAPIMap{};
40 you_tube_apimap youtubeAPIMap{};
41 song_apimap songAPIMap{};
42 std::atomic_bool doWeQuit{};
44 discord_core_internal::sound_cloud_api& discord_core_client::getSoundCloudAPI(snowflake guildId) {
45 if (!soundCloudAPIMap.contains(guildId.operator
const uint64_t&())) {
46 soundCloudAPIMap[guildId.operator
const uint64_t&()] = makeUnique<discord_core_internal::sound_cloud_api>(&getInstance()->configManager, guildId);
48 return *soundCloudAPIMap[guildId.operator
const uint64_t&()].get();
51 discord_core_internal::you_tube_api& discord_core_client::getYouTubeAPI(snowflake guildId) {
52 if (!youtubeAPIMap.contains(guildId.operator
const uint64_t&())) {
53 youtubeAPIMap[guildId.operator
const uint64_t&()] = makeUnique<discord_core_internal::you_tube_api>(&getInstance()->configManager, guildId);
55 return *youtubeAPIMap[guildId.operator
const uint64_t&()].get();
58 voice_connection& discord_core_client::getVoiceConnection(snowflake guildId) {
59 if (!voiceConnectionMap.contains(guildId.operator
const uint64_t&())) {
60 uint64_t theShardId{ (guildId.operator
const uint64_t&() >> 22) % getInstance()->configManager.getTotalShardCount() };
61 uint64_t baseSocketIndex{ theShardId % getInstance()->baseSocketAgentsMap.size() };
62 voiceConnectionMap[guildId.operator
const uint64_t&()] =
63 makeUnique<voice_connection>(&getInstance()->baseSocketAgentsMap[baseSocketIndex]->shardMap[theShardId], &doWeQuit);
65 return *voiceConnectionMap[guildId.operator
const uint64_t&()].get();
68 song_api& discord_core_client::getSongAPI(snowflake guildId) {
69 if (!songAPIMap.contains(guildId.operator
const uint64_t&())) {
70 songAPIMap[guildId.operator
const uint64_t&()] = makeUnique<song_api>(guildId);
72 return *songAPIMap[guildId.operator
const uint64_t&()].get();
75 discord_core_client* discord_core_client::getInstance() {
76 return instancePtr.get();
80 void atexitHandler() noexcept {
81 doWeQuit.store(
true, std::memory_order_release);
84 void signalHandler(int32_t value)
noexcept {
87 message_printer::printError<print_message_type::general>(
"SIGTERM ERROR.");
91 message_printer::printError<print_message_type::general>(
"SIGSEGV ERROR.");
95 message_printer::printError<print_message_type::general>(
"SIGINT ERROR.");
99 message_printer::printError<print_message_type::general>(
"SIGILL ERROR.");
103 message_printer::printError<print_message_type::general>(
"SIGABRT ERROR.");
107 message_printer::printError<print_message_type::general>(
"SIGFPE ERROR.");
114 instancePtr.reset(
this);
115 std::atexit(&atexitHandler);
116 std::signal(SIGTERM, &signalHandler);
117 std::signal(SIGSEGV, &signalHandler);
118 std::signal(SIGINT, &signalHandler);
119 std::signal(SIGILL, &signalHandler);
120 std::signal(SIGABRT, &signalHandler);
121 std::signal(SIGFPE, &signalHandler);
123 if (!discord_core_internal::ssl_context_holder::initialize()) {
124 message_printer::printError<print_message_type::general>(
"Failed to initialize the SSL_CTX structure!");
127 if (sodium_init() == -1) {
128 message_printer::printError<print_message_type::general>(
"Lib_sodium failed to initialize!");
131 httpsClient = makeUnique<discord_core_internal::https_client>(jsonifier::string{ configManager.getBotToken() });
132 application_commands::initialize(httpsClient.get());
133 auto_moderation_rules::initialize(httpsClient.get());
134 channels::initialize(httpsClient.get(), &configManager);
135 guilds::initialize(httpsClient.get(), &configManager);
136 guild_members::initialize(httpsClient.get(), &configManager);
137 guild_scheduled_events::initialize(httpsClient.get());
138 interactions::initialize(httpsClient.get());
139 messages::initialize(httpsClient.get());
140 reactions::initialize(httpsClient.get());
141 roles::initialize(httpsClient.get(), &configManager);
142 stickers::initialize(httpsClient.get());
143 stage_instances::initialize(httpsClient.get());
144 threads::initialize(httpsClient.get());
145 web_hooks::initialize(httpsClient.get());
146 users::initialize(httpsClient.get(), &configManager);
150 return configManager;
154 return discord_core_client::currentUser;
159 if (!instantiateWebSockets()) {
160 doWeQuit.store(
true, std::memory_order_release);
164 std::this_thread::sleep_for(1ms);
166 registerFunctionsInternal();
167 while (!doWeQuit.load(std::memory_order_acquire)) {
168 std::this_thread::sleep_for(1ms);
171 message_printer::printError<print_message_type::general>(error.what());
177 commandData.alwaysRegister = alwaysRegister;
179 commandsToRegister.emplace_back(commandData);
183 return commandController;
191 return std::chrono::duration_cast<milliseconds>(hrclock::now().time_since_epoch()) - startupTimeSinceEpoch;
194 void discord_core_client::registerFunctionsInternal() {
196 jsonifier::vector<application_command_data> theCommands{
199 while (commandsToRegister.size() > 0) {
200 create_application_command_data data = commandsToRegister.front();
201 commandsToRegister.pop_front();
203 if (data.alwaysRegister) {
204 if (data.guildId != 0) {
210 jsonifier::vector<application_command_data> guildCommands{};
211 if (data.guildId != 0) {
216 for (
auto& value: theCommands) {
222 for (
auto& value: guildCommands) {
230 if (data.guildId != 0) {
237 }
catch (dca_exception& error) {
238 message_printer::printError<print_message_type::https>(error.what());
245 gateway_bot_data discord_core_client::getGateWayBot() {
246 discord_core_internal::https_workload_data workload{ discord_core_internal::https_workload_type::Get_Gateway_Bot };
247 workload.workloadClass = discord_core_internal::https_workload_class::Get;
248 workload.relativePath =
"/gateway/bot";
249 workload.callStack =
"discord_core_client::getGateWayBot()";
250 gateway_bot_data data{};
251 httpsClient->submitWorkloadAndGetResult(workload, data);
255 bool discord_core_client::instantiateWebSockets() {
256 gateway_bot_data gatewayData{};
258 gatewayData = getGateWayBot();
259 }
catch (
const discord_core_internal::https_error& error) {
260 message_printer::printError<print_message_type::general>(error.what());
264 if (gatewayData.url ==
"") {
265 message_printer::printError<print_message_type::general>(
"Failed to collect the connection url! closing! did you remember to "
266 "properly set your bot token?");
267 std::this_thread::sleep_for(5s);
270 if (configManager.getStartingShard() + configManager.getShardCountForThisProcess() > configManager.getTotalShardCount()) {
271 message_printer::printError<print_message_type::general>(
"your sharding options are incorrect! please fix it!");
272 std::this_thread::sleep_for(5s);
275 uint64_t workerCount = configManager.getTotalShardCount() <= std::jthread::hardware_concurrency() ? configManager.getTotalShardCount()
276 :
static_cast<uint64_t
>(std::jthread::hardware_concurrency());
278 if (configManager.getConnectionAddress() ==
"") {
279 configManager.setConnectionAddress(gatewayData.url.substr(gatewayData.url.find(
"wss://") + jsonifier::string{
"wss://" }.size()));
281 if (configManager.getConnectionPort() == 0) {
282 configManager.setConnectionPort(443);
284 areWeReadyToConnect.store(
false, std::memory_order_release);
285 baseSocketAgentsMap.reserve(workerCount);
286 for (uint64_t x = 0; x < configManager.getTotalShardCount(); ++x) {
287 if (baseSocketAgentsMap.size() < workerCount) {
288 baseSocketAgentsMap[x] = makeUnique<discord_core_internal::base_socket_agent>(&doWeQuit);
289 baseSocketAgentsMap[x]->shardMap.reserve(configManager.getTotalShardCount() / workerCount);
291 baseSocketAgentsMap[x % workerCount]->shardMap[x] = discord_core_internal::websocket_client{ x, &doWeQuit };
293 areWeReadyToConnect.store(
true, std::memory_order_release);
294 while (!areWeFullyConnected()) {
295 std::this_thread::sleep_for(1ms);
297 for (
auto& value: configManager.getFunctionsToExecute()) {
298 executeFunctionAfterTimePeriod(value.function, value.intervalInMs, value.repeated,
false,
this);
300 startupTimeSinceEpoch = std::chrono::duration_cast<milliseconds>(hrclock::now().time_since_epoch());
304 bool discord_core_client::areWeFullyConnected() {
305 for (
auto& [key, value]: baseSocketAgentsMap) {
306 for (
auto& [keyNew, valueNew]: value->shardMap) {
307 if (!valueNew.areWeConnected()) {
315 discord_core_client::~discord_core_client() {
316 instancePtr.release();
319 bot_user discord_core_client::currentUser{};
static co_routine< jsonifier::vector< application_command_data > > getGlobalApplicationCommandsAsync(const get_global_application_commands_data dataPackage)
Get all of the global application_commands for this bot.
static co_routine< application_command_data > createGlobalApplicationCommandAsync(create_global_application_command_data dataPackage)
Create a global application_command_data for this bot.
static co_routine< application_command_data > createGuildApplicationCommandAsync(create_guild_application_command_data dataPackage)
Create a guild application_command_data for a single server for this bot.
static co_routine< jsonifier::vector< application_command_data > > getGuildApplicationCommandsAsync(const get_guild_application_commands_data dataPackage)
Get all of the guild application_commands for a single guild for this bot.
A type of user_data, to represent the bot and some of its associated endpoints.
A class for handling commands from user input.
void registerFunction(const jsonifier::vector< jsonifier::string > &functionNames, unique_ptr< base_function > baseFunction)
Registers a function to be called.
command_controller & getCommandController()
For collecting a reference to the command_controller.
event_manager & getEventManager()
For collecting a reference to the event_manager.
void runBot()
Executes the library, and waits for completion.
discord_core_client(const discord_core_client_config &configData)
discord_core_client constructor.
void registerFunction(const jsonifier::vector< jsonifier::string > &functionNames, unique_ptr< base_function > baseFunction, create_application_command_data commandData, bool alwaysRegister=false)
For registering a function with the command_controller.
static bot_user getBotUser()
For collecting a copy of the current bot's user_data.
milliseconds getTotalUpTime()
For collecting, the total time in milliseconds that this bot has been up for.
event_manager eventManager
An event-manager, for hooking into discord-api-events sent over the websockets.
const config_manager & getConfigManager() const
For collecting a reference to the config_manager.
Class for handling the assignment of event-handling functions.int32_t.
static void initialize(const value_type &other)
Initialize the message_printer with configuration settings and output/error streams.
A smart pointer class that provides unique ownership semantics.
snowflake id
The user's id.
The main namespace for the forward-facing interfaces.
For creating an application command.
An exception class derived from std::runtime_error for dca-related exceptions.
Configuration data for the library's main class, discord_core_client.