Giter Site home page Giter Site logo

zeroxs / aegis.cpp Goto Github PK

View Code? Open in Web Editor NEW
215.0 17.0 32.0 2.76 MB

Discord C++ library for interfacing with the API. Join our server: https://discord.gg/w7Y3Bb8

Home Page: https://discord.gg/w7Y3Bb8

License: MIT License

C++ 96.59% CMake 3.07% Shell 0.32% Vim Script 0.01%
discord bot cpp17 cpp discord-library c-plus-plus-17 c-plus-plus libaegis library aegis

aegis.cpp's Introduction

Hello, I'm Sharon.

๐Ÿ  I live in Pittsburgh, Pennsylvania, US

๐Ÿ‘ฉโ€๐Ÿ’ป I love working with code.

๐Ÿ’ฝ Backend programming is my jam.

aegis.cpp's People

Contributors

braindigitalis avatar cydrith avatar emil-jarosz avatar gena2018115rus avatar geniiii avatar gitmeep avatar j883376 avatar jpahm avatar lohkdesgds avatar mayankmohan avatar nandemonogatari avatar willem640 avatar zeroxs avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

aegis.cpp's Issues

get_messages() has small issue

Around and before are ignored, they work as after

switch (obj._type)
{
case get_messages_t::get_messages_type::AFTER:
query_params += fmt::format("after={}{}", obj._message_id, limit);
break;
case get_messages_t::get_messages_type::AROUND:
query_params += fmt::format("after={}{}", obj._message_id, limit);
break;
case get_messages_t::get_messages_type::BEFORE:
query_params += fmt::format("after={}{}", obj._message_id, limit);
break;
case get_messages_t::get_messages_type::LAST:
query_params += limit.substr(1);
break;
}

bot invites

bot could write its own invite link at startup

channel == nullptr

Due to the async design, a MESSAGE_CREATE can be processed prior to a GUILD_CREATE creating the scenario of a message being handled that has no channel in the cache which leads to the message being rejected.

log->warn("Shard#{} - channel == nullptr - {} {} {}", _shard->get_id(), c_id, result["d"]["author"]["id"].get<std::string>(), result["d"]["content"].get<std::string>());

Solution is to perform a create_channel() to create a semi-empty channel so the message can still be handled. This would be best accomplished with some sort of flag in the channel object itself to identify whether or not the channel is in this empty state or has been populated by a GUILD_CREATE or CHANNEL_CREATE.

Clean up API

Some of the visible Aegis API is either redundant or not necessary to be exposed.

Crash on message send

if ((_guild == nullptr) && (_guild_id > 0))
_guild = _core->find_guild(_guild_id);
if ((_channel == nullptr) && (_channel_id > 0))
_channel = _core->find_channel(_channel_id);
if (!_channel)
//throw because channel should always exist or else we have no understanding of the channel
//TODO: create a dummy channel in this instance then request full info after?
//bot would have already performed action on it by then. perhaps timed block here until channel info
//is requested and populated and throw if it can't be requested?
throw aegis::exception(error::channel_not_found);

crash when sending a message too early. throw performed due to missing guild/channel cache is not possible to be caught due to futures

Need a title

HP@Windobe MINGW64 ~/Documents/C++ Discord Bot/aegis.cpp/build (master)
$ cmake ..
-- CMake version: 3.17.3
-- Selecting Windows SDK version 10.0.18362.0 to target Windows 10.0.19041.
-- Could NOT find PkgConfig (missing: PKG_CONFIG_EXECUTABLE)
CMake Warning at cmake/FindAsio.cmake:10 (message):
  Using git-module path for Asio
Call Stack (most recent call first):
  CMakeLists.txt:34 (find_package)


-- Could NOT find PkgConfig (missing: PKG_CONFIG_EXECUTABLE)
CMake Warning at cmake/FindJSON.cmake:10 (message):
  Using git-module path for JSON
Call Stack (most recent call first):
  CMakeLists.txt:35 (find_package)


-- Could NOT find PkgConfig (missing: PKG_CONFIG_EXECUTABLE)
CMake Warning at cmake/FindSpdlog.cmake:10 (message):
  Using git-module path for Spdlog
Call Stack (most recent call first):
  CMakeLists.txt:36 (find_package)


