diff --git a/.vscode/settings.json b/.vscode/settings.json index 21ab674e7d..90c8db6d31 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -80,6 +80,7 @@ "numbers": "cpp", "semaphore": "cpp", "stop_token": "cpp", - "charconv": "cpp" + "charconv": "cpp", + "any": "cpp" } } \ No newline at end of file diff --git a/include/dpp/event_router.h b/include/dpp/event_router.h index 5a16aaa74b..33793144f1 100644 --- a/include/dpp/event_router.h +++ b/include/dpp/event_router.h @@ -305,7 +305,7 @@ template class event_router_t { if (std::holds_alternative(listener)) { std::get(listener)(event); } else { - throw dpp::logic_exception("cannot handle a coroutine event handler with a library built without DPP_CORO"); + throw dpp::logic_exception("cannot handle a coroutine event handler with a library built without DPP_CORO"); } } }; diff --git a/include/dpp/exception.h b/include/dpp/exception.h index b389ecc1c7..0b9167e6fa 100644 --- a/include/dpp/exception.h +++ b/include/dpp/exception.h @@ -27,6 +27,359 @@ namespace dpp { +/** + * @brief Exception error codes possible for dpp::exception::code() + * + * This list is a combined list of Discord's error codes, HTTP error codes, + * zlib, opus, sodium and C library codes (e.g. DNS, socket etc). You may + * use these to easily identify a type of exception without having to resort + * to string comparison against dpp::exception::what() + * + * For detailed descriptions of each error code, see the text description + * returned in `what()`. + * + * @note Some exceptions MAY have error codes which are NOT in this list + * in the event a C library is updated and adds new codes we did not document + * here. In this case, or where the code is not specific, refer to `what()`. + */ +enum exception_error_code { + err_this_is_not_an_error = 0, + err_zlib_see_errno = -1, + err_zlib_init_stream = -2, + err_zlib_init_data = -3, + err_zlib_init_mem = -4, + err_zlib_init_buffer = -5, + err_zlib_init_version = -6, + err_opus_bad_arg = -11, + err_opus_buffer_too_small = -12, + err_opus_internal_error = -13, + err_opus_invalid_packet = -14, + err_opus_unimplemented = -15, + err_opus_invalid_state = -16, + err_opus_alloc_fail = -17, + err_dns_bad_flags = -21, + err_name_or_service_unknown = -22, + err_dns_again = -23, + err_dns_fail = -24, + err_dns_family = -26, + err_dns_socket_type = -27, + err_dns_service = -28, + err_dns_memory = -30, + err_dns_system_error = -31, + err_dns_overflow = -32, + err_ssl_new = 1, + err_ssl_connect = 2, + err_write = 3, + err_ssl_write = 4, + err_no_sessions_left = 5, + err_auto_shard = 6, + err_reconnection = 7, + err_bind_failure = 8, + err_nonblocking_failure = 9, + err_voice_terminating = 10, + err_connect_failure = 11, + err_ssl_context = 12, + err_ssl_version = 13, + err_invalid_socket = 14, + err_socket_error = 15, + err_websocket_proto_already_set = 16, + err_command_handler_not_ready = 17, + err_no_owning_message = 18, + err_cancelled_event = 19, + err_event_status = 20, + err_event_start_time = 21, + err_event_end_time = 22, + err_command_has_caps = 23, + err_choice_autocomplete = 24, + err_interaction = 25, + err_too_many_component_rows = 26, + err_invalid_webhook = 27, + err_voice_state_timestamp = 28, + err_no_voice_support = 29, + err_invalid_voice_packet_length = 30, + err_opus = 31, + err_sodium = 32, + err_etf = 33, + err_cache = 34, + err_icon_size = 35, + err_massive_audio = 36, + err_unknown = 37, + err_bad_request = 400, + err_unauthorized = 401, + err_payment_requred = 402, + err_forbidden = 403, + err_not_found = 404, + err_method_not_allowed = 405, + err_not_acceptable = 406, + err_proxy_auth_required = 407, + err_request_timeout = 408, + err_conflict = 409, + err_gone = 410, + err_length_required = 411, + err_precondition_failed = 412, + err_payload_too_large = 413, + err_uri_too_long = 414, + err_unsupported_media_type = 415, + err_range_not_satisfiable = 416, + err_expectation_failed = 417, + err_im_a_teapot = 418, + err_page_expired = 419, + err_twitter_rate_limited = 420, + err_misdirected_request = 421, + err_unprocessable_content = 422, + err_webdav_locked = 423, + err_webdav_failed_dependency = 424, + err_too_early = 425, + err_upgrade_required = 426, + err_precondition_required = 428, + err_rate_limited = 429, + err_request_headers_too_large = 431, + err_page_blocked = 450, + err_unavailable_for_legal_reasons = 451, + err_http_request_on_https_port = 497, + err_internal_server_error = 500, + err_not_implemented = 501, + err_bad_gateway = 502, + err_service_unavailable = 503, + err_gateway_timeout = 504, + err_http_version_not_supported = 505, + err_variant_also_negotiates = 506, + err_webdav_insufficient_storage = 507, + err_webdav_loop_detected = 508, + err_bandwidth_limit_exceeded = 509, + err_not_extended = 510, + err_network_auth_required = 511, + err_web_server_down = 521, + err_connection_timed_out = 522, + err_origin_unreachable = 523, + err_timeout = 524, + err_ssl_handshake_failed = 525, + err_invalid_ssl_certificate = 526, + err_railgun = 527, + err_cloudflare = 530, + err_websocket_unknown = 4000, + err_websocket_bad_opcode= 4001, + err_websocket_decode = 4002, + err_websocket_not_authenticated = 4003, + err_websocket_authentication_failed = 4004, + err_websocket_already_authenticated = 4005, + err_websocket_invalid_seq_number = 4007, + err_websocket_rate_limited = 4008, + err_websocket_session_timeout = 4009, + err_websocket_invalid_shard = 4010, + err_websocket_sharding_required = 4011, + err_websocket_invalid_api_version = 4012, + err_websocket_invalid_intents = 4013, + err_websocket_disallowed_intents = 4014, + err_websocket_voice_disconnected = 4014, + err_websocket_voice_server_crashed = 4015, + err_websocket_voice_unknown_encryption = 4016, + err_compression_stream = 6000, + err_compression_data = 6001, + err_compression_memory = 6002, + err_unknown_account = 10001, + err_unknown_application = 10002, + err_unknown_channel = 10003, + err_unknown_guild = 10004, + err_unknown_integration = 10005, + err_unknown_invite = 10006, + err_unknown_member = 10007, + err_unknown_message = 10008, + err_unknown_permission_overwrite = 10009, + err_unknown_provider = 10010, + err_unknown_role = 10011, + err_unknown_token = 10012, + err_unknown_user = 10013, + err_unknown_emoji = 10014, + err_unknown_webhook = 10015, + err_unknown_webhook_service = 10016, + err_unknown_session = 10020, + err_unknown_ban = 10026, + err_unknown_sku = 10027, + err_unknown_store_listing = 10028, + err_unknown_entitlement = 10029, + err_unknown_build = 10030, + err_unknown_lobby = 10031, + err_unknown_branch = 10032, + err_unknown_store_directory_layout = 10033, + err_unknown_redistributable = 10036, + err_unknown_gift_code = 10038, + err_unknown_stream = 10049, + err_unknown_premium_server_subscribe_cooldown = 10050, + err_unknown_guild_template = 10057, + err_unknown_discoverable_server_category = 10059, + err_unknown_sticker = 10060, + err_unknown_interaction = 10062, + err_unknown_application_command = 10063, + err_unknown_voice_state = 10065, + err_unknown_application_command_permissions = 10066, + err_unknown_stage_instance = 10067, + err_unknown_guild_member_verification_form = 10068, + err_unknown_guild_welcome_screen = 10069, + err_unknown_guild_scheduled_event = 10070, + err_unknown_guild_scheduled_event_user = 10071, + err_unknown_tag = 10087, + err_bots_cannot_use_this_endpoint = 20001, + err_only_bots_can_use_this_endpoint = 20002, + err_explicit_content = 20009, + err_unauthorized_for_application = 20012, + err_slowmode_rate_limit = 20016, + err_owner_only = 20018, + err_announcement_rate_limit = 20022, + err_under_minimum_age = 20024, + err_write_rate_limit = 20029, + err_stage_banned_words = 20031, + err_guild_premium_subscription_level_too_low = 20035, + err_guilds = 30001, + err_friends = 30002, + err_pins_for_the_channel = 30003, + err_recipients = 30004, + err_guild_roles = 30005, + err_webhooks = 30007, + err_emojis = 30008, + err_reactions = 30010, + err_group_dms = 30011, + err_guild_channels = 30013, + err_attachments_in_a_message = 30015, + err_invites = 30016, + err_animated_emojis = 30018, + err_server_members = 30019, + err_server_categories = 30030, + err_guild_already_has_a_template = 30031, + err_application_commands = 30032, + err_thread_participants = 30033, + err_daily_application_command_creates = 30034, + err_bans_for_non_guild_members_have_been_exceeded = 30035, + err_bans_fetches = 30037, + err_uncompleted_guild_scheduled_events = 30038, + err_stickers = 30039, + err_prune_requests = 30040, + err_guild_widget_settings_updates = 30042, + err_edits_to_messages_older_than_1_hour = 30046, + err_pinned_threads_in_a_forum_channel = 30047, + err_tags_in_a_forum_channel = 30048, + err_bitrate_is_too_high_for_channel_of_this_type = 30052, + err_premium_emojis = 30056, + err_webhooks_per_guild = 30058, + err_channel_permission_overwrites = 30060, + err_the_channels_for_this_guild_are_too_large = 30061, + err_unauthorized_invalid_token = 40001, + err_verify_your_account = 40002, + err_you_are_opening_direct_messages_too_fast = 40003, + err_send_messages_has_been_temporarily_disabled = 40004, + err_request_entity_too_large = 40005, + err_this_feature_has_been_temporarily_disabled_server_side = 40006, + err_the_user_is_banned_from_this_guild = 40007, + err_connection_has_been_revoked = 40012, + err_target_user_is_not_connected_to_voice = 40032, + err_this_message_has_already_been_crossposted = 40033, + err_an_application_command_with_that_name_already_exists = 40041, + err_application_interaction_failed_to_send = 40043, + err_cannot_send_a_message_in_a_forum_channel = 40058, + err_interaction_has_already_been_acknowledged = 40060, + err_tag_names_must_be_unique = 40061, + err_service_resource_is_being_rate_limited = 40062, + err_no_tags_available = 40066, + err_tag_required = 40067, + err_entitlement_already_granted = 40074, + err_missing_access = 50001, + err_invalid_account_type = 50002, + err_cannot_execute_action_on_a_dm_channel = 50003, + err_guild_widget_disabled = 50004, + err_cannot_edit_a_message_by_other_user = 50005, + err_cannot_send_empty_message = 50006, + err_cannot_send_messages_to_this_user = 50007, + err_cannot_send_messages_in_a_non_text_channel = 50008, + err_channel_verification_level_too_high = 50009, + err_oauth2_application_does_not_have_a_bot = 50010, + err_oauth2_application_limit = 50011, + err_invalid_oauth2_state = 50012, + err_permissions = 50013, + err_invalid_authentication_token = 50014, + err_note_was_too_long = 50015, + err_too_few_or_too_many_messages = 50016, + err_invalid_mfa_level = 50017, + err_invalid_pin = 50019, + err_invite_code_invalid = 50020, + err_system_message = 50021, + err_channel_type = 50024, + err_invalid_oauth2_access_token = 50025, + err_missing_required_oauth2_scope = 50026, + err_invalid_webhook_token = 50027, + err_invalid_role = 50028, + err_invalid_recipients = 50033, + err_too_old_to_bulk_delete = 50034, + err_invalid_form_body = 50035, + err_invite_error = 50036, + err_invalid_activity_action = 50039, + err_invalid_api_version_provided = 50041, + err_file_uploaded_exceeds_the_maximum_size = 50045, + err_invalid_file_uploaded = 50046, + err_cannot_self_redeem_this_gift = 50054, + err_invalid_guild = 50055, + err_invalid_sku = 50057, + err_invalid_request_origin = 50067, + err_invalid_message_type = 50068, + err_payment_source_required = 50070, + err_cannot_modify_a_system_webhook = 50073, + err_cannot_delete_a_channel_required_for_community_guilds = 50074, + err_cannot_edit_stickers_within_a_message = 50080, + err_invalid_sticker_sent = 50081, + err_tried_to_perform_an_operation_on_an_archived_thread = 50083, + err_invalid_thread_notification_settings = 50084, + err_before_value_is_earlier_than_the_thread_creation_date = 50085, + err_community_server_channels_must_be_text_channels = 50086, + err_bad_event_entity_type = 50091, + err_this_server_is_not_available_in_your_location = 50095, + err_monetization_enabled_in_order_to_perform_this_action = 50097, + err_more_boosts_to_perform_this_action = 50101, + err_the_request_body_contains_invalid_json = 50109, + err_owner_cannot_be_pending_member = 50131, + err_ownership_cannot_be_transferred_to_a_bot_user = 50132, + err_failed_to_resize_asset_below_the_maximum_size = 50138, + err_cannot_mix_subscription_and_non_subscription_roles_for_an_emoji = 50144, + err_cannot_convert_between_premium_emoji_and_normal_emoji = 50145, + err_uploaded_file_not_found = 50146, + err_voice_messages_do_not_support_additional_content = 50159, + err_voice_messages_must_have_a_single_audio_attachment = 50160, + err_voice_messages_must_have_supporting_metadata = 50161, + err_voice_messages_cannot_be_edited = 50162, + err_cannot_delete_guild_subscription_integration = 50163, + err_you_cannot_send_voice_messages_in_this_channel = 50173, + err_the_user_account_must_first_be_verified = 50178, + err_you_do_not_have_permission_to_send_this_sticker = 50600, + err_two_factor_is_required_for_this_operation = 60003, + err_no_users_with_discordtag_exist = 80004, + err_reaction_was_blocked = 90001, + err_user_cannot_use_burst_reactions = 90002, + err_application_not_yet_available = 110001, + err_api_resource_is_currently_overloaded = 130000, + err_the_stage_is_already_open = 150006, + err_cannot_reply_without_permission_to_read_message_history = 160002, + err_a_thread_has_already_been_created_for_this_message = 160004, + err_thread_is_locked = 160005, + err_active_threads = 160006, + err_active_announcement_threads = 160007, + err_invalid_json_for_uploaded_lottie_file = 170001, + err_uploaded_lotties_cannot_contain_rasterized_images = 170002, + err_sticker_maximum_framerate = 170003, + err_sticker_frame_count = 170004, + err_lottie_animation_dimensions = 170005, + err_sticker_frame_rate = 170006, + err_sticker_animation_duration = 170007, + err_cannot_update_a_finished_event = 180000, + err_failed_to_create_stage_needed_for_stage_event = 180002, + err_message_was_blocked_by_automatic_moderation = 200000, + err_title_was_blocked_by_automatic_moderation = 200001, + err_webhooks_posted_to_forum_channels_must_have_a_thread_name_or_thread_id = 220001, + err_webhooks_posted_to_forum_channels_cannot_have_both_a_thread_name_and_thread_id = 220002, + err_webhooks_can_only_create_threads_in_forum_channels = 220003, + err_webhook_services_cannot_be_used_in_forum_channels = 220004, + err_message_blocked_links = 240000, + err_cannot_enable_onboarding_requirements_are_not_met = 350000, + err_cannot_update_onboarding_below_requirements = 350001, +}; + /** * @brief The dpp::exception class derives from std::exception and supports some other * ways of passing in error details such as via std::string. @@ -39,6 +392,11 @@ class exception : public std::exception */ std::string msg; + /** + * @brief Exception error code + */ + exception_error_code error_code; + public: using std::exception::exception; @@ -53,7 +411,15 @@ class exception : public std::exception * * @param what reason message */ - explicit exception(const char* what) : msg(what) { } + explicit exception(const char* what) : msg(what), error_code(err_this_is_not_an_error) { } + + /** + * @brief Construct a new exception object + * + * @param what reason message + * @param code Exception code + */ + explicit exception(exception_error_code code, const char* what) : msg(what), error_code(code) { } /** * @brief Construct a new exception object @@ -61,14 +427,22 @@ class exception : public std::exception * @param what reason message * @param len length of reason message */ - exception(const char* what, size_t len) : msg(what, len) { } + exception(const char* what, size_t len) : msg(what, len), error_code(err_this_is_not_an_error) { } /** * @brief Construct a new exception object * * @param what reason message */ - explicit exception(const std::string& what) : msg(what) { } + explicit exception(const std::string& what) : msg(what), error_code(err_this_is_not_an_error) { } + + /** + * @brief Construct a new exception object + * + * @param what reason message + * @param code Exception code + */ + explicit exception(exception_error_code code, const std::string& what) : msg(what), error_code(code) { } /** * @brief Construct a new exception object @@ -77,6 +451,14 @@ class exception : public std::exception */ explicit exception(std::string&& what) : msg(std::move(what)) { } + /** + * @brief Construct a new exception object + * + * @param what reason message + * @param code Exception code + */ + explicit exception(exception_error_code code, std::string&& what) : msg(std::move(what)), error_code(code) { } + /** * @brief Construct a new exception object (copy constructor) */ @@ -113,6 +495,13 @@ class exception : public std::exception */ [[nodiscard]] const char* what() const noexcept override { return msg.c_str(); }; + /** + * @brief Get exception code + * + * @return exception_error_code error code + */ + [[nodiscard]] exception_error_code code() const noexcept { return error_code; }; + }; #ifndef _DOXYGEN_ @@ -121,15 +510,19 @@ class exception : public std::exception using dpp::ancestor::ancestor; \ name() = default; \ explicit name(const char* what) : ancestor(what) { } \ + explicit name(exception_error_code code, const char* what) : ancestor(code, what) { } \ name(const char* what, size_t len) : ancestor(what, len) { } \ explicit name(const std::string& what) : ancestor(what) { } \ + explicit name(exception_error_code code, const std::string& what) : ancestor(code, what) { } \ explicit name(std::string&& what) : ancestor(what) { } \ + explicit name(exception_error_code code, std::string&& what) : ancestor(code, what) { } \ name(const name&) = default; \ name(name&&) = default; \ ~name() override = default; \ name & operator = (const name &) = default; \ name & operator = (name&&) = default; \ [[nodiscard]] const char* what() const noexcept override { return msg.c_str(); }; \ + [[nodiscard]] exception_error_code code() const noexcept { return error_code; }; \ }; #endif diff --git a/include/dpp/sync.h b/include/dpp/sync.h index 035a205778..707d7109fd 100644 --- a/include/dpp/sync.h +++ b/include/dpp/sync.h @@ -27,54 +27,55 @@ namespace dpp { - /** - * @brief Call a D++ REST function synchronously. - * - * Synchronously calling a REST function means *IT WILL BLOCK* - This is a Bad Thing™ and strongly discouraged. - * There are very few circumstances you actually need this. If you do need to use this, you'll know it. - * - * Example: - * - * ```cpp - * dpp::message m = dpp::sync(&bot, &dpp::cluster::message_create, dpp::message(channel_id, "moo.")); - * ``` - * - * @warning As previously mentioned, this template will block. It is ill-advised to call this outside of - * a separate thread and this should never be directly used in any event such as dpp::cluster::on_interaction_create! - * @tparam T type of expected return value, should match up with the method called - * @tparam F Type of class method in dpp::cluster to call. - * @tparam Ts Function parameters in method call - * @param c A pointer to dpp::cluster object - * @param func pointer to class method in dpp::cluster to call. This can call any - * dpp::cluster member function who's last parameter is a dpp::command_completion_event_t callback type. - * @param args Zero or more arguments for the method call - * @return An instantiated object of type T - * @throw dpp::rest_exception On failure of the method call, an exception is thrown - */ - template T sync(class cluster* c, F func, Ts&&... args) { - std::promise _p; - std::future _f = _p.get_future(); - /* (obj ->* func) is the obscure syntax for calling a method pointer on an object instance */ - (c ->* func)(std::forward(args)..., [&_p](const auto& cc) { - try { - if (cc.is_error()) { - throw dpp::rest_exception(cc.get_error().message); - } else { - try { - _p.set_value(std::get(cc.value)); - } catch (const std::exception& e) { - throw dpp::rest_exception(e.what()); - } - } - } catch (const dpp::rest_exception&) { - _p.set_exception(std::current_exception()); - } - }); + /** + * @brief Call a D++ REST function synchronously. + * + * Synchronously calling a REST function means *IT WILL BLOCK* - This is a Bad Thing™ and strongly discouraged. + * There are very few circumstances you actually need this. If you do need to use this, you'll know it. + * + * Example: + * + * ```cpp + * dpp::message m = dpp::sync(&bot, &dpp::cluster::message_create, dpp::message(channel_id, "moo.")); + * ``` + * + * @warning As previously mentioned, this template will block. It is ill-advised to call this outside of + * a separate thread and this should never be directly used in any event such as dpp::cluster::on_interaction_create! + * @tparam T type of expected return value, should match up with the method called + * @tparam F Type of class method in dpp::cluster to call. + * @tparam Ts Function parameters in method call + * @param c A pointer to dpp::cluster object + * @param func pointer to class method in dpp::cluster to call. This can call any + * dpp::cluster member function who's last parameter is a dpp::command_completion_event_t callback type. + * @param args Zero or more arguments for the method call + * @return An instantiated object of type T + * @throw dpp::rest_exception On failure of the method call, an exception is thrown + */ + template T sync(class cluster* c, F func, Ts&&... args) { + std::promise _p; + std::future _f = _p.get_future(); + /* (obj ->* func) is the obscure syntax for calling a method pointer on an object instance */ + (c ->* func)(std::forward(args)..., [&_p](const auto& cc) { + try { + if (cc.is_error()) { + const auto& error = cc.get_error(); + throw dpp::rest_exception((exception_error_code)error.code, error.message); + } else { + try { + _p.set_value(std::get(cc.value)); + } catch (const std::exception& e) { + throw dpp::rest_exception(err_unknown, e.what()); + } + } + } catch (const dpp::rest_exception&) { + _p.set_exception(std::current_exception()); + } + }); - /* Blocking calling thread until rest request is completed. - * Exceptions encountered on the other thread are re-thrown. - */ - return _f.get(); - } + /* Blocking calling thread until rest request is completed. + * Exceptions encountered on the other thread are re-thrown. + */ + return _f.get(); + } } // namespace dpp diff --git a/src/dpp/cluster.cpp b/src/dpp/cluster.cpp index ece2949d9f..e8a13a9bab 100644 --- a/src/dpp/cluster.cpp +++ b/src/dpp/cluster.cpp @@ -142,7 +142,7 @@ request_queue* cluster::get_raw_rest() { cluster& cluster::set_websocket_protocol(websocket_protocol_t mode) { if (start_time > 0) { - throw dpp::logic_exception("Cannot change websocket protocol on a started cluster!"); + throw dpp::logic_exception(err_websocket_proto_already_set, "Cannot change websocket protocol on a started cluster!"); } ws_mode = mode; return *this; @@ -177,7 +177,7 @@ void cluster::start(bool return_after) { g = dpp::sync(this, &cluster::get_gateway_bot); log(ll_debug, "Cluster: " + std::to_string(g.session_start_remaining) + " of " + std::to_string(g.session_start_total) + " session starts remaining"); if (g.session_start_remaining < g.shards) { - throw dpp::connection_exception("Discord indicates you cannot start enough sessions to boot this cluster! Cluster startup aborted. Try again later."); + throw dpp::connection_exception(err_no_sessions_left, "Discord indicates you cannot start enough sessions to boot this cluster! Cluster startup aborted. Try again later."); } if (g.session_start_max_concurrency > 1) { log(ll_debug, "Cluster: Large bot sharding; Using session concurrency: " + std::to_string(g.session_start_max_concurrency)); @@ -186,7 +186,7 @@ void cluster::start(bool return_after) { if (g.shards) { log(ll_info, "Auto Shard: Bot requires " + std::to_string(g.shards) + std::string(" shard") + ((g.shards > 1) ? "s" : "")); } else { - throw dpp::connection_exception("Auto Shard: Cannot determine number of shards. Cluster startup aborted. Check your connection."); + throw dpp::connection_exception(err_auto_shard, "Auto Shard: Cannot determine number of shards. Cluster startup aborted. Check your connection."); } numshards = g.shards; } @@ -194,7 +194,7 @@ void cluster::start(bool return_after) { catch (const dpp::rest_exception& e) { if (std::string(e.what()) == "401: Unauthorized") { /* Throw special form of exception for invalid token */ - throw dpp::invalid_token_exception("Invalid bot token (401: Unauthorized when getting gateway shard count)"); + throw dpp::invalid_token_exception(err_unauthorized, "Invalid bot token (401: Unauthorized when getting gateway shard count)"); } else { /* Rethrow */ throw e; diff --git a/src/dpp/cluster/user.cpp b/src/dpp/cluster/user.cpp index 0f1f0d0f25..a430f18a10 100644 --- a/src/dpp/cluster/user.cpp +++ b/src/dpp/cluster/user.cpp @@ -37,7 +37,7 @@ void cluster::current_user_edit(const std::string &nickname, const std::string& { i_webp, "image/webp" }, }; if (image_blob.size() > MAX_EMOJI_SIZE) { - throw dpp::length_exception("User icon file exceeds discord limit of 256 kilobytes"); + throw dpp::length_exception(err_icon_size, "User icon file exceeds discord limit of 256 kilobytes"); } j["avatar"] = "data:" + mimetypes.find(type)->second + ";base64," + base64_encode((unsigned char const*)image_blob.data(), (unsigned int)image_blob.length()); } @@ -59,7 +59,7 @@ void cluster::current_user_set_voice_state(snowflake guild_id, snowflake channel }); if (request_to_speak_timestamp) { if (request_to_speak_timestamp < time(nullptr)) { - throw dpp::logic_exception("Cannot set voice state request to speak timestamp to before current time"); + throw dpp::logic_exception(err_voice_state_timestamp, "Cannot set voice state request to speak timestamp to before current time"); } j["request_to_speak_timestamp"] = ts_to_string(request_to_speak_timestamp); } else { diff --git a/src/dpp/commandhandler.cpp b/src/dpp/commandhandler.cpp index ddd379c3bf..9e15168f53 100644 --- a/src/dpp/commandhandler.cpp +++ b/src/dpp/commandhandler.cpp @@ -91,7 +91,7 @@ commandhandler& commandhandler::add_command(const std::string &command, const pa if (slash_commands_enabled) { if (this->app_id.empty()) { if (owner->me.id.empty()) { - throw dpp::logic_exception("Command handler not ready (i don't know my application ID)"); + throw dpp::logic_exception(err_command_handler_not_ready, "Command handler not ready (i don't know my application ID)"); } else { this->app_id = owner->me.id; } diff --git a/src/dpp/discordclient.cpp b/src/dpp/discordclient.cpp index 96f9f52cd4..0f925f6313 100644 --- a/src/dpp/discordclient.cpp +++ b/src/dpp/discordclient.cpp @@ -149,8 +149,9 @@ void discord_client::setup_zlib() zlib->d_stream.zalloc = (alloc_func)0; zlib->d_stream.zfree = (free_func)0; zlib->d_stream.opaque = (voidpf)0; - if (inflateInit(&(zlib->d_stream)) != Z_OK) { - throw dpp::connection_exception("Can't initialise stream compression!"); + int error = inflateInit(&(zlib->d_stream)); + if (error != Z_OK) { + throw dpp::connection_exception((exception_error_code)error, "Can't initialise stream compression!"); } this->decomp_buffer = new unsigned char[DECOMP_BUFFER_SIZE]; } @@ -242,17 +243,17 @@ bool discord_client::handle_frame(const std::string &buffer) { case Z_NEED_DICT: case Z_STREAM_ERROR: - this->error(6000); + this->error(err_compression_stream); this->close(); return true; break; case Z_DATA_ERROR: - this->error(6001); + this->error(err_compression_data); this->close(); return true; break; case Z_MEM_ERROR: - this->error(6002); + this->error(err_compression_memory); this->close(); return true; break; @@ -383,7 +384,7 @@ bool discord_client::handle_frame(const std::string &buffer) case 7: log(dpp::ll_debug, "Reconnection requested, closing socket " + sessionid); message_queue.clear(); - throw dpp::connection_exception("Remote site requested reconnection"); + throw dpp::connection_exception(err_reconnection, "Remote site requested reconnection"); break; /* Heartbeat ack */ case 11: diff --git a/src/dpp/discordvoiceclient.cpp b/src/dpp/discordvoiceclient.cpp index 0dfeb03e5f..058130a765 100644 --- a/src/dpp/discordvoiceclient.cpp +++ b/src/dpp/discordvoiceclient.cpp @@ -261,7 +261,7 @@ void discord_voice_client::voice_courier_loop(discord_voice_client& client, cour } else { voice_receive_t& vr = *d.parked_payloads.top().vr; if (vr.audio_data.length() > 0x7FFFFFFF) { - throw dpp::length_exception("audio_data > 2GB! This should never happen!"); + throw dpp::length_exception(err_massive_audio, "audio_data > 2GB! This should never happen!"); } if (samples = opus_decode(d.decoder.get(), vr.audio_data.data(), static_cast(vr.audio_data.length() & 0x7FFFFFFF), pcm, 5760, 0); @@ -332,18 +332,18 @@ discord_voice_client::discord_voice_client(dpp::cluster* _cluster, snowflake _ch #if HAVE_VOICE if (!discord_voice_client::sodium_initialised) { if (sodium_init() < 0) { - throw dpp::voice_exception("discord_voice_client::discord_voice_client; sodium_init() failed"); + throw dpp::voice_exception(err_sodium, "discord_voice_client::discord_voice_client; sodium_init() failed"); } discord_voice_client::sodium_initialised = true; } int opusError = 0; encoder = opus_encoder_create(opus_sample_rate_hz, opus_channel_count, OPUS_APPLICATION_VOIP, &opusError); if (opusError) { - throw dpp::voice_exception("discord_voice_client::discord_voice_client; opus_encoder_create() failed"); + throw dpp::voice_exception(err_opus, "discord_voice_client::discord_voice_client; opus_encoder_create() failed"); } repacketizer = opus_repacketizer_create(); if (!repacketizer) { - throw dpp::voice_exception("discord_voice_client::discord_voice_client; opus_repacketizer_create() failed"); + throw dpp::voice_exception(err_opus, "discord_voice_client::discord_voice_client; opus_repacketizer_create() failed"); } try { this->connect(); @@ -353,7 +353,7 @@ discord_voice_client::discord_voice_client(dpp::cluster* _cluster, snowflake _ch throw; } #else - throw dpp::voice_exception("Voice support not enabled in this build of D++"); + throw dpp::voice_exception(err_no_voice_support, "Voice support not enabled in this build of D++"); #endif } @@ -621,11 +621,11 @@ bool discord_voice_client::handle_frame(const std::string &data) servaddr.sin_port = htons(0); if (bind(newfd, (sockaddr*)&servaddr, sizeof(servaddr)) < 0) { - throw dpp::connection_exception("Can't bind() client UDP socket"); + throw dpp::connection_exception(err_bind_failure, "Can't bind() client UDP socket"); } if (!set_nonblocking(newfd, true)) { - throw dpp::connection_exception("Can't switch voice UDP socket to non-blocking mode!"); + throw dpp::connection_exception(err_nonblocking_failure, "Can't switch voice UDP socket to non-blocking mode!"); } /* Hook poll() in the ssl_client to add a new file descriptor */ @@ -807,7 +807,11 @@ void discord_voice_client::read_ready() decoder.reset(opus_decoder_create(opus_sample_rate_hz, opus_channel_count, &opus_error), &opus_decoder_destroy); if (opus_error) { - throw dpp::voice_exception("discord_voice_client::discord_voice_client; opus_decoder_create() failed"); + /** + * NOTE: The -10 here makes the opus_error match up with values of exception_error_code, + * which would otherwise conflict as every C library loves to use values from -1 downwards. + */ + throw dpp::voice_exception((exception_error_code)(opus_error - 10), "discord_voice_client::discord_voice_client; opus_decoder_create() failed"); } } @@ -830,7 +834,7 @@ void discord_voice_client::read_ready() } } #else - throw dpp::voice_exception("Voice support not enabled in this build of D++"); + throw dpp::voice_exception(err_no_voice_support, "Voice support not enabled in this build of D++"); #endif } @@ -1063,7 +1067,7 @@ const std::vector discord_voice_client::get_marker_metadata() { void discord_voice_client::one_second_timer() { if (terminating) { - throw dpp::connection_exception("Terminating voice connection"); + throw dpp::connection_exception(err_voice_terminating, "Terminating voice connection"); } /* Rate limit outbound messages, 1 every odd second, 2 every even second */ if (this->get_state() == CONNECTED) { @@ -1128,10 +1132,10 @@ size_t discord_voice_client::encode(uint8_t *input, size_t inDataSize, uint8_t * } } } else { - throw dpp::voice_exception("Invalid input data length: " + std::to_string(inDataSize) + ", must be n times of " + std::to_string(mEncFrameBytes)); + throw dpp::voice_exception(err_invalid_voice_packet_length, "Invalid input data length: " + std::to_string(inDataSize) + ", must be n times of " + std::to_string(mEncFrameBytes)); } #else - throw dpp::voice_exception("Voice support not enabled in this build of D++"); + throw dpp::voice_exception(err_no_voice_support, "Voice support not enabled in this build of D++"); #endif return outDataSize; } @@ -1197,11 +1201,11 @@ discord_voice_client& discord_voice_client::set_send_audio_type(send_audio_type_ discord_voice_client& discord_voice_client::send_audio_raw(uint16_t* audio_data, const size_t length) { #if HAVE_VOICE if (length < 4) { - throw dpp::voice_exception("Raw audio packet size can't be less than 4"); + throw dpp::voice_exception(err_invalid_voice_packet_length, "Raw audio packet size can't be less than 4"); } if ((length % 4) != 0) { - throw dpp::voice_exception("Raw audio packet size should be divisible by 4"); + throw dpp::voice_exception(err_invalid_voice_packet_length, "Raw audio packet size should be divisible by 4"); } if (length > send_audio_raw_max_length) { @@ -1234,7 +1238,7 @@ discord_voice_client& discord_voice_client::send_audio_raw(uint16_t* audio_data, send_audio_opus(encodedAudioData.data(), encodedAudioLength); #else - throw dpp::voice_exception("Voice support not enabled in this build of D++"); + throw dpp::voice_exception(err_no_voice_support, "Voice support not enabled in this build of D++"); #endif return *this; } @@ -1245,7 +1249,7 @@ discord_voice_client& discord_voice_client::send_audio_opus(uint8_t* opus_packet uint64_t duration = (samples / 48) / (timescale / 1000000); send_audio_opus(opus_packet, length, duration); #else - throw dpp::voice_exception("Voice support not enabled in this build of D++"); + throw dpp::voice_exception(err_no_voice_support, "Voice support not enabled in this build of D++"); #endif return *this; } @@ -1279,7 +1283,7 @@ discord_voice_client& discord_voice_client::send_audio_opus(uint8_t* opus_packet speak(); #else - throw dpp::voice_exception("Voice support not enabled in this build of D++"); + throw dpp::voice_exception(err_no_voice_support, "Voice support not enabled in this build of D++"); #endif return *this; } diff --git a/src/dpp/dns.cpp b/src/dpp/dns.cpp index 37c3344ff2..e87fbd45e8 100644 --- a/src/dpp/dns.cpp +++ b/src/dpp/dns.cpp @@ -83,7 +83,11 @@ namespace dpp hints.ai_protocol = IPPROTO_TCP; if ((error = getaddrinfo(hostname.c_str(), port.c_str(), &hints, &addrs))) { - throw dpp::connection_exception(std::string("getaddrinfo error: ") + gai_strerror(error)); + /** + * The -20 makes sure the error codes dont conflict with codes given in the rest of the list + * Because C libraries love to use -1 and below directly as conflicting error codes. + */ + throw dpp::connection_exception((exception_error_code)(error - 20), std::string("getaddrinfo error: ") + gai_strerror(error)); } /* Thread safety scope */ diff --git a/src/dpp/emoji.cpp b/src/dpp/emoji.cpp index 3d6280e08e..b8d0350e20 100644 --- a/src/dpp/emoji.cpp +++ b/src/dpp/emoji.cpp @@ -97,7 +97,7 @@ bool emoji::is_available() const { emoji& emoji::load_image(std::string_view image_blob, const image_type type) { if (image_blob.size() > MAX_EMOJI_SIZE) { - throw dpp::length_exception("Emoji file exceeds discord limit of 256 kilobytes"); + throw dpp::length_exception(err_icon_size, "Emoji file exceeds discord limit of 256 kilobytes"); } image_data = utility::image_data{type, image_blob}; return *this; @@ -105,7 +105,7 @@ emoji& emoji::load_image(std::string_view image_blob, const image_type type) { emoji& emoji::load_image(const std::byte *data, uint32_t size, const image_type type) { if (size > MAX_EMOJI_SIZE) { - throw dpp::length_exception("Emoji file exceeds discord limit of 256 kilobytes"); + throw dpp::length_exception(err_icon_size, "Emoji file exceeds discord limit of 256 kilobytes"); } image_data = utility::image_data{type, data, size}; return *this; diff --git a/src/dpp/etf.cpp b/src/dpp/etf.cpp index 27b04c5070..a76f5d9c41 100644 --- a/src/dpp/etf.cpp +++ b/src/dpp/etf.cpp @@ -137,7 +137,7 @@ void etf_parser::append_atom(etf_buffer *b, const char *bytes, size_t size) { buf[0] = ett_atom; if (size > 0xFFFF) { - throw dpp::parse_exception("ETF: Atom too large"); + throw dpp::parse_exception(err_etf, "ETF: Atom too large"); } store_16_bits(buf + 1, size); @@ -156,7 +156,7 @@ void etf_parser::append_atom_utf8(etf_buffer *b, const char *bytes, size_t size) buf[0] = ett_atom_utf8; if (size > 0xFFFF) { - throw dpp::parse_exception("ETF: Atom too large"); + throw dpp::parse_exception(err_etf, "ETF: Atom too large"); } store_16_bits(buf + 1, size); @@ -225,7 +225,7 @@ etf_parser::~etf_parser() = default; uint8_t etf_parser::read_8_bits() { if (offset + sizeof(uint8_t) > size) { - throw dpp::parse_exception("ETF: read_8_bits() past end of buffer"); + throw dpp::parse_exception(err_etf, "ETF: read_8_bits() past end of buffer"); } auto val = *reinterpret_cast(data + offset); offset += sizeof(uint8_t); @@ -234,7 +234,7 @@ uint8_t etf_parser::read_8_bits() { uint16_t etf_parser::read_16_bits() { if (offset + sizeof(uint16_t) > size) { - throw dpp::parse_exception("ETF: read_16_bits() past end of buffer"); + throw dpp::parse_exception(err_etf, "ETF: read_16_bits() past end of buffer"); } uint16_t val = etf_byte_order_16(*reinterpret_cast(data + offset)); offset += sizeof(uint16_t); @@ -243,7 +243,7 @@ uint16_t etf_parser::read_16_bits() { uint32_t etf_parser::read_32_bits() { if (offset + sizeof(uint32_t) > size) { - throw dpp::parse_exception("ETF: read_32_bits() past end of buffer"); + throw dpp::parse_exception(err_etf, "ETF: read_32_bits() past end of buffer"); } uint32_t val = etf_byte_order_32(*reinterpret_cast(data + offset)); offset += sizeof(uint32_t); @@ -252,7 +252,7 @@ uint32_t etf_parser::read_32_bits() { uint64_t etf_parser::read_64_bits() { if (offset + sizeof(uint64_t) > size) { - throw dpp::parse_exception("ETF: read_64_bits() past end of buffer"); + throw dpp::parse_exception(err_etf, "ETF: read_64_bits() past end of buffer"); } uint64_t val = etf_byte_order_64(*reinterpret_cast(data + offset)); offset += sizeof(val); @@ -408,7 +408,7 @@ json etf_parser::decode_bigint(uint32_t digits) { const uint8_t sign = read_8_bits(); if (digits > 8) { - throw dpp::parse_exception("ETF: big integer larger than 8 bytes unsupported"); + throw dpp::parse_exception(err_etf, "ETF: big integer larger than 8 bytes unsupported"); } uint64_t value = 0; @@ -476,7 +476,7 @@ json etf_parser::decode_string_as_list() { const auto length = read_16_bits(); json array = json::array(); if (offset + length > size) { - throw dpp::parse_exception("String list past end of buffer"); + throw dpp::parse_exception(err_etf, "String list past end of buffer"); } for(uint16_t i = 0; i < length; ++i) { array.emplace_back(decode_small_integer()); @@ -501,7 +501,7 @@ json etf_parser::decode_compressed() { offset += sourceSize; if (ret != Z_OK) { - throw dpp::parse_exception("ETF compressed value: decompresson error"); + throw dpp::parse_exception(err_etf, "ETF compressed value: decompresson error"); } uint8_t* old_data = data; @@ -575,14 +575,14 @@ json etf_parser::decode_export() { json etf_parser::inner_parse() { /* Decode one value into json from ETF */ if (offset >= size) { - throw dpp::parse_exception("Read past end of ETF buffer"); + throw dpp::parse_exception(err_etf, "Read past end of ETF buffer"); } const uint8_t type = read_8_bits(); switch(type) { case ett_distribution: - throw dpp::parse_exception("Distribution headers are not supported"); + throw dpp::parse_exception(err_etf, "Distribution headers are not supported"); case ett_smallint: return decode_small_integer(); case ett_integer: @@ -626,7 +626,7 @@ json etf_parser::inner_parse() { case ett_compressed: return decode_compressed(); default: - throw dpp::parse_exception("Unknown data type in ETF"); + throw dpp::parse_exception(err_etf, "Unknown data type in ETF"); } } @@ -639,7 +639,7 @@ json etf_parser::parse(const std::string& in) { if (version == FORMAT_VERSION) { return inner_parse(); } else { - throw dpp::parse_exception("Incorrect ETF version"); + throw dpp::parse_exception(err_etf, "Incorrect ETF version"); } } @@ -690,7 +690,7 @@ void etf_parser::inner_build(const json* i, etf_buffer* b) append_nil_ext(b); } else { if (length > std::numeric_limits::max() - 1) { - throw dpp::parse_exception("ETF encode: List too large for ETF"); + throw dpp::parse_exception(err_etf, "ETF encode: List too large for ETF"); } } @@ -704,7 +704,7 @@ void etf_parser::inner_build(const json* i, etf_buffer* b) /* Object types (can contain any other type, recursively, but nlohmann::json only supports string keys) */ const size_t length = i->size(); if (length > std::numeric_limits::max() - 1) { - throw dpp::parse_exception("ETF encode: Map too large for ETF"); + throw dpp::parse_exception(err_etf, "ETF encode: Map too large for ETF"); } append_map_header(b, length); for (auto n = i->begin(); n != i->end(); ++n) { diff --git a/src/dpp/guild.cpp b/src/dpp/guild.cpp index a670c4f5a0..a1162321ea 100644 --- a/src/dpp/guild.cpp +++ b/src/dpp/guild.cpp @@ -1021,9 +1021,9 @@ guild_member find_guild_member(const snowflake guild_id, const snowflake user_id return gm->second; } - throw dpp::cache_exception("Requested member not found in the guild cache!"); + throw dpp::cache_exception(err_cache, "Requested member not found in the guild cache!"); } - throw dpp::cache_exception("Requested guild cache not found!"); + throw dpp::cache_exception(err_cache, "Requested guild cache not found!"); } diff --git a/src/dpp/message.cpp b/src/dpp/message.cpp index abb2d5f8af..3148b08434 100644 --- a/src/dpp/message.cpp +++ b/src/dpp/message.cpp @@ -865,7 +865,7 @@ attachment::attachment(struct message* o, json *j) : attachment(o) { void attachment::download(http_completion_event callback) const { /* Download attachment if there is one attached to this object */ if (owner == nullptr || owner->owner == nullptr) { - throw dpp::logic_exception("attachment has no owning message/cluster"); + throw dpp::logic_exception(err_no_owning_message, "attachment has no owning message/cluster"); } if (callback && this->id && !this->url.empty()) { owner->owner->request(this->url, dpp::m_get, callback); diff --git a/src/dpp/scheduled_event.cpp b/src/dpp/scheduled_event.cpp index 2bd8e03309..fe7e2c7a4c 100644 --- a/src/dpp/scheduled_event.cpp +++ b/src/dpp/scheduled_event.cpp @@ -77,15 +77,15 @@ scheduled_event& scheduled_event::set_creator_id(snowflake c) { scheduled_event& scheduled_event::set_status(event_status s) { if (this->status == es_completed || this->status == es_cancelled) { - throw dpp::logic_exception("Can't update status of a completed or cancelled event"); + throw dpp::logic_exception(err_cancelled_event, "Can't update status of a completed or cancelled event"); } else { if (this->status == es_scheduled) { if (s != es_active && s != es_cancelled) { - throw dpp::logic_exception("Invalid status transition, scheduled can only transition to active or cancelled"); + throw dpp::logic_exception(err_event_status, "Invalid status transition, scheduled can only transition to active or cancelled"); } } else if (this->status == es_active) { if (s != es_completed) { - throw dpp::logic_exception("Invalid status transition, active can only transition to completed"); + throw dpp::logic_exception(err_event_status, "Invalid status transition, active can only transition to completed"); } } } @@ -95,7 +95,7 @@ scheduled_event& scheduled_event::set_status(event_status s) { scheduled_event& scheduled_event::set_start_time(time_t t) { if (t < time(nullptr)) { - throw dpp::length_exception("Start time cannot be before current date and time"); + throw dpp::length_exception(err_event_start_time, "Start time cannot be before current date and time"); } this->scheduled_start_time = t; return *this; @@ -103,7 +103,7 @@ scheduled_event& scheduled_event::set_start_time(time_t t) { scheduled_event& scheduled_event::set_end_time(time_t t) { if (t < time(nullptr)) { - throw dpp::length_exception("End time cannot be before current date and time"); + throw dpp::length_exception(err_event_end_time, "End time cannot be before current date and time"); } this->scheduled_end_time = t; return *this; diff --git a/src/dpp/slashcommand.cpp b/src/dpp/slashcommand.cpp index be26714d48..5b4b8cb9b0 100644 --- a/src/dpp/slashcommand.cpp +++ b/src/dpp/slashcommand.cpp @@ -334,14 +334,14 @@ command_option::command_option(command_option_type t, const std::string &n, cons type(t), name(n), description(d), required(r), autocomplete(false) { if (std::any_of(n.begin(), n.end(), [](unsigned char c){ return std::isupper(c); })) { - throw dpp::logic_exception("Command options can not contain capital letters in the name of the option."); + throw dpp::logic_exception(err_command_has_caps, "Command options can not contain capital letters in the name of the option."); } } command_option& command_option::add_choice(const command_option_choice &o) { if (this->autocomplete) { - throw dpp::logic_exception("Can't set autocomplete=true if choices exist in the command_option"); + throw dpp::logic_exception(err_choice_autocomplete, "Can't set autocomplete=true if choices exist in the command_option"); } choices.emplace_back(o); return *this; @@ -362,7 +362,7 @@ command_option& command_option::add_channel_type(const channel_type ch) command_option& command_option::set_auto_complete(bool autocomp) { if (autocomp && !choices.empty()) { - throw dpp::logic_exception("Can't set autocomplete=true if choices exist in the command_option"); + throw dpp::logic_exception(err_choice_autocomplete, "Can't set autocomplete=true if choices exist in the command_option"); } this->autocomplete = autocomp; return *this; @@ -445,7 +445,7 @@ command_interaction interaction::get_command_interaction() const { if (std::holds_alternative(data)) { return std::get(data); } else { - throw dpp::logic_exception("Interaction is not for a command"); + throw dpp::logic_exception(err_interaction, "Interaction is not for a command"); } } @@ -453,7 +453,7 @@ component_interaction interaction::get_component_interaction() const { if (std::holds_alternative(data)) { return std::get(data); } else { - throw dpp::logic_exception("Interaction is not for a component"); + throw dpp::logic_exception(err_interaction, "Interaction is not for a component"); } } @@ -461,7 +461,7 @@ autocomplete_interaction interaction::get_autocomplete_interaction() const { if (std::holds_alternative(data)) { return std::get(data); } else { - throw dpp::logic_exception("Interaction is not for an autocomplete"); + throw dpp::logic_exception(err_interaction, "Interaction is not for an autocomplete"); } } @@ -843,7 +843,7 @@ interaction_modal_response& interaction_modal_response::add_row() { current_row++; components.push_back({}); } else { - throw dpp::logic_exception("A modal dialog can only have a maximum of five component rows"); + throw dpp::logic_exception(err_too_many_component_rows, "A modal dialog can only have a maximum of five component rows"); } return *this; } @@ -921,7 +921,7 @@ const dpp::message& interaction::get_context_message() const { const dpp::channel& interaction::get_channel() const { auto c = find_channel(channel_id); if (c == nullptr) { - throw dpp::logic_exception("No channel for this command interaction"); + throw dpp::logic_exception(err_unknown_channel, "No channel for this command interaction"); } return *c; } @@ -929,7 +929,7 @@ const dpp::channel& interaction::get_channel() const { const dpp::guild& interaction::get_guild() const { auto g = find_guild(guild_id); if (g == nullptr) { - throw dpp::logic_exception("No guild for this command interaction"); + throw dpp::logic_exception(err_unknown_guild, "No guild for this command interaction"); } return *g; } diff --git a/src/dpp/sslclient.cpp b/src/dpp/sslclient.cpp index d1e494fcf0..3d6577fa03 100644 --- a/src/dpp/sslclient.cpp +++ b/src/dpp/sslclient.cpp @@ -170,7 +170,7 @@ int connect_with_timeout(dpp::socket sockfd, const struct sockaddr *addr, sockle return (::connect(sockfd, addr, addrlen)); #else if (!set_nonblocking(sockfd, true)) { - throw dpp::connection_exception("Can't switch socket to non-blocking mode!"); + throw dpp::connection_exception(err_nonblocking_failure, "Can't switch socket to non-blocking mode!"); } #ifdef _WIN32 /* Windows connect returns -1 and sets its error value to 0 for successfull blocking connection - @@ -186,14 +186,14 @@ int connect_with_timeout(dpp::socket sockfd, const struct sockaddr *addr, sockle int err = errno; #endif if (rc == -1 && err != EWOULDBLOCK && err != EINPROGRESS) { - throw connection_exception(strerror(errno)); + throw connection_exception(err_connect_failure, strerror(errno)); } else { /* Set a deadline timestamp 'timeout' ms from now */ double deadline = utility::time_f() + (timeout_ms / 1000.0); do { rc = -1; if (utility::time_f() >= deadline) { - throw connection_exception("Connection timed out"); + throw connection_exception(err_connection_timed_out, "Connection timed out"); } pollfd pfd = {}; pfd.fd = sockfd; @@ -202,12 +202,12 @@ int connect_with_timeout(dpp::socket sockfd, const struct sockaddr *addr, sockle if (r > 0 && pfd.revents & POLLOUT) { rc = 0; } else if (r != 0 || pfd.revents & POLLERR) { - throw connection_exception(strerror(errno)); + throw connection_exception(err_connection_timed_out, strerror(errno)); } } while (rc == -1); } if (!set_nonblocking(sockfd, false)) { - throw connection_exception("Can't switch socket to blocking mode!"); + throw connection_exception(err_nonblocking_failure, "Can't switch socket to blocking mode!"); } return rc; #endif @@ -236,7 +236,7 @@ ssl_client::ssl_client(const std::string &_hostname, const std::string &_port, b // Set up winsock. WSADATA wsadata; if (WSAStartup(MAKEWORD(2, 2), &wsadata)) { - throw dpp::connection_exception("WSAStartup failure"); + throw dpp::connection_exception(err_connect_failure, "WSAStartup failure"); } #endif if (keepalive) { @@ -311,7 +311,7 @@ void ssl_client::connect() /* Check if none of the IPs yielded a valid connection */ if (sfd == ERROR_STATUS) { - throw dpp::connection_exception(strerror(err)); + throw dpp::connection_exception(err_connect_failure, strerror(err)); } if (!plaintext) { @@ -323,21 +323,21 @@ void ssl_client::connect() /* Create SSL context */ openssl_context = SSL_CTX_new(method); if (openssl_context == nullptr) { - throw dpp::connection_exception("Failed to create SSL client context!"); + throw dpp::connection_exception(err_ssl_context, "Failed to create SSL client context!"); } /* Do not allow SSL 3.0, TLS 1.0 or 1.1 * https://www.packetlabs.net/posts/tls-1-1-no-longer-secure/ */ if (!SSL_CTX_set_min_proto_version(openssl_context, TLS1_2_VERSION)) { - throw dpp::connection_exception("Failed to set minimum SSL version!"); + throw dpp::connection_exception(err_ssl_version, "Failed to set minimum SSL version!"); } } /* Create SSL session */ ssl->ssl = SSL_new(openssl_context); if (ssl->ssl == nullptr) { - throw dpp::connection_exception("SSL_new failed!"); + throw dpp::connection_exception(err_ssl_new, "SSL_new failed!"); } SSL_set_fd(ssl->ssl, (int)sfd); @@ -354,7 +354,7 @@ void ssl_client::connect() setsockopt(sfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); #endif if (SSL_connect(ssl->ssl) != 1) { - throw dpp::connection_exception("SSL_connect error"); + throw dpp::connection_exception(err_ssl_connect, "SSL_connect error"); } this->cipher = SSL_get_cipher(ssl->ssl); @@ -376,11 +376,11 @@ void ssl_client::write(const std::string &data) const int data_length = (int)data.length(); if (plaintext) { if (sfd == INVALID_SOCKET || ::send(sfd, data.data(), data_length, 0) != data_length) { - throw dpp::connection_exception("write() failed"); + throw dpp::connection_exception(err_write, "write() failed"); } } else { if (SSL_write(ssl->ssl, data.data(), data_length) != data_length) { - throw dpp::connection_exception("SSL_write() failed"); + throw dpp::connection_exception(err_ssl_write, "SSL_write() failed"); } } } @@ -417,12 +417,12 @@ void ssl_client::read_loop() try { if (sfd == INVALID_SOCKET) { - throw dpp::connection_exception("Invalid file descriptor in read_loop()"); + throw dpp::connection_exception(err_invalid_socket, "Invalid file descriptor in read_loop()"); } /* Make the socket nonblocking */ if (!set_nonblocking(sfd, true)) { - throw dpp::connection_exception("Can't switch socket to non-blocking mode!"); + throw dpp::connection_exception(err_nonblocking_failure, "Can't switch socket to non-blocking mode!"); } nonblocking = true; @@ -453,7 +453,7 @@ void ssl_client::read_loop() } if (sfd == -1) { - throw dpp::connection_exception("File descriptor invalidated, connection died"); + throw dpp::connection_exception(err_invalid_socket, "File descriptor invalidated, connection died"); } /* If we're waiting for a read on the socket don't try to write to the server */ @@ -477,7 +477,7 @@ void ssl_client::read_loop() custom_readable_ready(); } if ((pfd[0].revents & POLLERR) || (pfd[0].revents & POLLNVAL) || sfd == INVALID_SOCKET) { - throw dpp::connection_exception(strerror(errno)); + throw dpp::connection_exception(err_socket_error, strerror(errno)); } /* Now check if there's data to read */ diff --git a/src/dpp/webhook.cpp b/src/dpp/webhook.cpp index 4b3c23a620..4c43c4df2c 100644 --- a/src/dpp/webhook.cpp +++ b/src/dpp/webhook.cpp @@ -38,7 +38,7 @@ webhook::webhook(const std::string& webhook_url) : webhook() { auto pos = webhook_url.find_last_of('/'); if (pos == std::string::npos) { // throw when the url doesn't contain a slash at all - throw dpp::logic_exception(std::string("Failed to parse webhook URL: No '/' found in the webhook url")); + throw dpp::logic_exception(err_invalid_webhook, std::string("Failed to parse webhook URL: No '/' found in the webhook url")); } try { token = webhook_url.substr(pos + 1); @@ -46,7 +46,7 @@ webhook::webhook(const std::string& webhook_url) : webhook() id = std::stoull(webhook_url.substr(endpoint.size(), pos)); } catch (const std::exception& e) { - throw dpp::logic_exception(std::string("Failed to parse webhook URL: ") + e.what()); + throw dpp::logic_exception(err_invalid_webhook, std::string("Failed to parse webhook URL: ") + e.what()); } } @@ -93,7 +93,7 @@ json webhook::to_json_impl(bool with_id) const { webhook& webhook::load_image(const std::string &image_blob, const image_type type, bool is_base64_encoded) { if (image_blob.size() > MAX_ICON_SIZE) { - throw dpp::length_exception("Webhook icon file exceeds discord limit of 256 kilobytes"); + throw dpp::length_exception(err_icon_size, "Webhook icon file exceeds discord limit of 256 kilobytes"); } image_data = "data:" + utility::mime_type(type) + ";base64," + (is_base64_encoded ? image_blob : base64_encode(reinterpret_cast(image_blob.data()), static_cast(image_blob.length())));