some infra
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
.env
|
.env
|
||||||
build/
|
build/
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
config.json
|
||||||
+69
-11
@@ -388,6 +388,43 @@ else()
|
|||||||
# which is before Concord has been built.
|
# which is before Concord has been built.
|
||||||
file(MAKE_DIRECTORY "${CONCORD_INCLUDE_DIR}")
|
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
|
# 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
|
# 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
|
# Concord allocates plenty that our code then touches. CFLAGS goes through
|
||||||
@@ -396,30 +433,43 @@ else()
|
|||||||
# override those and break the build.
|
# override those and break the build.
|
||||||
set(CONCORD_CFLAGS "-O2 -g $<JOIN:${HAMMY_INSTRUMENT_COMPILE}, >")
|
set(CONCORD_CFLAGS "-O2 -g $<JOIN:${HAMMY_INSTRUMENT_COMPILE}, >")
|
||||||
|
|
||||||
|
# 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
|
ExternalProject_Add(concord_external
|
||||||
SOURCE_DIR "${concord_SOURCE_DIR}"
|
SOURCE_DIR "${concord_SOURCE_DIR}"
|
||||||
DOWNLOAD_COMMAND "" # FetchContent already cloned it
|
DOWNLOAD_COMMAND "" # FetchContent already cloned it
|
||||||
UPDATE_COMMAND ""
|
UPDATE_COMMAND ""
|
||||||
CONFIGURE_COMMAND ""
|
CONFIGURE_COMMAND ""
|
||||||
BUILD_IN_SOURCE TRUE # upstream's Makefile has no out-of-tree mode
|
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}
|
${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}"
|
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_BUILD TRUE
|
||||||
LOG_INSTALL TRUE
|
LOG_INSTALL TRUE
|
||||||
LOG_OUTPUT_ON_FAILURE 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)
|
add_library(concord::concord STATIC IMPORTED GLOBAL)
|
||||||
set_target_properties(concord::concord PROPERTIES
|
set_target_properties(concord::concord PROPERTIES
|
||||||
IMPORTED_LOCATION "${CONCORD_LIBRARY}"
|
IMPORTED_LOCATION "${CONCORD_LIBRARY}"
|
||||||
@@ -456,6 +506,14 @@ target_include_directories(hammy PRIVATE
|
|||||||
${PROJECT_SOURCE_DIR}/include
|
${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)
|
target_link_libraries(hammy PRIVATE concord::concord)
|
||||||
if(HAMMY_CONCORD_EXTERNAL)
|
if(HAMMY_CONCORD_EXTERNAL)
|
||||||
add_dependencies(hammy ${HAMMY_CONCORD_EXTERNAL})
|
add_dependencies(hammy ${HAMMY_CONCORD_EXTERNAL})
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
#ifndef HAMMY_BOT_H
|
||||||
|
#define HAMMY_BOT_H
|
||||||
|
|
||||||
|
#include <concord/discord.h>
|
||||||
|
#include <dlibc/vector.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <hammy/command.h>
|
||||||
|
|
||||||
|
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
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#ifndef HAMMY_COMMAND_H
|
||||||
|
#define HAMMY_COMMAND_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
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
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
#include <hammy/bot.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#include <hammy/command.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
+28
-6
@@ -1,21 +1,43 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <concord/discord.h>
|
#include <signal.h>
|
||||||
#include <concord/log.h>
|
#include <concord/log.h>
|
||||||
|
|
||||||
|
#include <hammy/bot.h>
|
||||||
|
|
||||||
|
static void on_signal(int sig) {
|
||||||
|
(void)sig;
|
||||||
|
discord_shutdown_all();
|
||||||
|
}
|
||||||
|
|
||||||
void on_ready(struct discord* client, const struct discord_ready* event) {
|
void on_ready(struct discord* client, const struct discord_ready* event) {
|
||||||
|
(void)client;
|
||||||
log_info("Logged in as %s", event->user->username);
|
log_info("Logged in as %s", event->user->username);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void) {
|
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();
|
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();
|
ccord_global_cleanup();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user