cogmasters / concord Goto Github PK
View Code? Open in Web Editor NEWA Discord API wrapper library made in C
Home Page: https://cogmasters.github.io/concord/
License: MIT License
A Discord API wrapper library made in C
Home Page: https://cogmasters.github.io/concord/
License: MIT License
Lines 68 to 69 in 769bdb7
The OUT_O
produced here gets linked with the rest of the code that's built with the cross-compiling CC
for the target platform, but this currently uses the same CC
that's used in the rest of gencodecs
to target the host platform. Attempting to cross-compile to a different platform will thus abort at the linking step, when the linker rejects the object in the wrong format.
aarch64-unknown-linux-gnu-gcc -shared -lcurl -o ../lib/libdiscord.so concord-once.o discord-refcount.o discord-rest.o discord-rest_request.o discord-rest_ratelimit.o discord-client.o discord-events.o discord-cache.o discord-loop.o discord-gateway.o discord-gateway_dispatch.o discord-messagecommands.o discord-timer.o discord-misc.o discord-worker.o application_command.o auto_moderation.o interaction.o audit_log.o channel.o emoji.o gateway.o guild.o guild_scheduled_event.o guild_template.o invite.o oauth2.o user.o voice.o webhook.o ../gencodecs/discord_codecs.o ../core/cog-utils.o ../core/io_poller.o ../core/user-agent.o ../core/websockets.o ../core/curl-websocket.o ../core/jsmn-find.o ../core/json-build.o ../core/log.o ../core/logconf.o ../core/priority_queue.o ../core/anomap.o ../core/sha1.o ../core/threadpool.o ../core/queriec.o
/nix/store/lvr57hbrpjvg7jyh0j2a1bx2cvwypjqh-aarch64-unknown-linux-gnu-binutils-2.40/bin/aarch64-unknown-linux-gnu-ld: ../gencodecs/discord_codecs.o: Relocations in generic ELF (EM: 62)
/nix/store/lvr57hbrpjvg7jyh0j2a1bx2cvwypjqh-aarch64-unknown-linux-gnu-binutils-2.40/bin/aarch64-unknown-linux-gnu-ld: ../gencodecs/discord_codecs.o: Relocations in generic ELF (EM: 62)
/nix/store/lvr57hbrpjvg7jyh0j2a1bx2cvwypjqh-aarch64-unknown-linux-gnu-binutils-2.40/bin/aarch64-unknown-linux-gnu-ld: ../gencodecs/discord_codecs.o: error adding symbols: file in wrong format
collect2: error: ld returned 1 exit status
/tmp/nix-build-concord-aarch64-unknown-linux-gnu-2.2.1.drv-0/source/src/discord-refcount.o: ELF 64-bit LSB relocatable, ARM aarch64, version 1 (SYSV), with debug_info, not stripped
/tmp/nix-build-concord-aarch64-unknown-linux-gnu-2.2.1.drv-0/source/gencodecs/discord_codecs.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
gencodecs/Makefile
uses separate HOST_CC
& HOST_CPP
variables (or whatever standard name they might have, if any) for the host-platform-targeting things, and inherits the target-platform-targeting CC
from the main Makefile
HOST_CC
/ HOST_CPP
to target the host platform, while the linked line uses CC
to cross-compile for the target platformn/a
Use a cross-compiling CC
for a target where objects for the host & target platform cannot be mixed (i.e. x86_64 and aarch64, not glibc x86_64 and musl x86_64)
Concord 2.2.1
Linux, 64-bit
Distributor ID: NixOS
Description: NixOS 23.05 (Stoat)
Release: 23.05
Codename: stoat
When I call discord_cleanup in a build using TSAN, I get diagnostic messages stating a locked mutex is being destroyed.
WARNING: ThreadSanitizer: destroy of a locked mutex (pid=24515)
#0 pthread_mutex_destroy ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1244 (libtsan.so.0+0x39398)
#1 threadpool_free <null> (game.so+0xcea1d)
[redacted]
and:
#0 pthread_mutex_lock ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:4240 (libtsan.so.0+0x53908)
#1 threadpool_free <null> (game.so+0xcea15)
[redacted]
Looking in threadpool.c and the threadpool_free function it seems you are intentionally locking the mutex just prior to deletion. I don't think this impacts the program's functionality in any way, but it is undefined behaviour according to the spec.
If the lock is just to make sure anything else that could have been using it has terminated, then you should be able to add in an unlock immediately after the lock and prior to the destroy. If there is a concern that something else could try to initiate a new lock on the mutex at this point in the code where you're destroying it, then I'd imagine that is a completely separate concurrency issue that would need to be resolved elsewhere.
commit 1da91a6 (HEAD, tag: v2.1.0)
Distributor ID: Ubuntu
Description: Ubuntu 22.04.1 LTS
Release: 22.04
Codename: jammy
I am not attempting to debug or QA concord's threading implementation. I am merely debugging my own threaded code in my library that uses concord and was very confused upon seeing these diagnostics. The similar orca library has the same "issue" fyi and given that it does not seem to actually have any negative impact aside from that noise in tsan when closing my application, it's understandable if you elect to just leave it as it is.
A bucket is frozen once a 429 is triggered, making so consecutive requests of the same bucket group never reach Discord.
It shouldn't lock the bucket's incoming requests.
The following example from @Anotra can trigger the issue:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <concord/discord.h>
#define TEST_FILE "..." // change to some file to be sent over Discord
static void
on_message_create(struct discord *client, const struct discord_message *message) {
if (strcmp(message->content, "quit") == 0) {
discord_shutdown(client);
} else if (!message->author->bot) {
discord_create_message(client, message->channel_id,
&(struct discord_create_message) {
.content = message->content,
}, NULL);
discord_create_message(client, message->channel_id,
&(struct discord_create_message) {
.attachments = &(struct discord_attachments) {
.realsize = 1, .size = 1,
.array = &(struct discord_attachment) {
.filename = TEST_FILE,
},
}
}, NULL);
}
}
int
main() {
struct discord *client = discord_config_init("../config.json");
discord_add_intents(client, DISCORD_GATEWAY_MESSAGE_CONTENT);
discord_set_on_message_create(client, on_message_create);
discord_run(client);
discord_cleanup(client);
}
2.1.0
Because those are technically the same HTTP method, it should also be the same value when generating a bucket key. Currently Concord will generate two different buckets for the same route, leading to wrong ratelimiting handling for those buckets.
Generate the same bucket key for some route using either method.
The following code from @Anotra can reproduce the error, it will trigger a 429 even though we're handling ratelimiting:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <concord/discord.h>
#define TEST_FILE "..." // change to some file to be sent over Discord
static void
on_message_create(struct discord *client, const struct discord_message *message) {
if (strcmp(message->content, "quit") == 0) {
discord_shutdown(client);
} else if (!message->author->bot) {
discord_create_message(client, message->channel_id,
&(struct discord_create_message) {
.content = message->content,
}, NULL);
discord_create_message(client, message->channel_id,
&(struct discord_create_message) {
.attachments = &(struct discord_attachments) {
.realsize = 1, .size = 1,
.array = &(struct discord_attachment) {
.filename = TEST_FILE,
},
}
}, NULL);
}
}
int
main() {
struct discord *client = discord_config_init("../config.json");
discord_add_intents(client, DISCORD_GATEWAY_MESSAGE_CONTENT);
discord_set_on_message_create(client, on_message_create);
discord_run(client);
discord_cleanup(client);
}
v2.1.0
Hello,
Using discord_modify_channel results in the following error :
[31mERROR�[0m �[90mdiscord-rest_request.c:391:�[0m [DISCORD_REQUEST] {"code": 50035, "errors": {"rtc_region": {"_errors": [{"code": "BASE_TYPE_CHOICES", "message": "Value must be one of ('brazil', 'hongkong', 'india', 'japan', 'rotterdam', 'russia', 'singapore', 'south-korea', 'southafrica', 'sydney', 'us-central', 'us-east', 'us-south', 'us-west')."}]}}, "message": "Invalid Form Body"}
It happens when I want to rename a discord channel. The channel doesn't get renamed, the request fails.
It doesn't work on the the version 2.1.0, 2.2.0, and the current master branch.
Do you observe the same issue ?
Thanks,
The assertion
Assert Failed: (size_t)len < (size_t)sizeof(b->hash)
aborts at src/discord-ratelimit.c:33:.
I believe this is due to DISCORD_ROUTE_LEN being defined as 64 and the
length of the string which is being given to the assertion is 71. The string
generated can be found in the stack trace:
#0 0x00007ffff7d9e34c in __pthread_kill_implementation () from /usr/lib/libc.so.6
#1 0x00007ffff7d514b8 in raise () from /usr/lib/libc.so.6
#2 0x00007ffff7d3b534 in abort () from /usr/lib/libc.so.6
#3 0x00005555555d4e93 in _discord_route_init (adapter=0x55555561a6b0,
route=0x55555580e5ec ":5:applications:%lu:guilds:896679108350722109:commands:%lu:permissions", b=0x555555819520)
at src/discord-ratelimit.c:33
#4 0x00005555555d73e2 in _discord_bucket_get_match (adapter=0x55555561a6b0,
route=0x55555580e5ec ":5:applications:%lu:guilds:896679108350722109:commands:%lu:permissions",
info=0x7fffffffd8c0) at src/discord-ratelimit.c:205
#5 0x00005555555d7c5f in discord_bucket_build (adapter=0x55555561a6b0, b=0x5555556194a0,
route=0x55555580e5ec ":5:applications:%lu:guilds:896679108350722109:commands:%lu:permissions",
info=0x7fffffffd8c0) at src/discord-ratelimit.c:371
#6 0x00005555555d3e28 in _discord_adapter_check_action (adapter=0x55555561a6b0, msg=0x55555561ff50)
at src/discord-adapter.c:810
#7 0x00005555555d4279 in discord_adapter_perform (adapter=0x55555561a6b0) at src/discord-adapter.c:882
#8 0x00005555555cfdbd in on_io_poller_curl (io=0x555555618ec0, mhandle=0x5555556188e0, user_data=0x55555561a6b0)
at src/discord-adapter.c:37
#9 0x00005555555cb38e in io_poller_perform (io=0x555555618ec0) at core/io_poller.c:111
#10 0x000055555555a016 in discord_run (client=0x55555561a600) at src/discord-client.c:353
#11 0x0000555555558888 in main (argc=1, argv=0x7fffffffe808) at wikid.c:78
Source code can be found here: https://github.com/arcnyxx/wikid
Using Concord with latest commit hash fe93008.
I use this library for an IRC relay (bot), and it would be helpful to be able to use the @silent
feature that seems to exist now, particularly for IRC join/part/quit messages, to avoid notifying everyone on Discord when these events happen, as there are currently a lot of complaints about this.
The message flag is documented here: https://github.com/discord/discord-api-docs/pull/5894/files
I confirmed by analyzing the network requests that the only different when using this feature is the flag is indeed set to 4096 (1 << 12), as opposed to 0, so this appears to be correct.
It appears that this would be the right place to add the flag: https://github.com/Cogmasters/concord/blob/master/gencodecs/api/channel.PRE.h#L30
I'm less certain about how the flag would be used. The only place I see any flags being used is here:
Line 195 in 769bdb7
However, I would think that flags would need to be provided in create_message
, e.g. here:
Line 220 in 769bdb7
Since I don't see this, would the ability to specify flags when sending a message need to be added as well, or is the other example the proper way to send messages if flags need to be added? I'm less sure about this, otherwise I think this should be a fairly straightforward addition.
Chash seems to not be saving properly data, being unable to find the saved data when after passed some seconds of saving it.
Chash should properly find the data related to the key.
A example of this bug is in my lib repo, where it only NOT works with FreeBSD, where this could also affect Concord ratelimiting system, that also uses chash.
Bug found on Concord latest dev, but could affect all versions with chash.
The FreeBSD version is 13.1. and this issue was made, even not being directly related to Concord, because chash not working could cause the Concord ratelimiting to not work. This issue is NOT confirmed, if someone is able to test on FreeBSD (please check that Concord ratelimit functions that uses chash to save info only are called with some specific tasks, basic bots, like a ping-pong bot shouldn't use it in a normal condition).
Please check that the same code using chash was tested on Ubuntu, Arch Linux and Termux, all of them worked properly, except in FreeBSD.
Opening a new ticket for this, there was some initial discussion of this on #135
I'm now able to get presence data, but it seems presence->size
can be smaller than members->size
in the event.
From looking at http.log
, it seems the JSON array really only is that large, so perhaps this is an API issue:
discord/discord-api-docs@12b414e
Since this was initially "undocumented", I wonder whether this is also an "undocumented limitation". It's also not consistent, now when I last tried it, I only got 28 presences, instead of 34 like before (still far under 77). I can confirm there's only one chunk received, so it's not as if the presences are getting split.
One workaround may be to retry any users we didn't get presence data in another request, filtered to such user(s), although it would be nice if the API response worked properly in the first place... oh well. It's very possible there's not much that can be done in this case.
Returning to the other thing I had mentioned, this seems like something that may not be quite right:
struct discord_channel dchannel;
struct discord_ret_channel ret2 = { .sync = &dchannel };
cp->channel_id = channel->id;
code = discord_get_channel(client, channel->id, &ret2);
if (code != CCORD_OK) {
continue;
}
/* At this point dchannel.member is NULL */
(It's hard to parse the official APIs, but this suggests that accessing recipients is the right way to get channel members: https://stackoverflow.com/questions/50840580/how-to-retrieve-a-list-of-discord-users-in-a-channel)
I thought perhaps maybe member is not set by default (like how the other API requires .presences = true
in order to get presence data, but there doesn't seem to be any such boolean flag, so I would assume members should always be returned. Some of the other data is set, but this one is NULL.
This is from the HTTP logs:
17:42:25 TRACE discord-rest_ratelimit.c:252: [DISCORD_RATELIMIT] [null] Couldn't match known buckets to ':1:channels:REDACTED'
17:42:25 DEBUG discord-rest_ratelimit.c:301: [DISCORD_RATELIMIT] [miss] Match ':1:channels:REDACTED' to bucket
17:42:25 DEBUG discord-rest_ratelimit.c:357: [DISCORD_RATELIMIT] [miss] Remaining = 1 | Reset = 0
[2023-02-06 17:42:25.817] ERROR[653098]: mod_discord.c:401 fetch_channels: Failed to fetch member list for channel REDACTED
Edit: I realize I should be using recipients
rather than members
, but both are actually NULL.
Looking at http.log
, unfortunately this data doesn't seem to be present, either, which is incongruent with their API documentation to me.
So I'm not sure if either of these is very actionable, but I know there was a fix for something, so I guess that can be linked against this issue instead now.
We should support the X-Audit-Log-Reason
header for any request that may include it, and the option of passing the reason
string
X-Audit-Log-Reason
header field includedv2.1.0
discord_start_thread_with_message_params is missing rate_limit_per_user
.
discord_start_thread_without_message_params is missing invitable
& rate_limit_per_user
.
The largest possible message length is 4,000, not 2,000.
Add client callbacks for On Reconnect, On Shutdown and On Error. Clients should be able to deal with those events on-demand, as they might have a method of logging or resource management that requires listening to these events.
discord_set_on_xxx()
methods for each one of the eventsv2.1.0
Can I see an example of bot which doesn't use config file (datas are already given while coding)
Thank
This issue is for keeping track of the many guides that should help make Concord a more welcoming place to newcomers. If you got any suggestions, feel free to write them down below!
NOTE: all of the following should be added to docs/guides/
config.json
filesenv
variablesv2.1.0
I am receiving the following errors when linking libdiscord.a to a shared library.
/usr/bin/ld: concord-prefix/lib/libdiscord.a(discord-worker.o): warning: relocation against `g_tpool' in read-only section `.text'
/usr/bin/ld: concord-prefix/lib/libdiscord.a(user-agent.o): relocation R_X86_64_PC32 against symbol `L' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: bad value
My personal preference would be that static libraries use -fPIC by default so they can be linked into either executables or shared libraries. Barring that, I think it would be perfectly fine though to just maybe have a simple mention in the README.md build instructions that you might need to run CLFLAGS="-fPIC" make
if linking into a shared library. Alternatively a separate static_pic target could be added to the makefile, but I think that might be overkill when its easy enough to add to the CFLAGS as long as you know that's what you need to do.
make
or make static
.This occurs on both master and dev branches.
commit 072e414 (HEAD -> master, origin/master, origin/HEAD)
commit d703210 (HEAD -> dev, origin/dev)
Distributor ID: Ubuntu
Description: Ubuntu 22.04.1 LTS
Release: 22.04
Codename: jammy
The default prefix written at config.json won't register.
ERROR discord-rest_request.c:382: [DISCORD_REQUEST] {"code": 50035, "errors": {"attachments": {"1": {"_errors": [{"code": "ATTACHMENT_NOT_FOUND", "message": "Attachment data not found"}]}}}, "message": "Invalid Form Body"}
This error only occurs when more than one attachment has been included. Otherwise, using one or the other works.
Replacing the strings with proper files should reproduce the error:
struct discord_attachment load_attachment(char* filename) {
char full_path[128];
snprintf(full_path, sizeof(full_path), "File/Path/%s", filename);
size_t fsize = 0;
char *fbuf = cog_load_whole_file(full_path, &fsize);
struct discord_attachment attachment = {
.filename = filename,
.content = fbuf,
.size = fsize
};
return attachment;
}
void embed_create(struct discord *client, const struct discord_message *msg) {
if (msg->author->bot) return;
struct discord_embed embed = {
.image = &(struct discord_embed_image) {
.url = "attachment://file_name.png"
},
.thumbnail = &(struct discord_embed_thumbnail) {
.url = "attachment://file_name.png"
}
};
struct discord_attachment add_image = load_attachment("file_name.png");
struct discord_attachment add_thumbnail = load_attachment("file_name.png");
struct discord_create_message params = {
.embeds = &(struct discord_embeds) {
.size = 1,
.array = &embed
},
.attachments = &(struct discord_attachments) {
.size = 2,
.array = (struct discord_attachment[]) {add_image, add_thumbnail}
}
};
discord_create_message(client, msg->channel_id, ¶ms, NULL);
}
Update from HTTP 1.0 to HTTP 1.1, should be a straightforward curl_easy_setopt() operation.
discord-rest_request.c
V2.1.0
I'm using libdiscord
in a shared library module that I built for a large multithreaded application, e.g. Concord is only a very small part of the entire program, and there are lots of other threads. Everything is pretty much working, but I'm having segmentation faults on shut down, and it appears it may be because I'm shutting down the client in one thread, and perhaps this isn't legal. I looked at some of the code and it appears if have_sigint
is set, then discord_run
will exit. I'm not using SIGINT because that only makes sense for a standalone program, but perhaps this suggests that there's no way to terminate a session "out of band" (apart from this mechanism)? Is this the right understanding?
Essentially, I have this (some stuff removed for conciseness):
static void *discord_relay(void *varg)
{
struct discord *client = varg;
discord_run(client);
return NULL;
}
static int load_module(void)
{
ccord_global_init();
discord_client = discord_init(token);
if (!discord_client) {
return -1;
}
discord_add_intents(discord_client, DISCORD_GATEWAY_MESSAGE_CONTENT | DISCORD_GATEWAY_GUILD_MESSAGES | DISCORD_GATEWAY_GUILD_MEMBERS);
discord_set_on_ready(discord_client, &on_ready);
discord_set_on_message_create(discord_client, &on_message_create);
discord_set_on_message_update(discord_client, &on_message_update);
discord_set_on_guild_members_chunk(discord_client, &on_guild_members_chunk);
if (pthread_create(&discord_thread, NULL, discord_relay, discord_client)) {
discord_shutdown(discord_client);
discord_cleanup(discord_client);
ccord_global_cleanup();
return -1;
}
return 0;
}
static int unload_module(void)
{
discord_shutdown(discord_client);
pthread_join(discord_thread, NULL);
discord_cleanup(discord_client);
ccord_global_cleanup();
return 0;
}
I initially had this ordering:
discord_shutdown(discord_client);
discord_cleanup(discord_client);
pthread_join(discord_thread, NULL);
When I did this, I got segmentation faults in the thread with discord_run
, suggesting that perhaps it is not legal to call discord_shutdown
in another thread. However, I need to be able to do that... how else can I tell the client to exit?
With the ordering shown in the larger snippet, pthread_join
never returns, so the unload blocks forever (though no crash).
Is there an example or suggested approaching for doing an out of band shutdown as I'm trying to do here? I'd think this would be a common use case, but I didn't find any examples of it. It seems like there is a race condition here with the way I'm currently doing it that leads to the discord_run
thread trying to read invalid memory... and if I don't call discord_shutdown
, then the discord_run
thread won't exit, so I'm not sure if there's a way around that.
Perhaps something like the following could be added to src/concord-once.c
? (Although I'm not positive if this would be the right fix or not.)
static void ccord_shutdown_notify(int signum)
{
ccord_has_sigint = 1;
}
My thinking is this would allow the discord_thread to gracefully exit on its own, and then I could call pthread_join
directly, since the discord_run
thread itself appears to call discord_shutdown
on its own. So really, maybe what's need is just a way to asynchronously shut down using a public function, generically, not just the internal SIGINT handler which doesn't apply to every use case. (Correct me if I'm wrong, but I don't think this currently exists from what I could find.)
This happens consistently if I shut down my program (which unloads all dynamic modules), but not always (only sometimes) if I only attempt to unload the Discord module:
==534690== 1 errors in context 16 of 29:
==534690== Invalid read of size 8
==534690== at 0x4F273D3: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.7.0)
==534690== by 0x4EF747F: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.7.0)
==534690== by 0x4F0A32F: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.7.0)
==534690== by 0x4F286AF: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.7.0)
==534690== by 0x4F298D6: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.7.0)
==534690== by 0x4F2A225: curl_multi_perform (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.7.0)
==534690== by 0x4F2A562: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.7.0)
==534690== by 0x4F2A679: curl_multi_socket_all (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.7.0)
==534690== by 0x9253F2C: ws_multi_socket_run (in /usr/local/lib/libdiscord.so)
==534690== by 0x91CAA39: discord_gateway_perform (in /usr/local/lib/libdiscord.so)
==534690== by 0x91C9EFF: _discord_on_gateway_perform (in /usr/local/lib/libdiscord.so)
==534690== by 0x924E86F: io_poller_perform (in /usr/local/lib/libdiscord.so)
==534690== Address 0xb485e50 is 192 bytes inside a block of size 6,440 free'd
==534690== at 0x48399AB: free (vg_replace_malloc.c:538)
==534690== by 0x4F0A89A: ??? (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.7.0)
==534690== by 0x4F00B78: curl_easy_cleanup (in /usr/lib/x86_64-linux-gnu/libcurl.so.4.7.0)
==534690== by 0x92550AE: _cws_cleanup (in /usr/local/lib/libdiscord.so)
==534690== by 0x9256F10: cws_free (in /usr/local/lib/libdiscord.so)
==534690== by 0x9253325: ws_cleanup (in /usr/local/lib/libdiscord.so)
==534690== by 0x91CA291: discord_gateway_cleanup (in /usr/local/lib/libdiscord.so)
==534690== by 0x91C56FB: discord_cleanup (in /usr/local/lib/libdiscord.so)
==534690== by 0x9183699: unload_module (mod_discord.c:409)
==534944== 2 errors in context 17 of 34:
==534944== Invalid read of size 4
==534944== at 0x4FE09F9: pthread_mutex_trylock (pthread_mutex_trylock.c:42)
==534944== by 0xFB6EEBB: discord_requestor_dispatch_responses (in /usr/local/lib/libdiscord.so)
==534944== by 0xFB761AB: discord_run (in /usr/local/lib/libdiscord.so)
==534944== by 0x9183207: discord_relay (mod_discord.c:322)
==534944== by 0x134D81: thread_run (thread.c:252)
==534944== by 0x4FDDEA6: start_thread (pthread_create.c:477)
==534944== by 0x50F4A2E: clone (clone.S:95)
==534944== Address 0xfac8be0 is 96 bytes inside a block of size 120 free'd
==534944== at 0x48399AB: free (vg_replace_malloc.c:538)
==534944== by 0xFB6E213: discord_requestor_cleanup (in /usr/local/lib/libdiscord.so)
==534944== by 0xFB6D93F: discord_rest_cleanup (in /usr/local/lib/libdiscord.so)
==534944== by 0xFB736E9: discord_cleanup (in /usr/local/lib/libdiscord.so)
==534944== by 0x9183699: unload_module (mod_discord.c:409)
Describe the bug
Calling discord_bulk_overwrite_global_application_command
with partial application command data results in an API error, stating that "the command has an invalid ID".
Expected behavior
Bulk overwriting of commands should work with partial application command data.
To Reproduce
Any call to discord_bulk_overwrite_global_application_command
with application commands with no IDs should trigger the bug.
Version
aa57b19 (master)
Stack trace
N/A
Additional context
I briefly looked at the issue with a debugger, looks like the issue is that the library serializes the ID of the partial commands (which is 0), which results in the Discord API erroring out. The correct behavior would be to omit the ID from the body.
Support ETF formatting for WebSockets payloads, which is supposed to be a much more lightweight alternative to JSON.
gencodecs
specs for initializing some data from its unique xxx_from_etf()
methodv2.1.0
Something with the installation went wrong.
Commands run on Raspberry Pi (64-bit):
apt update && apt install -y libcurl4-openssl-dev
git clone https://github.com/cogmasters/concord.git && cd concord
make
gcc myBot.c -o myBot -pthread -ldiscord -lcurl
(either in concord
or just outside of concord
, still does not work)
No LSB modules are available.
Distributor ID: Debian
Description: Debian GNU/Linux 11 (bullseye)
Release: 11
Codename: bullseye
When using cflag CCORD_SIGINTCATCH, the signal handler will call fputs(unsafe), and locks and unlocks a mutex(unsafe).
fputs has been there since inception, mutex was introduced in PR #140
Shipping a simple pkg-config file would make adding this library to CMake- or Meson-based projects more straightforward.
Any, to my knowledge.
This is what file would probably look like when installed:
prefix=/usr
libdir=${prefix}/lib
includedir=${prefix}/include
Name: Concord
Description: A Discord API wrapper library made in C
URL: https://cogmasters.github.io/concord/
Version: 2.2.1
Libs: -L${libdir} -ldiscord
Requires.private: libcurl
Cflags: -I${includedir}
The first line should be set to prefix used for installation. Probably just echo
ing into file directly from Makefile (and then calling install
on it) is sufficient in this case.
I am encountering a "server didn't accept the websocket upgrade" error when trying to connect to Discord's server using an HTTP proxy.
I expected to be able to connect to the server without encountering any errors. Investigate whether libcurl is able to detect if an HTTP proxy is being used and where we can go from there:
N/A
== Info: Uses proxy env variable no_proxy == '127.0.0.0/8,localhost,::1'
== Info: Uses proxy env variable https_proxy == 'http://127.0.0.1:48157'
== Info: Hostname 127.0.0.1 was found in DNS cache
== Info: Trying 127.0.0.1:48157...
== Info: TCP_NODELAY set
== Info: Connected to 127.0.0.1 (127.0.0.1) port 48157 (#2)
== Info: allocate connect buffer!
== Info: Establish HTTP proxy tunnel to gateway.discord.gg:443
=> Send header, 0000000103 bytes (0x00000067)
0000: 43 4f 4e 4e 45 43 54 20 67 61 74 65 77 61 79 2e CONNECT gateway.
0010: 64 69 73 63 6f 72 64 2e 67 67 3a 34 34 33 20 48 discord.gg:443 H
0020: 54 54 50 2f 31 2e 31 0d 0a 48 6f 73 74 3a 20 67 TTP/1.1
0029: 48 6f 73 74 3a 20 67 61 74 65 77 61 79 2e 64 69 Host: gateway.di
0039: 73 63 6f 72 64 2e 67 67 3a 34 34 33 0d 0a 50 72 scord.gg:443
0047: 50 72 6f 78 79 2d 43 6f 6e 6e 65 63 74 69 6f 6e Proxy-Connection
0057: 3a 20 4b 65 65 70 2d 41 6c 69 76 65 0d 0a 0d 0a : Keep-Alive
0065: 0d 0a
<= Recv header, 0000000017 bytes (0x00000011)
0000: 48 54 54 50 2f 31 2e 31 20 32 30 30 20 4f 4b 0d HTTP/1.1 200 OK
<= Recv header, 0000000037 bytes (0x00000025)
0000: 64 61 74 65 3a 20 54 75 65 2c 20 30 39 20 4d 61 date: Tue, 09 Ma
0010: 79 20 32 30 32 33 20 31 36 3a 31 34 3a 33 38 20 y 2023 16:14:38
0020: 47 4d 54 0d 0a GMT
<= Recv header, 0000000002 bytes (0x00000002)
0000: 0d 0a
There is a bit of a problem when building on OpenBSD, which seems to be from the codecs generation.
This happens on a fresh OpenBSD installation, with all dependencies for Concord installed.
The expected behavior is that the build should complete correctly-- it does not.
Here is a textual error log, as well as some screenshots.
Install a new OpenBSD virtual machine, pkg_add git, clone Concord, and perform make
One of the payloads requested to be sent (not the Discord websocket) sometimes takes too long to be sent (up to ~15 seconds), while the first one rapidly is sent.
The websocket payload in some milliseconds after concord websocket say it has been sent, the server receive the payload.
You can reproduce it compiling my repo of a Concord music bot and start playing a music.
Concord version: latest dev
Flags used while compiling Concord: -DCCORD_SIGINTCATCH
OS: Ubuntu 22 latests [x64]
The server (Lavalink) is running locally, and the first payload is rapidly sent (in milliseconds), just the second one that takes way too long (much more than expected).
Older versions of the codebase of this bot, manually implementing the websocket directly to the discord_run (custom version) is much faster than the actual one using on_cycle to send payloads.
Code:
void on_cycle(struct discord *client) {
(void) client;
uint64_t tstamp;
ws_easy_run(g_ws, 5, &tstamp);
}
...
// Function used to send payloads:
void sendPayload(char payload[], char *payloadOP) {
if (ws_send_text(g_ws, NULL, payload, strlen(payload)) == false) {
log_fatal("[LIBCURL] Something went wrong while sending a payload with op %s to Lavalink.", payloadOP);
return;
} else {
log_debug("[LIBCURL] Sucessfully sent a payload with op %s to Lavalink.", payloadOP);
}
}
// Inside main function:
struct ws_callbacks cbs = {
.on_text = &on_text,
.on_connect = &on_connect,
.on_close = &on_close,
.data = client
};
CURLM *mhandle = curl_multi_init();
g_ws = ws_init(&cbs, mhandle, NULL); // MEMORY LEAK (2)
struct ccord_szbuf_readonly value = discord_config_get_field(client, (char *[2]){ "lavalink", "hostname" }, 2);
snprintf(lavaHostname, sizeof(lavaHostname), "%.*s", (int)value.size, value.start);
char lavaWs[256];
snprintf(lavaWs, sizeof(lavaWs), "wss://%s", lavaHostname);
ws_set_url(g_ws, lavaWs, NULL);
ws_start(g_ws);
value = discord_config_get_field(client, (char *[2]){ "lavalink", "password" }, 2);
snprintf(lavaPasswd, sizeof(lavaPasswd), "%.*s", (int)value.size, value.start);
const struct discord_user *bot = discord_get_self(client);
snprintf(botID, sizeof(botID), "%"PRIu64"", bot->id);
ws_add_header(g_ws, "Authorization", lavaPasswd);
ws_add_header(g_ws, "Num-Shards", "1"); // You may want to change this.
ws_add_header(g_ws, "User-Id", botID);
ws_add_header(g_ws, "Client-Name", "MusicBotWithConcord");
There are some static buffer sizes in discord-gateway_dispatch.c
that can be too small for large requests, causing truncation of the JSON payload and causing the Discord API to disconnect us, aborting any requests in progress. For example, this limit can be hit when requesting guild members with a payload of between 40 and 45 users, with a buffer size of 1024.
This commit partially addresses this with a stopgap fix: b860d9f
Seems like dynamic allocation should be used instead?
If the ws hoster shutdowns, it will happen a high CPU usage.
after using discord_create_message, how do i get the messages ID so i can edit it?
Sharding is a must-have feature for larger bots that require scaling through multiple servers. At its current state, concord is not a viable option for building large-scale bots, adding this feature would be a great step in the right direction.
v2.1.0
I was trying to build the bot and encountered a Make error, that I don't know how to solve. I tried running the Cygwin terminal as administrator along with cygstart --action=runas make
and no luck.
Expected it to be built just fine.
Install Cygwin normally, along with the packages required by the repository, clone the repository, enter, run make
and this happens.
Latest, as of writing this.
Windows 10 64-bit.
make[1]: Entering directory 'C:/cygwin64/home/user11/concord/core'
cc -O2 -std=c99 -pthread -D_XOPEN_SOURCE=600 -DLOG_USE_COLOR -I. -I/usr/local/in
clude -c -o cog-utils.o cog-utils.c
process_begin: CreateProcess(C:\cygwin64\bin\cc, cc -O2 -std=c99 -pthread -D_XOP
EN_SOURCE=600 -DLOG_USE_COLOR -I. -I/usr/local/include -c -o cog-utils.o cog-uti
ls.c, ...) failed.
make (e=5): Access is denied.
make[1]: *** [: cog-utils.o] Error 5
make[1]: Leaving directory 'C:/cygwin64/home/user11/concord/core'
make: *** [Makefile:26: static] Error 2
user-specified memory functions are hyperbased for a whole host of reasons, we've thoroughly discussed it in the discord, and I will make a PR to implement them Soon™ unless someone objects, in which case we go back to the drawing board.
Currently, concord uses the dynamic memory allocation routines provided by the OS. It does not check their return values, even though they can fail. This is probably fine -- not elegant or correct, but perfectly usable.
This backwards-compatible change would introduce a function ccord_global_init_memory
, which would take as arguments the following five function pointers:
void *malloc_fn(size_t length)
, a malloc
equivalent.
void *calloc_fn(size_t nmemb, size_t length)
, a calloc
equivalent.
void *realloc_fn(void *old_ptr, size_t length)
, a realloc
equivalent.
void free_fn(void *ptr)
, a free
equivalent.
char *strdup_fn(const char *str)
, a strdup
equivalent.
The names are irrelevant, please reply if you wish for them to be changed.
All functions must be thread-safe. They need not be async-signal-safe (Async-signal-safety would be impractical for many implementations).
The functions must behave as follows:
malloc_fn
allocates exactly length
bytes of memory and returns a pointer to it. It must return a valid pointer or abort execution. The returned pointer must be suitably aligned for any type. If length
is 0
or exceeds PTRDIFF_MAX
, the behavior is undefined.calloc_fn
allocates memory for exactly length
items of size nmemb
and returns a pointer to it. It must return a valid pointer or abort execution. The returned pointer must be suitably aligned for any type. If length
or nmemb
are 0
, or the value of length * nmemb
exceeds PTRDIFF_MAX
, or the multiplication overflows, the behavior is undefined.realloc_fn
returns a pointer to a new allocation of length length
for the data in old_ptr
. It must return a valid pointer or abort execution. It need not (but may) return old_ptr. The returned pointer must be suitably aligned for any type. If length
is 0
or exceeds PTRDIFF_MAX
, the behavior is undefined.free_fn
releases the memory pointed to by ptr
. It must succeed or abort execution. If ptr
is a null pointer, it must return without any operation being performed.strdup_fn
returns a new allocation for the null-terminated string pointed to by str
. It must return a valid pointer or abort execution. The returned pointer need not be aligned. If str
is a null pointer, or the length of str exceeds PTRDIFF_MAX
, the behavior is undefined.The function ccord_global_init_memory
would:
curl_global_init_mem
with callbacks derived from these function pointers, as specified by libcurl.ccord_global_init
.The implementation of ccord_global_init
would change as follows:
ccord_global_init_memory
with callbacks derived from the system's implementation of these functions.The interface and behavior of ccord_global_init
would not change. This change is entirely backwards compatible.
To prevent decision fatigue and confusion for the library user, a note stating that ccord_global_init_memory
is reserved for advanced use cases exclusively, and that ccord_global_init
should be used, would be prominently displayed in the documentation.
All calls to malloc
, calloc
, realloc
, free
, and strdup
would need to be converted to calls to internal functions with identical signatures. No other alterations to the calling code would be required, making porting trivial. These functions would, in debugging builds of concord, assert compliance with the interface specified above, verifying the existing assumption that memory allocation functions cannot fail.
I have sought critique on the discord server. This led to the following reasoning for the choices made:
curl_free
to release memory acquired by libcurl. This is invalid, as curl's memory allocation debugging is implemented on top of the memory allocation functions provided to it.I would happily implement this. I may underestimate the scope of this change, but I do not expect it to be particularly technically challenging, difficult to implement cleanly and elegantly, or labor-intensive.
Thank you for considering this proposal.
The current API for Voice Connection should be rewritten, as it relies on the outdated paradigm of starting a thread per voice connection, and does not support sending/receiving data packets. Voice adds extra dependencies, therefore, including it in the build should be optional.
v2.1.0
Although Discord is no longer endorsing message-content-based bots, smaller bots should still be able to take full advantage of it in the future. For this reason, adding an API for Message Collectors can be of great use.
v2.1.0
For references, see discord.js Collectors
Support zlib payload decompressing for incoming WebSockets payloads.
v2.1.0
If you enable default_prefix in config.json you immediately segfault.
{
"logging": {
"level": "trace",
"filename": "logs/bot.log",
"quiet": true,
"overwrite": true,
"use_color": true,
"http": {
"enable": true,
"filename": "logs/http.log"
},
"disable_modules": ["WEBSOCKETS", "USER_AGENT"]
},
"discord": {
"token": "ODIzMzExMDAxMTcxNjU2NzU0.YFe-Hw.qslT7vAgbxU_sZi4J5hqWQcld4A",
"default_prefix": {
"enable": true,
"prefix": "."
}
}
}
Output Segmentation fault
I am at the latest change in the master branch. I am running under kali-rolling in WSL2. Although I had this same behavior in arch and debian.
(gdb) run
Starting program: /home/mazy/programming/discode/discode/build/discode
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff6f69640 (LWP 2845)]
[New Thread 0x7ffff6768640 (LWP 2846)]
Thread 1 "discode" received signal SIGSEGV, Segmentation fault.
__strnlen_avx2 () at ../sysdeps/x86_64/multiarch/strlen-avx2.S:74
74 ../sysdeps/x86_64/multiarch/strlen-avx2.S: No such file or directory.
==2905== Memcheck, a memory error detector
==2905== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==2905== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==2905== Command: ./discode
==2905==
==2905== Invalid read of size 1
==2905== at 0x48457B9: strnlen (vg_replace_strmem.c:461)
==2905== by 0x4989F4D: __vfprintf_internal (vfprintf-internal.c:1647)
==2905== by 0x499C175: __vsnprintf_internal (vsnprintf.c:114)
==2905== by 0x4976B41: snprintf (snprintf.c:31)
==2905== by 0x1142FA: discord_gateway_init (discord-gateway.c:1480)
==2905== by 0x10D2F8: _discord_init (discord-client.c:19)
==2905== by 0x10D5B2: discord_config_init (discord-client.c:80)
==2905== by 0x10B705: main (main.c:124)
==2905== Address 0x29 is not stack'd, malloc'd or (recently) free'd
==2905==
==2905==
==2905== Process terminating with default action of signal 11 (SIGSEGV)
==2905== Access not within mapped region at address 0x29
==2905== at 0x48457B9: strnlen (vg_replace_strmem.c:461)
==2905== by 0x4989F4D: __vfprintf_internal (vfprintf-internal.c:1647)
==2905== by 0x499C175: __vsnprintf_internal (vsnprintf.c:114)
==2905== by 0x4976B41: snprintf (snprintf.c:31)
==2905== by 0x1142FA: discord_gateway_init (discord-gateway.c:1480)
==2905== by 0x10D2F8: _discord_init (discord-client.c:19)
==2905== by 0x10D5B2: discord_config_init (discord-client.c:80)
==2905== by 0x10B705: main (main.c:124)
==2905== If you believe this happened as a result of a stack
==2905== overflow in your program's main thread (unlikely but
==2905== possible), you can try to increase the size of the
==2905== main thread stack using the --main-stacksize= flag.
==2905== The main thread stack size used in this run was 8388608.
==2905==
==2905== HEAP SUMMARY:
==2905== in use at exit: 209,505 bytes in 3,648 blocks
==2905== total heap usage: 5,174 allocs, 1,526 frees, 277,335 bytes allocated
==2905==
==2905== LEAK SUMMARY:
==2905== definitely lost: 0 bytes in 0 blocks
==2905== indirectly lost: 0 bytes in 0 blocks
==2905== possibly lost: 640 bytes in 2 blocks
==2905== still reachable: 208,865 bytes in 3,646 blocks
==2905== suppressed: 0 bytes in 0 blocks
==2905== Rerun with --leak-check=full to see details of leaked memory
==2905==
==2905== For lists of detected and suppressed errors, rerun with: -s
==2905== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault
Describe the bug
If you try to use the log functions to enable logging, it won't enable.
Expected behavior
It would enable the logging.
To Reproduce
struct logconf *conf = discord_get_logconf(client);
logconf_set_quiet(conf, false);
Version
Latest, dev
Check to see if server member has a permission of some sort.
u64bitmask discord_get_member_permissions(const struct discord_guild_member* member) {
u64bitmask permissions = 0;
for (int i = 0; i < member->roles->size; ++i) {
permissions |= member->roles->array[i].permissions;
}
return permissions;
}
Though, maybe a function like bool discord_member_has_permission(const struct discord_guild_member* member, unsigned int code)
(maybe unsigned int
should be something else) could also be implemented.
Discord chat (credit goes to @lcsmuller).
Add an alternative method for initializing a client with some settings (such as logging), without requiring the config.json
file. This would add greater flexibility to the user, as they might use their own custom logic for parsing of their configuration fields.
Possible implementation:
struct discord_settings settings = {
.token = BOT_TOKEN,
.prefix = "!",
.logging = {
.level = DISCORD_LOG_LEVEL_TRACE,
.filename = "bot.log",
.quiet = false,
.http = "http.log",
},
};
struct discord *client = discord_settings_init(&settings);
discord_config_init()
to be calling this new method underneathv2.1.0
Describe the bug
Describe what you see that (you think) is wrong.
The library is not setting the timestamp member in discord_message struct instances.
Expected behavior
I expect the member to be set to the timestamp of when the message was sent
To Reproduce
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "concord/discord.h"
void on_message_create(struct discord *client, const struct discord_message *msg)
{
if (msg->author->bot)
return;
printf("A message was created at: %lu\n", msg->timestamp);
}
int main(int argc, char *argv[])
{
const char *config_file;
if (argc > 1)
config_file = argv[1];
else
config_file = "./config.json";
ccord_global_init();
struct discord *client = discord_config_init(config_file);
assert(NULL != client && "Couldn't initialize client");
discord_set_on_message_create(client, &on_message_create);
discord_run(client);
discord_cleanup(client);
ccord_global_cleanup();
}
Version
I installed the library from source yesterday, but I deleted the cloned repo so I can't give the top hash
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 20.04.4 LTS
Release: 20.04
Codename: focal
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.