-- Could NOT find PkgConfig (missing: PKG_CONFIG_EXECUTABLE)
CMake Warning at cmake/FindWebsocketpp.cmake:10 (message):
  Using git-module path for Websocketpp
Call Stack (most recent call first):
  CMakeLists.txt:37 (find_package)


CMake Error at C:/Program Files/CMake/share/cmake-3.17/Modules/FindPackageHandleStandardArgs.cmake:164 (message):
  Could NOT find OpenSSL, try to set the path to OpenSSL root folder in the
  system variable OPENSSL_ROOT_DIR (missing: OPENSSL_CRYPTO_LIBRARY
  OPENSSL_INCLUDE_DIR) (Required is at least version "1.0.1")
Call Stack (most recent call first):
  C:/Program Files/CMake/share/cmake-3.17/Modules/FindPackageHandleStandardArgs.cmake:445 (_FPHSA_FAILURE_MESSAGE)
  C:/Program Files/CMake/share/cmake-3.17/Modules/FindOpenSSL.cmake:459 (find_package_handle_standard_args)
  CMakeLists.txt:38 (find_package)


-- Configuring incomplete, errors occurred!
See also "C:/Users/HP/Documents/C++ Discord Bot/aegis.cpp/build/CMakeFiles/CMakeOutput.log".
See also "C:/Users/HP/Documents/C++ Discord Bot/aegis.cpp/build/CMakeFiles/CMakeError.log".

Process aborted by std::terminate()

Just a HTTP 401 error causes abnormal process shutdown from the library.
I don't understand the whole design yet, but I assume that it is a little bit too rough.

catch (std::exception & e)
{
log->critical("Exception during startup: {}", e.what());
std::terminate();
}
}

Do you have difficulties in restoring the state, for example?
44e4c45

Cannot get SPDLOG_VERSION from common.h.

When i run cmake i get the error:

CMake Error at cmake/FindSpdlog.cmake:16 (message): Cannot get SPDLOG_VERSION from common.h. Call Stack (most recent call first): CMakeLists.txt:36 (find_package)

i installed spdlog and the other dependencies.

Build break on BUILD_SHARED_LIBS=off

CMake option BUILD_SHARED_LIBS=off causes build errors.

In file included from /home/yappy/aegis.cpp/include/aegis/config.hpp:13,
                 from /home/yappy/aegis.cpp/include/aegis/channel.hpp:12,
                 from /home/yappy/aegis.cpp/include/aegis/impl/channel.cpp:10:
/home/yappy/aegis.cpp/include/aegis/fwd.hpp:12:10: fatal error: nlohmann/json_fwd.hpp: No such file or directory
 #include <nlohmann/json_fwd.hpp>
          ^~~~~~~~~~~~~~~~~~~~~~~
In file included from /home/yappy/aegis.cpp/include/aegis/config.hpp:13,
                 from /home/yappy/aegis.cpp/include/aegis/impl/core.cpp:10:
/home/yappy/aegis.cpp/include/aegis/fwd.hpp:12:10: fatal error: nlohmann/json_fwd.hpp: No such file or directory
 #include <nlohmann/json_fwd.hpp>
          ^~~~~~~~~~~~~~~~~~~~~~~
...

This patch will fix this but I don't know whether it is the best way.
fix_static_lib.patch.txt

Token Login

Response for invalid token is not processed correctly giving vague json parse error.

[Bug] Running into a ratelimit with a custom logger causes segmentation fault

Environment

  • Recent Gentoo Linux
  • gcc 10.2.0
  • CMake 3.18.5
  • aegis.cpp Version 2.7.0
  • spdlog 1.8.2
  • libfmt 7.0.3
  • ASIO (aegis fork) 1.12.2
  • Websocketpp (aegis fork) 0.7.0
  • nlohmann JSON 3.9.1

Description

When using aegis with a custom logger (tested with spdlog::sinks::basic_file_sink_mt, spdlog::sinks::basic_file_sink_st, spdlog::sinks::null_sink_mt and spdlog::sinks::stdout_color_sink_mt) running into a rate limit (e.g. by spamming messages to a channel using a while (true) {/*...*/} construct), the executable gets terminated with SIGSEGV.

Example code

