diff --git a/Makefile b/Makefile index 88c9e8c..19d6ee9 100644 --- a/Makefile +++ b/Makefile @@ -39,6 +39,7 @@ INCLUDE_PATH += $(SOURCE_PATH)/external SOURCES := \ $(SOURCE_PATH)/bot.c \ + $(SOURCE_PATH)/config.c \ $(SOURCE_PATH)/info.c \ $(SOURCE_PATH)/json.c \ $(SOURCE_PATH)/krdict.c \ diff --git a/include/saerom.h b/include/saerom.h index 49edff7..3bdc110 100644 --- a/include/saerom.h +++ b/include/saerom.h @@ -27,7 +27,7 @@ /* | 매크로 정의... | */ #define APPLICATION_NAME "jdeokkim/saerom" -#define APPLICATION_VERSION "v0.2.0" +#define APPLICATION_VERSION "v0.2.1-dev" #define APPLICATION_DESCRIPTION "A C99 Discord bot for Korean learning servers." #define APPLICATION_PROJECT_URL "https://github.com/jdeokkim/saerom" @@ -39,18 +39,6 @@ /* | 자료형 정의... | */ -/* Discord 봇의 환경 설정을 나타내는 구조체. */ -struct sr_config { - unsigned char flags; - struct { - char api_key[MAX_STRING_SIZE]; - } krdict; - struct { - char client_id[MAX_STRING_SIZE]; - char client_secret[MAX_STRING_SIZE]; - } papago; -}; - /* Discord 봇의 명령어를 나타내는 구조체. */ struct sr_command { const char *name; @@ -62,35 +50,34 @@ struct sr_command { ); }; -/* Discord 봇의 환경 설정 플래그를 나타내는 열거형. */ -enum sr_flag { - SR_FLAG_KRDICT = (1 << 0), - SR_FLAG_PAPAGO = (1 << 1) +/* Discord 봇의 모듈 플래그를 나타내는 열거형. */ +enum sr_module_flag { + SR_MODULE_KRDICT = (1 << 0), + SR_MODULE_PAPAGO = (1 << 1) +}; + +/* Discord 봇의 상태 플래그를 나타내는 열거형. */ +enum sr_status_flag { + SR_STATUS_RUNNING = (1 << 0) }; /* | `bot` 모듈 함수... | */ /* Discord 봇을 초기화한다. */ -void init_bot(int argc, char *argv[]); +void sr_bot_init(int argc, char *argv[]); + +/* Discord 봇에 할당된 메모리를 해제한다. */ +void sr_bot_cleanup(void); /* Discord 봇을 실행한다. */ -void run_bot(void); +void sr_bot_run(void); -/* Discord 봇에 할당된 메모리를 해제한다. */ -void deinit_bot(void); +/* Discord 봇의 클라이언트 객체를 반환한다. */ +struct discord *get_client(void); /* `CURLV` 인터페이스를 반환한다. */ void *get_curlv(void); -/* Discord 봇의 애플리케이션 고유 번호를 반환한다. */ -u64snowflake get_application_id(void); - -/* Discord 봇 관리자의 고유 번호를 반환한다. */ -u64snowflake get_owner_id(void); - -/* Discord 봇의 환경 설정 정보를 반환한다. */ -struct sr_config *get_sr_config(void); - /* Discord 봇의 명령어 목록을 반환한다. */ const struct sr_command *get_commands(int *len); @@ -103,6 +90,41 @@ double get_ram_usage(void); /* Discord 봇의 작동 시간 (단위: 밀리초)을 반환한다. */ uint64_t get_uptime(void); +/* | `config` 모듈 함수... | */ + +/* Discord 봇의 환경 설정을 초기화한다. */ +void sr_config_init(void); + +/* Discord 봇의 환경 설정에 할당된 메모리를 해제한다. */ +void sr_config_cleanup(void); + +/* Discord 봇의 애플리케이션 ID를 반환한다. */ +u64snowflake sr_config_get_application_id(void); + +/* Discord 봇의 애플리케이션 소유자 ID를 반환한다. */ +u64snowflake sr_config_get_application_owner_id(void); + +/* Discord 봇의 모듈 플래그 데이터를 반환한다. */ +u64bitmask sr_config_get_module_flags(void); + +/* Discord 봇의 상태 플래그 데이터를 반환한다. */ +u64bitmask sr_config_get_status_flags(void); + +/* Discord 봇의 국립국어원 한국어기초사전 API 키를 반환한다. */ +const char *sr_config_get_krdict_api_key(void); + +/* Discord 봇의 NAVER™ 파파고 NMT API 클라이언트 ID를 반환한다. */ +const char *sr_config_get_papago_client_id(void); + +/* Discord 봇의 NAVER™ 파파고 NMT API 클라이언트 시크릿을 반환한다. */ +const char *sr_config_get_papago_client_secret(void); + +/* Discord 봇의 모듈 플래그 데이터를 `flags`로 설정한다. */ +void sr_config_set_module_flags(u64bitmask flags); + +/* Discord 봇의 상태 플래그 데이터를 `flags`로 설정한다. */ +void sr_config_set_status_flags(u64bitmask flags); + /* | `info` 모듈 함수... | */ /* `/info` 명령어를 생성한다. */ diff --git a/src/bot.c b/src/bot.c index be5137d..591e60f 100644 --- a/src/bot.c +++ b/src/bot.c @@ -15,7 +15,6 @@ along with this program. If not, see . */ -#include #include #include @@ -73,21 +72,12 @@ static sigar_t *sigar; /* Discord 봇의 클라이언트 객체. */ static struct discord *client; -/* Discord 봇의 환경 설정. */ -static struct sr_config config; - -/* Discord 봇의 애플리케이션 고유 번호. */ -static u64snowflake application_id; - -/* Discord 봇 관리자의 고유 번호. */ -static u64snowflake owner_id; - /* Discord 봇의 시작 시간. */ static uint64_t timestamp; /* | `bot` 모듈 함수... | */ -/* Discord 봇이 실행 중일 때 주기적으로 호출된다. */ +/* Discord 봇이 대기 중일 때 주기적으로 호출된다. */ static void on_idle(struct discord *client); /* Discord 봇의 클라이언트가 준비되었을 때 호출된다. */ @@ -103,10 +93,10 @@ static void on_interaction_create( ); /* Discord 봇의 추가 정보를 초기화한다. */ -static void sr_config_init(void); +static void sr_core_init(void); /* Discord 봇의 추가 정보에 할당된 메모리를 해제한다. */ -static void sr_config_cleanup(void); +static void sr_core_cleanup(void); /* 표준 입력 스트림에서 명령어를 입력받는 스레드를 생성한다. */ static void sr_input_reader_init(void); @@ -118,13 +108,12 @@ static void create_commands(struct discord *client); static void release_commands(struct discord *client); /* Discord 봇을 초기화한다. */ -void init_bot(int argc, char *argv[]) { +void sr_bot_init(int argc, char *argv[]) { ccord_global_init(); client = discord_config_init((argc > 1) ? argv[1] : CONFIG_PATH); - sr_config_init(); - sr_input_reader_init(); + sr_core_init(); discord_set_on_idle(client, on_idle); discord_set_on_ready(client, on_ready); @@ -133,16 +122,11 @@ void init_bot(int argc, char *argv[]) { create_commands(client); } -/* Discord 봇을 실행한다. */ -void run_bot(void) { - discord_run(client); -} - /* Discord 봇에 할당된 메모리를 해제한다. */ -void deinit_bot(void) { +void sr_bot_cleanup(void) { release_commands(client); - sr_config_cleanup(); + sr_core_cleanup(); log_info("[SAEROM] Cleaning up global resources"); @@ -151,24 +135,19 @@ void deinit_bot(void) { ccord_global_cleanup(); } -/* `CURLV` 인터페이스를 반환한다. */ -void *get_curlv(void) { - return (void *) curlv; -} - -/* Discord 봇의 애플리케이션 고유 번호를 반환한다. */ -u64snowflake get_application_id(void) { - return application_id; +/* Discord 봇을 실행한다. */ +void sr_bot_run(void) { + discord_run(client); } -/* Discord 봇 관리자의 고유 번호를 반환한다. */ -u64snowflake get_owner_id(void) { - return owner_id; +/* Discord 봇의 클라이언트 객체를 반환한다. */ +struct discord *get_client(void) { + return client; } -/* Discord 봇의 환경 설정 정보를 반환한다. */ -struct sr_config *get_sr_config(void) { - return &config; +/* `CURLV` 인터페이스를 반환한다. */ +void *get_curlv(void) { + return (void *) curlv; } /* Discord 봇의 명령어 목록을 반환한다. */ @@ -211,8 +190,18 @@ uint64_t get_uptime(void) { return discord_timestamp(client) - timestamp; } -/* Discord 봇이 실행 중일 때 주기적으로 호출된다. */ +/* Discord 봇이 대기 중일 때 주기적으로 호출된다. */ static void on_idle(struct discord *client) { + if (!(sr_config_get_status_flags() & SR_STATUS_RUNNING)) { + sr_config_set_status_flags(0); + + log_info("[SAEROM] Shutting down the bot"); + + sr_bot_cleanup(); + + exit(EXIT_SUCCESS); + } + curlv_read_requests(curlv); // CPU 사용량 최적화 @@ -318,77 +307,24 @@ static void on_interaction_create( } } -/* (Discord 봇의 추가 정보를 초기화한다.) */ -static void _sr_config_init( - struct discord *client, - struct discord_response *resp, - const struct discord_application *ret -) { - owner_id = ret->owner->id; -} - /* Discord 봇의 추가 정보를 초기화한다. */ -static void sr_config_init(void) { +static void sr_core_init(void) { if (client == NULL) return; curlv = curlv_init(); sigar_open(&sigar); - struct ccord_szbuf_readonly field = discord_config_get_field( - client, (char *[2]) { "discord", "application_id" }, 2 - ); - - char buffer[MAX_STRING_SIZE]; - - strncpy(buffer, field.start, field.size); - - application_id = strtoull(buffer, NULL, 10); - - field = discord_config_get_field( - client, (char *[3]) { "saerom", "krdict", "enable" }, 3 - ); - - if (strncmp("true", field.start, field.size) == 0) { - config.flags |= SR_FLAG_KRDICT; - - field = discord_config_get_field( - client, (char *[3]) { "saerom", "krdict", "api_key" }, 3 - ); - - strncpy(config.krdict.api_key, field.start, field.size); - } - - field = discord_config_get_field( - client, (char *[3]) { "saerom", "papago", "enable" }, 3 - ); - - if (strncmp("true", field.start, field.size) == 0) { - config.flags |= SR_FLAG_PAPAGO; - - field = discord_config_get_field( - client, (char *[3]) { "saerom", "papago", "client_id" }, 3 - ); - - strncpy(config.papago.client_id, field.start, field.size); - - field = discord_config_get_field( - client, (char *[3]) { "saerom", "papago", "client_secret" }, 3 - ); - - strncpy(config.papago.client_secret, field.start, field.size); - } - - discord_get_current_bot_application_information( - client, - &(struct discord_ret_application) { - .done = _sr_config_init - } - ); + sr_config_init(); + sr_input_reader_init(); } /* Discord 봇의 추가 정보에 할당된 메모리를 해제한다. */ -static void sr_config_cleanup(void) { +static void sr_core_cleanup(void) { + if (client == NULL) return; + + sr_config_cleanup(); + curlv_cleanup(curlv); sigar_close(sigar); @@ -412,14 +348,16 @@ static void sr_input_reader_init(void) { static void create_commands(struct discord *client) { const int commands_len = sizeof(commands) / sizeof(*commands); + const u64bitmask module_flags = sr_config_get_module_flags(); + log_info("[SAEROM] Creating %d global application command(s)", commands_len); for (int i = 0; i < commands_len; i++) { if (streq(commands[i].name, "krd") - && !(config.flags & SR_FLAG_KRDICT)) continue; + && !(module_flags & SR_MODULE_KRDICT)) continue; if (streq(commands[i].name, "ppg") - && !(config.flags & SR_FLAG_PAPAGO)) continue; + && !(module_flags & SR_MODULE_PAPAGO)) continue; if (commands[i].on_create != NULL) commands[i].on_create(client); @@ -430,14 +368,16 @@ static void create_commands(struct discord *client) { static void release_commands(struct discord *client) { const int commands_len = sizeof(commands) / sizeof(*commands); + const u64bitmask module_flags = sr_config_get_module_flags(); + log_info("[SAEROM] Releasing %d global application command(s)", commands_len); for (int i = 0; i < commands_len; i++) { if (streq(commands[i].name, "krd") - && !(config.flags & SR_FLAG_KRDICT)) continue; + && !(module_flags & SR_MODULE_KRDICT)) continue; if (streq(commands[i].name, "ppg") - && !(config.flags & SR_FLAG_PAPAGO)) continue; + && !(module_flags & SR_MODULE_PAPAGO)) continue; if (commands[i].on_release != NULL) commands[i].on_release(client); diff --git a/src/config.c b/src/config.c new file mode 100644 index 0000000..998244d --- /dev/null +++ b/src/config.c @@ -0,0 +1,203 @@ +/* + Copyright (c) 2022 jdeokkim + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include + +#include + +#include "saerom.h" + +/* | `config` 모듈 자료형 정의... | */ + +/* Discord 봇의 환경 설정을 나타내는 구조체. */ +struct sr_config { + u64snowflake application_id; + u64snowflake application_owner_id; + struct { + u64bitmask module; + u64bitmask status; + } flags; + struct { + char api_key[MAX_STRING_SIZE]; + } krdict; + struct { + char client_id[MAX_STRING_SIZE]; + char client_secret[MAX_STRING_SIZE]; + } papago; + pthread_mutex_t lock; +}; + +/* | `config` 모듈 상수 및 변수... | */ + +/* Discord 봇의 환경 설정. */ +static struct sr_config config; + +/* | `config` 모듈 함수... | */ + +/* (Discord 봇의 환경 설정을 초기화한다.) */ +static void _sr_config_init( + struct discord *client, + struct discord_response *resp, + const struct discord_application *ret +) { + pthread_mutex_lock(&config.lock); + + config.application_owner_id = ret->owner->id; + + pthread_mutex_unlock(&config.lock); +} + +/* Discord 봇의 환경 설정을 초기화한다. */ +void sr_config_init(void) { + if (get_client() == NULL) return; + + struct discord *client = get_client(); + + pthread_mutex_init(&config.lock, NULL); + + struct ccord_szbuf_readonly field = discord_config_get_field( + client, (char *[2]) { "discord", "application_id" }, 2 + ); + + char buffer[MAX_STRING_SIZE]; + + strncpy(buffer, field.start, field.size); + + { + pthread_mutex_lock(&config.lock); + + config.application_id = strtoull(buffer, NULL, 10); + + pthread_mutex_unlock(&config.lock); + } + + field = discord_config_get_field( + client, (char *[3]) { "saerom", "krdict", "enable" }, 3 + ); + + if (strncmp("true", field.start, field.size) == 0) { + pthread_mutex_lock(&config.lock); + + config.flags.module |= SR_MODULE_KRDICT; + + field = discord_config_get_field( + client, (char *[3]) { "saerom", "krdict", "api_key" }, 3 + ); + + strncpy(config.krdict.api_key, field.start, field.size); + + pthread_mutex_unlock(&config.lock); + } + + field = discord_config_get_field( + client, (char *[3]) { "saerom", "papago", "enable" }, 3 + ); + + if (strncmp("true", field.start, field.size) == 0) { + pthread_mutex_lock(&config.lock); + + config.flags.module |= SR_MODULE_PAPAGO; + + field = discord_config_get_field( + client, (char *[3]) { "saerom", "papago", "client_id" }, 3 + ); + + strncpy(config.papago.client_id, field.start, field.size); + + field = discord_config_get_field( + client, (char *[3]) { "saerom", "papago", "client_secret" }, 3 + ); + + strncpy(config.papago.client_secret, field.start, field.size); + + pthread_mutex_unlock(&config.lock); + } + + { + pthread_mutex_lock(&config.lock); + + config.flags.status = SR_STATUS_RUNNING; + + pthread_mutex_unlock(&config.lock); + } + + discord_get_current_bot_application_information( + client, + &(struct discord_ret_application) { + .done = _sr_config_init + } + ); +} + +/* Discord 봇의 환경 설정에 할당된 메모리를 해제한다. */ +void sr_config_cleanup(void) { + pthread_mutex_destroy(&config.lock); +} + +/* Discord 봇의 애플리케이션 ID를 반환한다. */ +u64snowflake sr_config_get_application_id(void) { + return config.application_id; +} + +/* Discord 봇의 애플리케이션 소유자 ID를 반환한다. */ +u64snowflake sr_config_get_application_owner_id(void) { + return config.application_owner_id; +} + +/* Discord 봇의 모듈 플래그 데이터를 반환한다. */ +u64bitmask sr_config_get_module_flags(void) { + return config.flags.module; +} + +/* Discord 봇의 상태 플래그 데이터를 반환한다. */ +u64bitmask sr_config_get_status_flags(void) { + return config.flags.status; +} + +/* Discord 봇의 국립국어원 한국어기초사전 API 키를 반환한다. */ +const char *sr_config_get_krdict_api_key(void) { + return config.krdict.api_key; +} + +/* Discord 봇의 NAVER™ 파파고 NMT API 클라이언트 ID를 반환한다. */ +const char *sr_config_get_papago_client_id(void) { + return config.papago.client_id; +} + +/* Discord 봇의 NAVER™ 파파고 NMT API 클라이언트 시크릿을 반환한다. */ +const char *sr_config_get_papago_client_secret(void) { + return config.papago.client_secret; +} + +/* Discord 봇의 모듈 플래그 데이터를 `flags`로 설정한다. */ +void sr_config_set_module_flags(u64bitmask flags) { + pthread_mutex_lock(&config.lock); + + config.flags.module = flags; + + pthread_mutex_unlock(&config.lock); +} + +/* Discord 봇의 상태 플래그 데이터를 `flags`로 설정한다. */ +void sr_config_set_status_flags(u64bitmask flags) { + pthread_mutex_lock(&config.lock); + + config.flags.status = flags; + + pthread_mutex_unlock(&config.lock); +} \ No newline at end of file diff --git a/src/info.c b/src/info.c index 52be4db..edb9473 100644 --- a/src/info.c +++ b/src/info.c @@ -34,7 +34,7 @@ static struct discord_create_global_application_command params = { void create_info_command(struct discord *client) { discord_create_global_application_command( client, - get_application_id(), + sr_config_get_application_id(), ¶ms, NULL ); @@ -56,8 +56,6 @@ void run_info_command( char uptime_str[MAX_STRING_SIZE]; char ping_str[MAX_STRING_SIZE]; char flags_str[MAX_STRING_SIZE]; - - struct sr_config *config = get_sr_config(); time_t uptime_in_seconds = get_uptime() * 0.001f; @@ -66,7 +64,7 @@ void run_info_command( strftime(uptime_str, sizeof(uptime_str), "%T", gmtime(&uptime_in_seconds)); snprintf(ping_str, sizeof(ping_str), "%dms", discord_get_ping(client)); - snprintf(flags_str, sizeof(flags_str), "0x%02hhX", config->flags); + snprintf(flags_str, sizeof(flags_str), "0x%02" PRIu64 "X", sr_config_get_module_flags()); if (event == NULL) { log_info("[SAEROM] %s: %s", APPLICATION_NAME, APPLICATION_DESCRIPTION); diff --git a/src/krdict.c b/src/krdict.c index 3498e44..3f4122d 100644 --- a/src/krdict.c +++ b/src/krdict.c @@ -110,7 +110,7 @@ static void handle_error(struct krdict_context *context, const char *code); void create_krdict_command(struct discord *client) { discord_create_global_application_command( client, - get_application_id(), + sr_config_get_application_id(), ¶ms, NULL ); @@ -152,15 +152,13 @@ void run_krdict_command( char buffer[DISCORD_MAX_MESSAGE_LEN] = ""; - struct sr_config *config = get_sr_config(); - snprintf( buffer, DISCORD_MAX_MESSAGE_LEN, streq(translated, "true") ? "key=%s&q=%s&advanced=y&translated=y&trans_lang=1" : "key=%s&q=%s&advanced=y", - config->krdict.api_key, + sr_config_get_krdict_api_key(), query ); @@ -532,7 +530,7 @@ static void on_response(CURLV_STR res, void *user_data) { discord_edit_original_interaction_response( context->client, - get_application_id(), + sr_config_get_application_id(), context->event.token, &(struct discord_edit_original_interaction_response) { .components = &(struct discord_components){ @@ -578,7 +576,7 @@ static void handle_error(struct krdict_context *context, const char *code) { discord_edit_original_interaction_response( context->client, - get_application_id(), + sr_config_get_application_id(), context->event.token, &(struct discord_edit_original_interaction_response) { .embeds = &(struct discord_embeds) { diff --git a/src/main.c b/src/main.c index 6652537..3820e98 100644 --- a/src/main.c +++ b/src/main.c @@ -18,11 +18,11 @@ #include "saerom.h" int main(int argc, char *argv[]) { - init_bot(argc, argv); + sr_bot_init(argc, argv); - run_bot(); + sr_bot_run(); - deinit_bot(); + sr_bot_cleanup(); return 0; } \ No newline at end of file diff --git a/src/owner.c b/src/owner.c index c565f71..08db4d9 100644 --- a/src/owner.c +++ b/src/owner.c @@ -85,7 +85,7 @@ void create_msg_command(struct discord *client) { discord_create_global_application_command( client, - get_application_id(), + sr_config_get_application_id(), ¶ms, NULL ); @@ -111,7 +111,7 @@ void run_msg_command( ? event->member->user : event->user; - if (user->id != get_owner_id()) { + if (user->id != sr_config_get_application_owner_id()) { const struct discord_user *self = discord_get_self(client); struct discord_embed embeds[] = { @@ -218,7 +218,7 @@ void create_stop_command(struct discord *client) { discord_create_global_application_command( client, - get_application_id(), + sr_config_get_application_id(), ¶ms, NULL ); @@ -229,6 +229,15 @@ void release_stop_command(struct discord *client) { /* no-op */ } +/* (`/stop` 명령어를 실행한다.) */ +static void _run_stop_command( + struct discord *client, + struct discord_response *resp, + const struct discord_interaction_response *ret +) { + sr_config_set_status_flags(0); +} + /* `/stop` 명령어를 실행한다. */ void run_stop_command( struct discord *client, @@ -239,9 +248,9 @@ void run_stop_command( ? event->member->user : event->user; - if (user->id != get_owner_id()) { - const struct discord_user *self = discord_get_self(client); + const struct discord_user *self = discord_get_self(client); + if (user->id != sr_config_get_application_owner_id()) { struct discord_embed embeds[] = { { .description = "This command can only be invoked by the bot owner.", @@ -280,11 +289,14 @@ void run_stop_command( struct discord_embed embeds[] = { { - .title = APPLICATION_NAME, .description = "Shutting down the bot...", .timestamp = discord_timestamp(client), .footer = &(struct discord_embed_footer) { .text = "⚡" + }, + .author = &(struct discord_embed_author) { + .name = self->username, + .icon_url = (char *) get_avatar_url(self) } } }; @@ -305,14 +317,14 @@ void run_stop_command( event->token, ¶ms, &(struct discord_ret_interaction_response) { - .done = sr_shutdown + .done = _run_stop_command } ); return; } - sr_shutdown(NULL, NULL, NULL); + sr_config_set_status_flags(0); } /* 채널 메시지 전송에 성공했을 때 호출되는 함수. */ @@ -402,17 +414,4 @@ static void on_message_complete(struct discord *client, void *data) { free(event->token); free(event); -} - -/* Discord 봇을 종료한다. */ -static void sr_shutdown( - struct discord *client, - struct discord_response *resp, - const struct discord_interaction_response *ret -) { - log_info("[SAEROM] Shutting down the bot"); - - deinit_bot(); - - exit(EXIT_SUCCESS); } \ No newline at end of file diff --git a/src/papago.c b/src/papago.c index 1518a2c..3c14be2 100644 --- a/src/papago.c +++ b/src/papago.c @@ -107,7 +107,7 @@ static void handle_error(struct papago_context *context, const char *code); void create_papago_command(struct discord *client) { discord_create_global_application_command( client, - get_application_id(), + sr_config_get_application_id(), ¶ms, NULL ); @@ -160,8 +160,6 @@ void run_papago_command( curl_easy_setopt(request.easy, CURLOPT_COPYPOSTFIELDS, buffer); curl_easy_setopt(request.easy, CURLOPT_POST, 1); - struct sr_config *config = get_sr_config(); - request.header = curl_slist_append( request.header, "Content-Type: application/x-www-form-urlencoded; charset=UTF-8" @@ -171,7 +169,7 @@ void run_papago_command( buffer, sizeof(buffer), "X-Naver-Client-Id: %s", - config->papago.client_id + sr_config_get_papago_client_id() ); request.header = curl_slist_append(request.header, buffer); @@ -180,7 +178,7 @@ void run_papago_command( buffer, sizeof(buffer), "X-Naver-Client-Secret: %s", - config->papago.client_secret + sr_config_get_papago_client_secret() ); request.header = curl_slist_append(request.header, buffer); @@ -272,7 +270,7 @@ static void on_response(CURLV_STR res, void *user_data) { discord_edit_original_interaction_response( context->client, - get_application_id(), + sr_config_get_application_id(), context->event.token, &(struct discord_edit_original_interaction_response) { .embeds = &(struct discord_embeds) { @@ -323,7 +321,7 @@ static void handle_error(struct papago_context *context, const char *code) { discord_edit_original_interaction_response( context->client, - get_application_id(), + sr_config_get_application_id(), context->event.token, &(struct discord_edit_original_interaction_response) { .embeds = &(struct discord_embeds) {