mirror of
https://github.com/WCBROW01/zblock.git
synced 2025-12-11 20:18:07 -05:00
[main.c] Complete list functionality
This commit is contained in:
207
arena.c
Normal file
207
arena.c
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
/* This arena allocator implementation was created by Will Brown (WCBROW01).
|
||||||
|
* Orginal source can be found at: https://github.com/WCBROW01/arena-allocator
|
||||||
|
* Licensed under the MIT License (c) 2022-2024 Will Brown */
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdalign.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "arena.h"
|
||||||
|
|
||||||
|
#define next_multiple(a, b) ((a) + (b) - (a) % (b))
|
||||||
|
#define MEM_ALIGNMENT alignof(max_align_t)
|
||||||
|
#define align(n) ((n) % MEM_ALIGNMENT == 0 ? (n) : next_multiple(n, MEM_ALIGNMENT))
|
||||||
|
|
||||||
|
// The arena region itself is allocated after the contents of the struct.
|
||||||
|
struct Arena {
|
||||||
|
size_t size;
|
||||||
|
size_t tmp_size;
|
||||||
|
void *last_block;
|
||||||
|
void *next_block;
|
||||||
|
Arena *next_region;
|
||||||
|
bool dynamic;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get the start address of the arena
|
||||||
|
static inline void *Arena_start(Arena *arena) {
|
||||||
|
return arena + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocates a fixed-size arena. Accepts the size of the arena in bytes.
|
||||||
|
Arena *Arena_new(size_t size) {
|
||||||
|
Arena *new_arena = malloc(sizeof(Arena) + size);
|
||||||
|
|
||||||
|
*new_arena = (Arena) {
|
||||||
|
.size = size,
|
||||||
|
.tmp_size = 0,
|
||||||
|
.last_block = NULL,
|
||||||
|
.next_block = Arena_start(new_arena),
|
||||||
|
.next_region = NULL,
|
||||||
|
.dynamic = false
|
||||||
|
};
|
||||||
|
|
||||||
|
return new_arena;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocates a dynamically-sized arena. Accepts the initial size of the arena in bytes.
|
||||||
|
* If there is not enough space in the arena for an allocation, a new region will be created. */
|
||||||
|
Arena *Arena_new_dynamic(size_t size) {
|
||||||
|
Arena *new_arena = malloc(sizeof(Arena) + size);
|
||||||
|
|
||||||
|
*new_arena = (Arena) {
|
||||||
|
.size = size,
|
||||||
|
.tmp_size = 0,
|
||||||
|
.last_block = NULL,
|
||||||
|
.next_block = Arena_start(new_arena),
|
||||||
|
.next_region = NULL,
|
||||||
|
.dynamic = true
|
||||||
|
};
|
||||||
|
|
||||||
|
return new_arena;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Frees the entire arena from memory.
|
||||||
|
void Arena_delete(Arena *arena) {
|
||||||
|
if (arena->next_region != NULL) Arena_delete(arena->next_region);
|
||||||
|
free(arena);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_DIAG
|
||||||
|
static void print_diagnostic(Arena *arena, size_t size) {
|
||||||
|
fprintf(stderr, "Diagnostic info:\n");
|
||||||
|
fprintf(stderr, "Arena size: %zu bytes\n", arena->size);
|
||||||
|
fprintf(stderr, "Amount currently allocated: %zu bytes\n", arena->next_block - Arena_start(arena));
|
||||||
|
fprintf(stderr, "New block size: %zu bytes\n", size);
|
||||||
|
fprintf(stderr, "New size upon success: %zu bytes\n", arena->next_block + align(size) - Arena_start(arena));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline void *Arena_init_block(Arena *arena, size_t size) {
|
||||||
|
size_t blksize = align(size);
|
||||||
|
arena->tmp_size += blksize;
|
||||||
|
void *new_block = arena->next_block;
|
||||||
|
arena->last_block = new_block;
|
||||||
|
arena->next_block += blksize;
|
||||||
|
return new_block;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Will return a null pointer if you've tried allocating too much memory.
|
||||||
|
void *Arena_alloc(Arena *arena, size_t size) {
|
||||||
|
if (arena->next_block + align(size) > Arena_start(arena) + arena->size) {
|
||||||
|
if (arena->dynamic) {
|
||||||
|
if (arena->next_region == NULL) {
|
||||||
|
// If the size is too large for a region, make a special region for only that block.
|
||||||
|
size_t region_size = size > arena->size ? size : arena->size;
|
||||||
|
arena->next_region = Arena_new_dynamic(region_size);
|
||||||
|
return Arena_init_block(arena->next_region, size);
|
||||||
|
} else {
|
||||||
|
return Arena_alloc(arena->next_region, size);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
#ifdef ENABLE_DIAG
|
||||||
|
fprintf(stderr, "Allocation too large. You've attempted to allocate a block of memory past the end of the arena.\n");
|
||||||
|
print_diagnostic(arena, size);
|
||||||
|
#endif
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Arena_init_block(arena, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Identical to Arena_alloc but it zeros your memory
|
||||||
|
void *Arena_allocz(Arena *arena, size_t size) {
|
||||||
|
return memset(Arena_alloc(arena, size), 0, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy a block of memory into an arena.
|
||||||
|
* Functionally equivalent to memcpy. */
|
||||||
|
void *Arena_copy(Arena *arena, const void *src, size_t size) {
|
||||||
|
void *new_block = Arena_alloc(arena, size);
|
||||||
|
if (new_block == NULL) {
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
memcpy(new_block, src, size);
|
||||||
|
return new_block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the pointer is to the last allocation, it will be resized.
|
||||||
|
* Otherwise, a new allocation will be created.
|
||||||
|
* Be careful with this! A null pointer will be returned upon error.
|
||||||
|
* Using this with memory outside of the arena is undefined behavior. */
|
||||||
|
void *Arena_realloc(Arena *arena, void *ptr, size_t size) {
|
||||||
|
if (ptr == arena->last_block) {
|
||||||
|
if (arena->last_block + align(size) > Arena_start(arena) + arena->size) {
|
||||||
|
if (arena->dynamic) {
|
||||||
|
return Arena_copy(arena, ptr, size);
|
||||||
|
} else {
|
||||||
|
#ifdef ENABLE_DIAG
|
||||||
|
fprintf(stderr, "Allocation too large. You've attempted to allocate a block of memory past the end of the arena.\n");
|
||||||
|
print_diagnostic(arena, size - (arena->next_block - arena->last_block));
|
||||||
|
#endif
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
arena->next_block = arena->last_block + align(size);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Arena_copy(arena, ptr, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Marks the beginning of a temporary buffer that can be deallocated at any time.
|
||||||
|
* The state of the last one is saved in case you have multiple. */
|
||||||
|
void Arena_tmp_begin(Arena *arena) {
|
||||||
|
size_t tmp_size = arena->tmp_size;
|
||||||
|
void *last_block = arena->last_block;
|
||||||
|
arena->tmp_size = 0;
|
||||||
|
|
||||||
|
void *state = Arena_alloc(arena, sizeof(size_t) + sizeof(void*));
|
||||||
|
if (state == NULL) return;
|
||||||
|
*(size_t*) state = tmp_size;
|
||||||
|
*(void**) (state + sizeof(void*)) = last_block;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tmp_rewind(Arena *arena, bool *complete) {
|
||||||
|
void *stateloc = arena->next_block - arena->tmp_size;
|
||||||
|
if (arena->next_region != NULL) {
|
||||||
|
tmp_rewind(arena->next_region, complete);
|
||||||
|
arena->next_region = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*complete) return;
|
||||||
|
|
||||||
|
if (stateloc == Arena_start(arena)) {
|
||||||
|
Arena_delete(arena);
|
||||||
|
} else {
|
||||||
|
arena->tmp_size = *(size_t*) stateloc;
|
||||||
|
arena->last_block = *(void**) (stateloc + sizeof(size_t));
|
||||||
|
arena->next_block = stateloc;
|
||||||
|
*complete = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deallocates the last temporary buffer. If there is none,
|
||||||
|
* the entire arena will be deallocated. */
|
||||||
|
void Arena_tmp_rewind(Arena *arena) {
|
||||||
|
bool complete = false;
|
||||||
|
|
||||||
|
if (arena->next_region != NULL) {
|
||||||
|
tmp_rewind(arena->next_region, &complete);
|
||||||
|
arena->next_region = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!complete) {
|
||||||
|
void *stateloc = arena->next_block - arena->tmp_size;
|
||||||
|
if (stateloc != Arena_start(arena)) {
|
||||||
|
arena->tmp_size = *(size_t*) stateloc;
|
||||||
|
arena->last_block = *(void**) (stateloc + sizeof(size_t));
|
||||||
|
}
|
||||||
|
arena->next_block = stateloc;
|
||||||
|
}
|
||||||
|
}
|
||||||
52
arena.h
Normal file
52
arena.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/* This arena allocator implementation was created by Will Brown (WCBROW01).
|
||||||
|
* Orginal source can be found at: https://github.com/WCBROW01/arena-allocator
|
||||||
|
* Licensed under the MIT License (c) 2022-2024 Will Brown */
|
||||||
|
|
||||||
|
#ifndef ARENA_H
|
||||||
|
#define ARENA_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct Arena Arena;
|
||||||
|
|
||||||
|
// Allocates a fixed-size arena. Accepts the size of the arena in bytes.
|
||||||
|
Arena *Arena_new(size_t size);
|
||||||
|
|
||||||
|
/* Allocates a dynamically-sized arena. Accepts the initial size of the arena in bytes.
|
||||||
|
* If there is not enough space in the arena for an allocation, a new region will be created. */
|
||||||
|
Arena *Arena_new_dynamic(size_t size);
|
||||||
|
|
||||||
|
// Frees the entire arena from memory.
|
||||||
|
void Arena_delete(Arena *arena);
|
||||||
|
|
||||||
|
// Will return a null pointer if you've tried allocating too much memory.
|
||||||
|
void *Arena_alloc(Arena *arena, size_t size);
|
||||||
|
|
||||||
|
// Identical to Arena_alloc but it zeros your memory
|
||||||
|
void *Arena_allocz(Arena *arena, size_t size);
|
||||||
|
|
||||||
|
/* Copy a block of memory into an arena.
|
||||||
|
* Functionally equivalent to memcpy. */
|
||||||
|
void *Arena_copy(Arena *arena, const void *src, size_t size);
|
||||||
|
|
||||||
|
/* If the pointer is to the last allocation, it will be resized.
|
||||||
|
* Otherwise, a new allocation will be created.
|
||||||
|
* Be careful with this! A null pointer will be returned upon error.
|
||||||
|
* Using this with memory outside of the arena is undefined behavior. */
|
||||||
|
void *Arena_realloc(Arena *arena, void *ptr, size_t size);
|
||||||
|
|
||||||
|
/* Marks the beginning of a temporary buffer that can be deallocated at any time.
|
||||||
|
* The state of the last one is saved in case you have multiple. */
|
||||||
|
void Arena_tmp_begin(Arena *arena);
|
||||||
|
|
||||||
|
/* Deallocates the last temporary buffer. If there is none,
|
||||||
|
* the entire arena will be deallocated. */
|
||||||
|
void Arena_tmp_rewind(Arena *arena);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
172
main.c
172
main.c
@ -1,3 +1,4 @@
|
|||||||
|
#include <assert.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -19,6 +20,7 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "feed_info.h"
|
#include "feed_info.h"
|
||||||
|
#include "arena.h"
|
||||||
|
|
||||||
// Function pointer type for commands
|
// Function pointer type for commands
|
||||||
typedef void (*command_func)(struct discord *, const struct discord_interaction *);
|
typedef void (*command_func)(struct discord *, const struct discord_interaction *);
|
||||||
@ -263,48 +265,142 @@ static void bot_command_remove(struct discord *client, const struct discord_inte
|
|||||||
discord_create_interaction_response(client, event->id, event->token, &res, NULL);
|
discord_create_interaction_response(client, event->id, event->token, &res, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define LIST_PAGE_SIZE 5
|
||||||
|
|
||||||
|
// The arena everything gets allocated to will be returned in the arena pointer
|
||||||
|
static struct discord_interaction_callback_data *list_data_create(u64snowflake channel_id, int page_number, Arena **arena) {
|
||||||
|
assert(arena && "No arena provided"); // this is programmer error
|
||||||
|
// clamp page number
|
||||||
|
page_number = page_number < 1 ? 1 : page_number;
|
||||||
|
|
||||||
|
*arena = Arena_new(8192); // this should be more than enough
|
||||||
|
struct discord_interaction_callback_data *data = Arena_allocz(*arena, sizeof(*data));
|
||||||
|
|
||||||
|
int64_t count;
|
||||||
|
zblock_feed_info_err error = zblock_feed_info_count_channel(database_conn, channel_id, &count);
|
||||||
|
if (error) {
|
||||||
|
char *msg = Arena_alloc(*arena, sizeof(DISCORD_MAX_MESSAGE_LEN));
|
||||||
|
snprintf(msg, DISCORD_MAX_MESSAGE_LEN, "Error creating list: %s", zblock_feed_info_strerror(error));
|
||||||
|
data->content = msg;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
int last_page_number = count ? count % LIST_PAGE_SIZE ? count / LIST_PAGE_SIZE + 1 : count / LIST_PAGE_SIZE : 1;
|
||||||
|
|
||||||
|
zblock_feed_info feeds[LIST_PAGE_SIZE];
|
||||||
|
int num_retrieved;
|
||||||
|
error = zblock_feed_info_retrieve_chunk_channel(database_conn, channel_id, (page_number - 1) * LIST_PAGE_SIZE, LIST_PAGE_SIZE, feeds, &num_retrieved);
|
||||||
|
if (error) {
|
||||||
|
char *msg = Arena_alloc(*arena, sizeof(DISCORD_MAX_MESSAGE_LEN));
|
||||||
|
snprintf(msg, DISCORD_MAX_MESSAGE_LEN, "Error creating list: %s", zblock_feed_info_strerror(error));
|
||||||
|
data->content = msg;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create our components starting with the action row
|
||||||
|
data->components = Arena_alloc(*arena, sizeof(*data->components));
|
||||||
|
data->components->size = 1;
|
||||||
|
data->components->array = Arena_allocz(*arena, data->components->size * sizeof(*data->components->array));
|
||||||
|
struct discord_component *action_row = data->components->array;
|
||||||
|
action_row->type = DISCORD_COMPONENT_ACTION_ROW;
|
||||||
|
// create buttons
|
||||||
|
action_row->components = Arena_alloc(*arena, sizeof(*action_row->components));
|
||||||
|
action_row->components->size = 2;
|
||||||
|
action_row->components->array = Arena_allocz(*arena, action_row->components->size * sizeof(*action_row->components->array));
|
||||||
|
struct discord_component *buttons = action_row->components->array;
|
||||||
|
// create emojis
|
||||||
|
struct discord_emoji *back_arrow = Arena_allocz(*arena, sizeof(*back_arrow));
|
||||||
|
back_arrow->name = "◀️";
|
||||||
|
struct discord_emoji *next_arrow = Arena_allocz(*arena, sizeof(*next_arrow));
|
||||||
|
next_arrow->name = "▶️";
|
||||||
|
// create button ids
|
||||||
|
int back_id_size = snprintf(NULL, 0, "list_page%d", page_number - 1) + 1;
|
||||||
|
char *back_id = Arena_alloc(*arena, back_id_size);
|
||||||
|
snprintf(back_id, back_id_size, "list_page%d", page_number - 1);
|
||||||
|
int next_id_size = snprintf(NULL, 0, "list_page%d", page_number + 1) + 1;
|
||||||
|
char *next_id = Arena_alloc(*arena, next_id_size);
|
||||||
|
snprintf(next_id, next_id_size, "list_page%d", page_number + 1);
|
||||||
|
// populate buttons
|
||||||
|
buttons[0] = (struct discord_component) {
|
||||||
|
.type = DISCORD_COMPONENT_BUTTON,
|
||||||
|
.disabled = page_number == 1,
|
||||||
|
.style = DISCORD_BUTTON_SECONDARY,
|
||||||
|
.custom_id = back_id,
|
||||||
|
.label = "Back",
|
||||||
|
.emoji = back_arrow
|
||||||
|
};
|
||||||
|
buttons[1] = (struct discord_component) {
|
||||||
|
.type = DISCORD_COMPONENT_BUTTON,
|
||||||
|
.disabled = page_number == last_page_number,
|
||||||
|
.style = DISCORD_BUTTON_SECONDARY,
|
||||||
|
.custom_id = next_id,
|
||||||
|
.label = "Next",
|
||||||
|
.emoji = next_arrow
|
||||||
|
};
|
||||||
|
|
||||||
|
// create embed
|
||||||
|
data->embeds = Arena_alloc(*arena, sizeof(*data->embeds));
|
||||||
|
data->embeds->size = 1;
|
||||||
|
data->embeds->array = Arena_allocz(*arena, data->embeds->size * sizeof(*data->embeds->array));
|
||||||
|
struct discord_embed *embed = data->embeds->array;
|
||||||
|
int embed_title_size = snprintf(NULL, 0, "Feed List (Page %d of %d)", page_number, last_page_number) + 1;
|
||||||
|
char *embed_title = Arena_alloc(*arena, embed_title_size);
|
||||||
|
snprintf(embed_title, embed_title_size, "Feed List (Page %d of %d)", page_number, last_page_number);
|
||||||
|
|
||||||
|
// write the description
|
||||||
|
char *embed_description;
|
||||||
|
if (count) {
|
||||||
|
embed_description = Arena_alloc(*arena, 4096); // the current max size of embed descriptions
|
||||||
|
int embed_description_size = 0;
|
||||||
|
for (int i = 0; i < num_retrieved; ++i) {
|
||||||
|
// in case somebody has maliciously long text in their feed
|
||||||
|
if (embed_description_size < 4096) {
|
||||||
|
embed_description_size += snprintf(embed_description + embed_description_size, 4096 - embed_description_size,
|
||||||
|
"### %d. %s\n" // feed title
|
||||||
|
"Link: %s\n" // feed url
|
||||||
|
"Last updated: %s\n", // last_pubDate
|
||||||
|
(page_number - 1) * LIST_PAGE_SIZE + i + 1, feeds[i].title,
|
||||||
|
feeds[i].url,
|
||||||
|
feeds[i].last_pubDate
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
embed_description = "There are no feeds in this channel.";
|
||||||
|
}
|
||||||
|
|
||||||
|
*embed = (struct discord_embed) {
|
||||||
|
.title = embed_title,
|
||||||
|
.type = "rich",
|
||||||
|
.description = embed_description
|
||||||
|
};
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
static void bot_command_list(struct discord *client, const struct discord_interaction *event) {
|
static void bot_command_list(struct discord *client, const struct discord_interaction *event) {
|
||||||
|
Arena *arena;
|
||||||
struct discord_interaction_response res = {
|
struct discord_interaction_response res = {
|
||||||
.type = DISCORD_INTERACTION_CHANNEL_MESSAGE_WITH_SOURCE,
|
.type = DISCORD_INTERACTION_CHANNEL_MESSAGE_WITH_SOURCE,
|
||||||
.data = &(struct discord_interaction_callback_data) {
|
.data = list_data_create(event->channel_id, 1, &arena)
|
||||||
.components = CREATE_COMPONENTS({
|
|
||||||
{
|
|
||||||
.type = DISCORD_COMPONENT_ACTION_ROW,
|
|
||||||
.components = CREATE_COMPONENTS({
|
|
||||||
{
|
|
||||||
.type = DISCORD_COMPONENT_BUTTON,
|
|
||||||
.disabled = false,
|
|
||||||
.style = DISCORD_BUTTON_SECONDARY,
|
|
||||||
.custom_id = "page_back",
|
|
||||||
.label = "Back",
|
|
||||||
.emoji = &(struct discord_emoji) {
|
|
||||||
.name = "◀️"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.type = DISCORD_COMPONENT_BUTTON,
|
|
||||||
.disabled = false,
|
|
||||||
.style = DISCORD_BUTTON_SECONDARY,
|
|
||||||
.custom_id = "page_next",
|
|
||||||
.label = "Next",
|
|
||||||
.emoji = &(struct discord_emoji) {
|
|
||||||
.name = "▶️"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
.embeds = CREATE_EMBEDS({
|
|
||||||
{
|
|
||||||
.title = "Feed List",
|
|
||||||
.type = "rich",
|
|
||||||
.description = "List functionality has not been fully implemented yet."
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
discord_create_interaction_response(client, event->id, event->token, &res, NULL);
|
discord_create_interaction_response(client, event->id, event->token, &res, NULL);
|
||||||
|
Arena_delete(arena);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void list_update(struct discord *client, const struct discord_interaction *event) {
|
||||||
|
int page_number;
|
||||||
|
sscanf(event->data->custom_id, "list_page%d", &page_number);
|
||||||
|
|
||||||
|
Arena *arena;
|
||||||
|
struct discord_interaction_response res = {
|
||||||
|
.type = DISCORD_INTERACTION_UPDATE_MESSAGE,
|
||||||
|
.data = list_data_create(event->channel_id, page_number, &arena)
|
||||||
|
};
|
||||||
|
|
||||||
|
discord_create_interaction_response(client, event->id, event->token, &res, NULL);
|
||||||
|
Arena_delete(arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bot_command_help(struct discord *client, const struct discord_interaction *event) {
|
static void bot_command_help(struct discord *client, const struct discord_interaction *event) {
|
||||||
@ -409,8 +505,8 @@ static void on_interaction(struct discord *client, const struct discord_interact
|
|||||||
};
|
};
|
||||||
discord_create_interaction_response(client, event->id, event->token, &res, NULL);
|
discord_create_interaction_response(client, event->id, event->token, &res, NULL);
|
||||||
} break;
|
} break;
|
||||||
case DISCORD_INTERACTION_MESSAGE_COMPONENT: {
|
case DISCORD_INTERACTION_MESSAGE_COMPONENT: { // only the list command is used here so far
|
||||||
// nothing yet
|
list_update(client, event);
|
||||||
} break;
|
} break;
|
||||||
default: // nothing
|
default: // nothing
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user