An excerpt from my main() without all the #include directives and command line parsing.

	auto log_file_sink =
		std::make_shared<spdlog::sinks::basic_file_sink_mt>(logfile_path); // logfile_path is a std::string, same problem when using any other mentioned sink
	auto logger =
		std::make_shared<spdlog::logger>("my_cool_logger_name", log_file_sink);
	logger->flush_on(spdlog::level::info); // removing this line doesn't mitigate the issue

	if (log_verbose) // log_verbose is a bool and (in my tests) always true
		logger->set_level(spdlog::level::debug); // same results when using spdlog::level::trace or spdlog::level::info

	logger->debug("creating aegis::core");
        // token is a std::string
	aegis::core core(aegis::create_bot_t{}.token(token).logger(logger)); // remove .logger(logger) and everything works fine!
	core.run();

	while (true)
	{
		core.channel_create(TEST_CHANNEL_ID)->create_message("spam").get();
	}

Behaviour when the code gets executed

The program runs fine for some time, spamming the given channel with messages until the rate limit kicks in.
After that, the programm terminates immediately, leaving (at least to me) no reasonable output:

[2021-05-09 16:48:59.280] [my_cool_logger_name] [debug] creating aegis::core
[2021-05-09 16:48:59.281] [my_cool_logger_name] [info] Creating websocket
[2021-05-09 16:48:59.550] [my_cool_logger_name] [info] Shard count: 1
[2021-05-09 16:48:59.550] [my_cool_logger_name] [info] Starting shard manager with 1 shards
[2021-05-09 16:48:59.550] [my_cool_logger_name] [info] Starting bot with 1 shards
[2021-05-09 16:48:59.550] [my_cool_logger_name] [info] Websocket[s] connecting
[2021-05-09 16:48:59.650] [my_cool_logger_name] [debug] Shards to connect : 1
[2021-05-09 16:48:59.650] [my_cool_logger_name] [debug] Shard#0: connecting
[2021-05-09 16:48:59.782] [my_cool_logger_name] [debug] message::populate_self() user not found - created
[2021-05-09 16:49:01.152] [my_cool_logger_name] [debug] Shard#0: connection established
[2021-05-09 16:49:02.085] [my_cool_logger_name] [info] Shard#0 READY Processed

(same output with spdlog::level::debug and spdlog::level::trace)

gdb gives me the following:

GNU gdb (Gentoo 10.1 vanilla) 10.1
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-pc-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://bugs.gentoo.org/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./src/(my test executable)...
(gdb) r
Starting program: (my test executable) -l output.log -v -t (my token)
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
[New Thread 0x7ffff7585640 (LWP 122985)]
[New Thread 0x7ffff6d84640 (LWP 122986)]
[New Thread 0x7ffff6583640 (LWP 122987)]
[New Thread 0x7ffff5d82640 (LWP 122988)]
[New Thread 0x7ffff5555640 (LWP 122989)]

Thread 3 "(my bot name)" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff6d84640 (LWP 122986)]
0x00005555555b8bb7 in aegis::ratelimit::bucket::perform(aegis::rest::request_params) ()
(gdb) bt
#0  0x00005555555b8bb7 in aegis::ratelimit::bucket::perform(aegis::rest::request_params) ()
#1  0x00005555555ce781 in asio::detail::executor_op<asio::detail::work_dispatcher<aegis::core::async<aegis::ratelimit::ratelimit_mgr::post_task<aegis::gateway::objects::message, void>(aegis::rest::request_params)::{lambda()#1}, aegis::gateway::objects::message, void>(aegis::ratelimit::ratelimit_mgr::post_task<aegis::gateway::objects::message, void>(aegis::rest::request_params)::{lambda()#1})::{lambda()#1}>, std::allocator<void>, asio::detail::scheduler_operation>::do_complete(void*, asio::detail::scheduler_operation*, std::error_code const&, unsigned long) ()
#2  0x00005555555ff62f in asio::detail::scheduler::run(std::error_code&) ()
#3  0x0000555555601cda in asio::io_context::run() ()
#4  0x00005555555d5f8e in aegis::core::_thread_track(aegis::thread_state*) ()
#5  0x00007ffff79c9ef0 in ?? () from /usr/lib/gcc/x86_64-pc-linux-gnu/10.2.0/libstdc++.so.6
#6  0x00007ffff7e63f5e in start_thread () from /lib64/libpthread.so.0
#7  0x00007ffff781c1ef in clone () from /lib64/libc.so.6

