diff --git a/.gitignore b/.gitignore index 7edc792..3b7ec64 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .env build/ .DS_Store +config.json \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index ed42d94..fd450f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -388,6 +388,43 @@ else() # which is before Concord has been built. file(MAKE_DIRECTORY "${CONCORD_INCLUDE_DIR}") + # Upstream's `make install` is three shell globs relative to the working + # directory, fed to install(1). When one matches nothing the shell passes it + # through literally and install reports `cannot stat 'include/*.h'`, which + # says nothing about which glob mattered or why. Do the copy ourselves with + # absolute paths and name the two failure modes that actually occur. + # + # The globs run at install time rather than configure time because + # gencodecs/discord_codecs.h does not exist until the build has generated it. + set(CONCORD_INSTALL_SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/concord_install.cmake") + file(CONFIGURE + OUTPUT "${CONCORD_INSTALL_SCRIPT}" + @ONLY + CONTENT [[ +file(MAKE_DIRECTORY "@CONCORD_INCLUDE_DIR@/concord" "@CONCORD_PREFIX@/lib") + +# Upstream flattens all three header directories into one include/concord. Check +# them one at a time: a single empty directory is the interesting failure, and a +# combined glob would hide it behind whichever siblings still matched. +set(_hdrs "") +foreach(_dir include core gencodecs) + file(GLOB _found "@concord_SOURCE_DIR@/${_dir}/*.h") + if(NOT _found) + message(FATAL_ERROR + "Concord: no headers in @concord_SOURCE_DIR@/${_dir} -- the source " + "tree is incomplete; remove build/_deps and reconfigure to re-clone") + endif() + list(APPEND _hdrs ${_found}) +endforeach() +file(COPY ${_hdrs} DESTINATION "@CONCORD_INCLUDE_DIR@/concord") + +file(GLOB _libs "@concord_SOURCE_DIR@/lib/libdiscord.*") +if(NOT _libs) + message(FATAL_ERROR "Concord: build produced no library in @concord_SOURCE_DIR@/lib") +endif() +file(COPY ${_libs} DESTINATION "@CONCORD_PREFIX@/lib") +]]) + # Concord gets our instrumentation but not our warning set: ASan only sees a # bug if the translation unit that owns the memory was compiled with it, and # Concord allocates plenty that our code then touches. CFLAGS goes through @@ -396,30 +433,43 @@ else() # override those and break the build. set(CONCORD_CFLAGS "-O2 -g $") + # gencodecs/Makefile hardcodes CC/HOSTCC/CPP to "cc" for its host-side code + # generator, with plain '=' assignments that the environment cannot override. + # On a system where cc is GCC and we build with Clang, the generator is then + # handed our Clang-only flags (-fno-sanitize=function) and dies. Command-line + # assignments do beat makefile assignments, so force the compiler there -- + # while leaving CFLAGS in the environment, per the note above. + # + # gencodecs-pp is a build-time text filter, run as `cpp ... | ./gencodecs-pp`. + # ASan's exit-time leak check would turn a leak in that throwaway tool into a + # build failure reported as a broken pipeline, so switch it off for the + # duration of Concord's build only; our own binary is unaffected. ExternalProject_Add(concord_external SOURCE_DIR "${concord_SOURCE_DIR}" DOWNLOAD_COMMAND "" # FetchContent already cloned it UPDATE_COMMAND "" CONFIGURE_COMMAND "" BUILD_IN_SOURCE TRUE # upstream's Makefile has no out-of-tree mode - BUILD_COMMAND ${CMAKE_COMMAND} -E env "CC=${CMAKE_C_COMPILER}" "CFLAGS=${CONCORD_CFLAGS}" + # Upstream tracks nothing we can express as a byproduct, so the stamp + # would happily report "built" after a `make clean` emptied lib/. + BUILD_ALWAYS TRUE + BUILD_COMMAND ${CMAKE_COMMAND} -E env + "CC=${CMAKE_C_COMPILER}" + "CFLAGS=${CONCORD_CFLAGS}" + "ASAN_OPTIONS=detect_leaks=0" ${HAMMY_MAKE_EXECUTABLE} - INSTALL_COMMAND ${HAMMY_MAKE_EXECUTABLE} install "PREFIX=${CONCORD_PREFIX}" + "CC=${CMAKE_C_COMPILER}" + "HOSTCC=${CMAKE_C_COMPILER}" + "CPP=${CMAKE_C_COMPILER} -E" + INSTALL_COMMAND ${CMAKE_COMMAND} -P "${CONCORD_INSTALL_SCRIPT}" BUILD_BYPRODUCTS "${CONCORD_LIBRARY}" - USES_TERMINAL_BUILD TRUE + # USES_TERMINAL_BUILD would silently disable LOG_BUILD; with + # LOG_OUTPUT_ON_FAILURE we get the full log exactly when it matters. LOG_BUILD TRUE LOG_INSTALL TRUE LOG_OUTPUT_ON_FAILURE TRUE ) - ExternalProject_Add_Step(concord_external mirror_headers - COMMAND ${CMAKE_COMMAND} -E copy_directory - "${CONCORD_INCLUDE_DIR}/concord" - "${PROJECT_SOURCE_DIR}/include/concord" - DEPENDEES install - COMMENT "Mirroring Concord headers into include/concord" - ) - add_library(concord::concord STATIC IMPORTED GLOBAL) set_target_properties(concord::concord PROPERTIES IMPORTED_LOCATION "${CONCORD_LIBRARY}" @@ -456,6 +506,14 @@ target_include_directories(hammy PRIVATE ${PROJECT_SOURCE_DIR}/include ) +target_include_directories(hammy SYSTEM PRIVATE + ${PROJECT_SOURCE_DIR}/third_party +) + +# Concord's headers arrive through concord::concord. CMake passes an imported +# target's interface includes as -isystem, so upstream's headers never trip our +# warning set and no second copy under third_party/ is needed. + target_link_libraries(hammy PRIVATE concord::concord) if(HAMMY_CONCORD_EXTERNAL) add_dependencies(hammy ${HAMMY_CONCORD_EXTERNAL}) diff --git a/include/hammy/bot.h b/include/hammy/bot.h new file mode 100644 index 0000000..a36d0cf --- /dev/null +++ b/include/hammy/bot.h @@ -0,0 +1,34 @@ +#ifndef HAMMY_BOT_H +#define HAMMY_BOT_H + +#include +#include +#include + +#include + +typedef struct { + struct discord* client; // Owning reference to the client - handoff from main.c + bool commands_registered; // A flag if commands have been registered. Avoid re-registering every reconnect. + vector_t* commands; // vector_t of commands. Owning. +} hammy_bot_t; + +// Alloc on heap and create +hammy_bot_t* hammy_bot_create(); + +// Sets the on_ready() call function pointer +bool hammy_bot_set_on_ready(hammy_bot_t* bot, void (*func)(struct discord* client, const struct discord_ready* event)); + +// Runs the bot. Return true on succeed, false on failure. +bool hammy_bot_run(hammy_bot_t* bot); + +// Adds a command to the vector as a COPY, get rid of the old struct. +bool hammy_bot_add_command(hammy_bot_t* bot, hammy_command_t* command); + +// Registers all commands. Return true if succeeded or already registered; false if failure. +bool hammy_bot_register_commands(hammy_bot_t* bot); + +// Destroy bot, NULLs the passing reference +bool hammy_bot_destroy(hammy_bot_t** bot); + +#endif diff --git a/include/hammy/command.h b/include/hammy/command.h new file mode 100644 index 0000000..df554dd --- /dev/null +++ b/include/hammy/command.h @@ -0,0 +1,17 @@ +#ifndef HAMMY_COMMAND_H +#define HAMMY_COMMAND_H + +#include + +typedef struct { + // TODO: add shit here + char empty; +} hammy_command_t; + +// Creates the command on the heap, returns NULL if failed. +hammy_command_t* hammy_command_create(); + +// Destroys a command. +void hammy_command_destroy(void* cmd); + +#endif diff --git a/src/hammy/bot.c b/src/hammy/bot.c new file mode 100644 index 0000000..32ca995 --- /dev/null +++ b/src/hammy/bot.c @@ -0,0 +1,80 @@ +#include + +hammy_bot_t* hammy_bot_create() { + hammy_bot_t* bot = (hammy_bot_t*)malloc(sizeof(hammy_bot_t)); + if (!bot) { + return NULL; + } + + // Set defaults + bot->client = NULL; + bot->commands_registered = false; + bot->commands = vector_create(sizeof(hammy_command_t)); + + // Check if vector allocation errored + if (!bot->commands) { + free(bot); + return NULL; + } + + if (vector_set_destructor(bot->commands, &hammy_command_destroy) < 0) { + vector_destroy(&bot->commands); + free(bot); + return NULL; + } + + // Init the discord client - even though this is an owning reference, the main() and others may call functions on it (if we don't stay singlethread anymore then FIX THIS) + bot->client = discord_from_json("config.json"); + if (!bot->client) { + vector_destroy(&bot->commands); + free(bot); + return NULL; + } + + return bot; +} + +bool hammy_bot_set_on_ready(hammy_bot_t* bot, void (*func)(struct discord* client, const struct discord_ready* event)) { + if (!bot || !func || !bot->client) { return false; } + + discord_set_on_ready(bot->client, func); + return true; +} + +bool hammy_bot_run(hammy_bot_t* bot) { + if (!bot || !bot->client) { return false; } + + discord_run(bot->client); + + return true; +} + +bool hammy_bot_add_command(hammy_bot_t* bot, hammy_command_t* command) { + if (!bot || !command) { return false; } + + // Push into commands vector + if (vector_push_back(bot->commands, command) < 0) { + return false; + } + + return true; +} + +bool hammy_bot_register_commands(hammy_bot_t* bot) { + if (!bot) { return false; } + + // TODO: Figure out registration logic +} + +bool hammy_bot_destroy(hammy_bot_t** bot) { + if (!bot || !(*bot)) { return false; } + + if ((*bot)->client) { + discord_cleanup((*bot)->client); + } + + // TODO: Potential other stuff here + vector_destroy(&(*bot)->commands); // commands is NULL form hereon, calls destructors on commands automatically + free(*bot); + *bot = NULL; +} diff --git a/src/hammy/command.c b/src/hammy/command.c new file mode 100644 index 0000000..bdcf7ac --- /dev/null +++ b/src/hammy/command.c @@ -0,0 +1,24 @@ +#include + +hammy_command_t* hammy_command_create() { + hammy_command_t* cmd = (hammy_command_t*)malloc(sizeof(hammy_command_t)); + if (!cmd) { + return NULL; + } + + // TODO: set defaults + + return cmd; +} + +void hammy_command_destroy(void* cmd) { + if (!cmd) { + return; + } + + cmd = (hammy_command_t*)cmd; + + // TODO: Other things here eventually + + free(cmd); +} diff --git a/src/main.c b/src/main.c index 526e5ce..9f3f0e4 100644 --- a/src/main.c +++ b/src/main.c @@ -1,21 +1,43 @@ #include -#include +#include #include +#include + +static void on_signal(int sig) { + (void)sig; + discord_shutdown_all(); +} + void on_ready(struct discord* client, const struct discord_ready* event) { + (void)client; log_info("Logged in as %s", event->user->username); } int main(void) { + struct sigaction sa = { 0 }; + sa.sa_handler = &on_signal; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; /* deliberately no SA_RESTART */ + + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + ccord_global_init(); - struct discord* client = discord_config_init("config.json"); + hammy_bot_t* bot = hammy_bot_create(); + if (!bot) { + log_error("Hammy Bot creation returned NULL! Bailing!"); + ccord_global_cleanup(); - discord_set_on_ready(client, &on_ready); + return 1; + } + + hammy_bot_set_on_ready(bot, &on_ready); + hammy_bot_run(bot); // This will block and exit afterwards + + hammy_bot_destroy(&bot); - discord_run(client); - - discord_cleanup(client); ccord_global_cleanup(); return 0; diff --git a/include/concord/all.PRE.h b/third_party/concord/all.PRE.h similarity index 100% rename from include/concord/all.PRE.h rename to third_party/concord/all.PRE.h diff --git a/include/concord/anomap.h b/third_party/concord/anomap.h similarity index 100% rename from include/concord/anomap.h rename to third_party/concord/anomap.h diff --git a/include/concord/application_command.h b/third_party/concord/application_command.h similarity index 100% rename from include/concord/application_command.h rename to third_party/concord/application_command.h diff --git a/include/concord/attributes.h b/third_party/concord/attributes.h similarity index 100% rename from include/concord/attributes.h rename to third_party/concord/attributes.h diff --git a/include/concord/audit_log.h b/third_party/concord/audit_log.h similarity index 100% rename from include/concord/audit_log.h rename to third_party/concord/audit_log.h diff --git a/include/concord/auto_moderation.h b/third_party/concord/auto_moderation.h similarity index 100% rename from include/concord/auto_moderation.h rename to third_party/concord/auto_moderation.h diff --git a/include/concord/carray.h b/third_party/concord/carray.h similarity index 100% rename from include/concord/carray.h rename to third_party/concord/carray.h diff --git a/include/concord/channel.h b/third_party/concord/channel.h similarity index 100% rename from include/concord/channel.h rename to third_party/concord/channel.h diff --git a/include/concord/chash.h b/third_party/concord/chash.h similarity index 100% rename from include/concord/chash.h rename to third_party/concord/chash.h diff --git a/include/concord/clock.h b/third_party/concord/clock.h similarity index 100% rename from include/concord/clock.h rename to third_party/concord/clock.h diff --git a/include/concord/cog-utils.h b/third_party/concord/cog-utils.h similarity index 100% rename from include/concord/cog-utils.h rename to third_party/concord/cog-utils.h diff --git a/include/concord/concord-error.h b/third_party/concord/concord-error.h similarity index 100% rename from include/concord/concord-error.h rename to third_party/concord/concord-error.h diff --git a/include/concord/concord-notifier.h b/third_party/concord/concord-notifier.h similarity index 100% rename from include/concord/concord-notifier.h rename to third_party/concord/concord-notifier.h diff --git a/include/concord/concord-once.h b/third_party/concord/concord-once.h similarity index 100% rename from include/concord/concord-once.h rename to third_party/concord/concord-once.h diff --git a/include/concord/discord-cache.h b/third_party/concord/discord-cache.h similarity index 100% rename from include/concord/discord-cache.h rename to third_party/concord/discord-cache.h diff --git a/include/concord/discord-events.h b/third_party/concord/discord-events.h similarity index 100% rename from include/concord/discord-events.h rename to third_party/concord/discord-events.h diff --git a/include/concord/discord-internal.h b/third_party/concord/discord-internal.h similarity index 100% rename from include/concord/discord-internal.h rename to third_party/concord/discord-internal.h diff --git a/include/concord/discord-request.h b/third_party/concord/discord-request.h similarity index 100% rename from include/concord/discord-request.h rename to third_party/concord/discord-request.h diff --git a/include/concord/discord-response.h b/third_party/concord/discord-response.h similarity index 100% rename from include/concord/discord-response.h rename to third_party/concord/discord-response.h diff --git a/include/concord/discord-worker.h b/third_party/concord/discord-worker.h similarity index 100% rename from include/concord/discord-worker.h rename to third_party/concord/discord-worker.h diff --git a/include/concord/discord.h b/third_party/concord/discord.h similarity index 100% rename from include/concord/discord.h rename to third_party/concord/discord.h diff --git a/include/concord/discord_codecs.PRE.h b/third_party/concord/discord_codecs.PRE.h similarity index 100% rename from include/concord/discord_codecs.PRE.h rename to third_party/concord/discord_codecs.PRE.h diff --git a/include/concord/discord_codecs.h b/third_party/concord/discord_codecs.h similarity index 100% rename from include/concord/discord_codecs.h rename to third_party/concord/discord_codecs.h diff --git a/include/concord/emoji.h b/third_party/concord/emoji.h similarity index 100% rename from include/concord/emoji.h rename to third_party/concord/emoji.h diff --git a/include/concord/gateway.h b/third_party/concord/gateway.h similarity index 100% rename from include/concord/gateway.h rename to third_party/concord/gateway.h diff --git a/include/concord/gencodecs-process.PRE.h b/third_party/concord/gencodecs-process.PRE.h similarity index 100% rename from include/concord/gencodecs-process.PRE.h rename to third_party/concord/gencodecs-process.PRE.h diff --git a/include/concord/gencodecs.h b/third_party/concord/gencodecs.h similarity index 100% rename from include/concord/gencodecs.h rename to third_party/concord/gencodecs.h diff --git a/include/concord/guild.h b/third_party/concord/guild.h similarity index 100% rename from include/concord/guild.h rename to third_party/concord/guild.h diff --git a/include/concord/guild_scheduled_event.h b/third_party/concord/guild_scheduled_event.h similarity index 100% rename from include/concord/guild_scheduled_event.h rename to third_party/concord/guild_scheduled_event.h diff --git a/include/concord/guild_template.h b/third_party/concord/guild_template.h similarity index 100% rename from include/concord/guild_template.h rename to third_party/concord/guild_template.h diff --git a/include/concord/interaction.h b/third_party/concord/interaction.h similarity index 100% rename from include/concord/interaction.h rename to third_party/concord/interaction.h diff --git a/include/concord/invite.h b/third_party/concord/invite.h similarity index 100% rename from include/concord/invite.h rename to third_party/concord/invite.h diff --git a/include/concord/io_poller.h b/third_party/concord/io_poller.h similarity index 100% rename from include/concord/io_poller.h rename to third_party/concord/io_poller.h diff --git a/include/concord/jsmn-find.h b/third_party/concord/jsmn-find.h similarity index 100% rename from include/concord/jsmn-find.h rename to third_party/concord/jsmn-find.h diff --git a/include/concord/jsmn.h b/third_party/concord/jsmn.h similarity index 100% rename from include/concord/jsmn.h rename to third_party/concord/jsmn.h diff --git a/include/concord/json-build.h b/third_party/concord/json-build.h similarity index 100% rename from include/concord/json-build.h rename to third_party/concord/json-build.h diff --git a/include/concord/log.h b/third_party/concord/log.h similarity index 100% rename from include/concord/log.h rename to third_party/concord/log.h diff --git a/include/concord/logmod.h b/third_party/concord/logmod.h similarity index 100% rename from include/concord/logmod.h rename to third_party/concord/logmod.h diff --git a/include/concord/oa_hash.h b/third_party/concord/oa_hash.h similarity index 100% rename from include/concord/oa_hash.h rename to third_party/concord/oa_hash.h diff --git a/include/concord/oauth2.h b/third_party/concord/oauth2.h similarity index 100% rename from include/concord/oauth2.h rename to third_party/concord/oauth2.h diff --git a/include/concord/osname.h b/third_party/concord/osname.h similarity index 100% rename from include/concord/osname.h rename to third_party/concord/osname.h diff --git a/include/concord/priority_queue.h b/third_party/concord/priority_queue.h similarity index 100% rename from include/concord/priority_queue.h rename to third_party/concord/priority_queue.h diff --git a/include/concord/queriec.h b/third_party/concord/queriec.h similarity index 100% rename from include/concord/queriec.h rename to third_party/concord/queriec.h diff --git a/include/concord/queue.h b/third_party/concord/queue.h similarity index 100% rename from include/concord/queue.h rename to third_party/concord/queue.h diff --git a/include/concord/stage_instance.h b/third_party/concord/stage_instance.h similarity index 100% rename from include/concord/stage_instance.h rename to third_party/concord/stage_instance.h diff --git a/include/concord/sticker.h b/third_party/concord/sticker.h similarity index 100% rename from include/concord/sticker.h rename to third_party/concord/sticker.h diff --git a/include/concord/threadpool.h b/third_party/concord/threadpool.h similarity index 100% rename from include/concord/threadpool.h rename to third_party/concord/threadpool.h diff --git a/include/concord/types.h b/third_party/concord/types.h similarity index 100% rename from include/concord/types.h rename to third_party/concord/types.h diff --git a/include/concord/user-agent.h b/third_party/concord/user-agent.h similarity index 100% rename from include/concord/user-agent.h rename to third_party/concord/user-agent.h diff --git a/include/concord/user.h b/third_party/concord/user.h similarity index 100% rename from include/concord/user.h rename to third_party/concord/user.h diff --git a/include/concord/voice.h b/third_party/concord/voice.h similarity index 100% rename from include/concord/voice.h rename to third_party/concord/voice.h diff --git a/include/concord/webhook.h b/third_party/concord/webhook.h similarity index 100% rename from include/concord/webhook.h rename to third_party/concord/webhook.h diff --git a/include/concord/websockets.h b/third_party/concord/websockets.h similarity index 100% rename from include/concord/websockets.h rename to third_party/concord/websockets.h diff --git a/include/dlibc/vector.h b/third_party/dlibc/vector.h similarity index 100% rename from include/dlibc/vector.h rename to third_party/dlibc/vector.h