sometimes, this is the function where the SEGV is received:

0x00005555555b8297 in void spdlog::logger::log_<fmt::v7::basic_string_view<char>, int>(spdlog::source_loc, spdlog::level::level_enum, fmt::v7::basic_string_view<char> const&, int const&) ()

Workaround

Refrain from using custom loggers or running into rate limits (good luck with that^^) for now.

Additional remarks

From the following excerpt I had the assumption that aegis might be implicitly depending on the logger being named aegis:

if (bot_config._log)
log = bot_config._log;
else
setup_logging();

spdlog::get("aegis")->debug("Ratelimit almost hit: {}({}) - waiting {}ms", rest::rest_controller::get_method(params.method), params.path, waitfor.count());

(note the spdlog::get)

However, without having searched the rest of the codebase, I assume that spdlog::get will be called elsewhere as well. Furthermore, giving the custom logger the name aegis like in the aegis codebase (see below) doesn't resolve the problem.

log = std::make_shared<spdlog::async_logger>("aegis", sinks.begin(), sinks.end(), spdlog::thread_pool(), spdlog::async_overflow_policy::block);

Another explanation might be that the file logger is too slow for the rate limit manager and somehow causes the rate limit manager to access memory which (possibly from another thread) has been deallocated by the time the memory is accessed.

Lastly, it still might be possible that the rate limit manager is the only one accessing the logger using spdlog::get() which I'd find a bit odd. But then, doing the registration of the logger wrong in a way that spdlog::get() returns an invalid pointer (possibly nullptr) could explain the symptoms. But it doesn't explain the debugger sometimes telling me that SEGV is received during an internal spdlog function call (for which I assume the logger object must have been accessed correctly).

nlohmann/json_fwd.hpp: No such file or directory

I cloned the repository with its dependencies, and built the lib:

git clone --recursive [email protected]:zeroxs/aegis.cpp
cd aegis.cpp
mkdir build
cd build
cmake ..
make
sudo make install

No error until here.

Then I created a little project, with a single main.cpp file, containing the template code given in the Readme - in which I took care to replace "TOKEN" with my bot's token, obviously.

When compiling it with

g++ -o bot src/main.cpp -Wall -Wextra -Werror

I get an error:

/usr/local/include/aegis/fwd.hpp:12:10: fatal error: nlohmann/json_fwd.hpp: No such file or directory

I'm investigating on this, looking for some lib I wouldn't have installed on my PC.

Saying hi ...

Hi there,

I'm the author of a websocket C++ library (with also http support) which has been used by other libraries already to talk to discord (you can see which ones at the bottom of the landing page). If you want to give it a try it is here -> https://github.com/machinezone/IXWebSocket

I am very biased because I wrote it ... but one thing I like about it is that it has few dependencies (zlib + a tls backend) ; it does not depend on boost so people usually find it easy to integrate in their project, and it is not too low level and uses C++11 threads etc... with callbacks.

Ciao and good luck with your library !

(this really would belong more to a 'discussion', but using a github issue instead)

aegis::guild::member_has_role gives wrong information

aegis::guild::member_has_role function always returns false for the bot, except right after the roles are changed on server side. For other users it only returns true for the role @everyone and false for everything else. This has worked in the past. Here is my code:

void showRoles(aegis::gateway::objects::message m) {
	unordered_map<aegis::snowflake, aegis::gateway::objects::role> roles = m.get_guild().get_roles();
	for (pair<aegis::snowflake, aegis::gateway::objects::role> role : roles) {
		cout << role.second.name << endl;
		unordered_map<aegis::snowflake, aegis::user*> members = m.get_guild().get_members();
		for (pair<aegis::snowflake, aegis::user*> member : members) {
			cout << member.second->get_full_name() << ": ";
			if (m.get_guild().member_has_role(member.second->get_id(), role.second.id) == true)
				cout << "True" << endl;
			else
				cout << "False" << endl;
		}
		cout << endl;
	}
}

Fill out docs

Pretty much everything listed as needing documentation needs to be added. As time goes on I fill it out slowly.

Incorrectly structured request causes create_guild_ban to fail

The code in guild.cpp for create_guild_ban incorrectly PUTs the reason and delete_message_days parameters to Discord as URL parameters. This causes an HTTP 400 Bad Request response, as the Discord docs specify that that these parameters should be sent as a JSON object, seen here.

I noticed this issue when the ban command for my bot failed, and resolved the issue by changing the code for the create_guild_ban method to the following:

AEGIS_DECL aegis::future<rest::rest_reply> guild::create_guild_ban(snowflake user_id, int8_t delete_message_days, const std::string & reason)
{
#if !defined(AEGIS_DISABLE_ALL_CACHE)
    if (!perms().can_ban())
        return aegis::make_exception_future(error::no_permission);
#endif

    std::shared_lock<shared_mutex> l(_m);

    json obj = { { "delete_message_days", delete_message_days }, { "reason", reason } };

    return _bot->get_ratelimit().post_task({ fmt::format("/guilds/{}/bans/{}", guild_id, user_id), rest::Put, obj.dump()});
}

Shard#0: disconnected. lastheartbeat(1549) lastwsevent(906) lastheartbeatack(90 6) ms ago

this issue started today it was working fine yesterday it compiles links as normal when I run it this is what I get:

2020-06-30 17:27:49.990 [I] [th#9460] : Creating websocket
2020-06-30 17:27:50.900 [I] [th#9460] : Shard count: 1
2020-06-30 17:27:50.901 [I] [th#9460] : Starting shard manager with 1 shards
2020-06-30 17:27:50.901 [I] [th#9460] : Starting bot with 1 shards
2020-06-30 17:27:50.901 [I] [th#9460] : Websocket[s] connecting
2020-06-30 17:27:51.003 [D] [th#7716] : Shards to connect : 1
2020-06-30 17:27:51.003 [D] [th#7716] : Shard#0: connecting
2020-06-30 17:27:51.693 [D] [th#15508] : Shard#0: connection established
2020-06-30 17:27:52.663 [D] [th#15508] : Shard#0: disconnected. lastheartbeat(1659) lastwsevent(969) lastheartbeatack(96
9) ms ago
2020-06-30 17:27:57.801 [D] [th#15764] : Shards to connect : 1
2020-06-30 17:27:57.802 [D] [th#15764] : Shard#0: connecting
2020-06-30 17:27:58.444 [D] [th#15508] : Shard#0: connection established
2020-06-30 17:27:59.351 [D] [th#15508] : Shard#0: disconnected. lastheartbeat(1549) lastwsevent(906) lastheartbeatack(90
6) ms ago

A couple issues I've found while trying to build.

void guild::_load(const json & obj, shards::shard * _shard) noexcept

This function is noexcept, but throws.
Also, in one of the catch clauses:

spdlog::get("aegis")->error("Shard#{} : Error processing guild[{}] {}", _shard->get_id(), g_id, (std::string)e.what());

The cast to std::string feels redundant, on top of oncurring an unnecessary construction.


Consider allowing users to use Boost.Asio instead of standalone asio (It should pretty much be a drop-in replacement, at least for versions of Boost.Asio up to 1.73 (1.74 has some namespace changes that require aliases). This is what websocketpp does, which is one of your dependency. The most egregious change is asio::system_error, since it doesn't exist in Boost.Asio: boost::system::error_code is the counterpart. In turn, because websocketpp uses std::error_code, there are calls that will no longer compile (because they used asio::system_error), and need to be manually fixed.


There are missing includes in some places (I'm not using PCH headers, maybe that's why you're not seeing those). Unfortunately, since all my edits are currently unstaged, I can't provide a diff. If you wish me to, I can try to generate one, but I heavily hacked away at config.hpp (removing the polyfills for std::optional, among other things), so I'll have to filter some changes out.


                        // shard_mgr.cpp
                        _shard->_connection = websocket_o.get_connection(gateway_url, ecs);
                        _shard->_strand = _shard->_connection->get_strand();
                        if (ecs)
                            throw ecs;

Should probably become this?

                        _shard->_connection = websocket_o.get_connection(gateway_url, ecs);
                        if (ecs)
                            throw ecs;
                        _shard->_strand = _shard->_connection->get_strand();

On MSVC, i'm getting duplicate function bodies across multiple types, namely permissions's to_json and from_json. This was deeply confusing and I just moved the implementation back into permissions.hpp. Not a clean solution, but I'm not sure why this happens.

Cheers

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.