use crate::http::HttpClient;
use crate::token::Token;
pub type APIVersion = u32;
#[allow(non_upper_case_globals)]
pub const APIv1: APIVersion = 1;
#[allow(non_upper_case_globals)]
pub const MaxIdleConns: usize = 3000;
#[allow(non_upper_case_globals)]
pub const HeaderCallbackAppID: &str = "X-Callback-AppID";
#[allow(non_snake_case)]
pub fn APIVersionString(version: APIVersion) -> String {
format!("v{version}")
}
#[derive(Clone)]
pub struct BotApi {
http: HttpClient,
app_id: String,
token: Option<Token>,
}
mod announces;
mod api_permissions;
mod audio;
mod base;
mod channel;
mod channel_permissions;
mod compat;
mod direct_message;
mod gateway;
mod guild;
mod interaction;
mod me;
mod member;
mod message;
mod message_reaction;
mod message_setting;
mod pins;
mod resource;
mod role;
mod schedule;
mod webhook;
impl std::fmt::Debug for BotApi {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("BotApi").field("http", &self.http).finish()
}
}
#[cfg(test)]
mod tests {
use crate::http::HttpClient;
use crate::options::Options;
use std::time::Duration;
use super::{APIVersionString, APIv1, BotApi};
#[test]
fn test_api_creation() {
let http = HttpClient::new(30, false).unwrap();
let api = BotApi::new(http);
assert!(!api.http().is_sandbox());
}
#[test]
fn test_base_helpers() {
let (api, token) = BotApi::Setup("app-id", "secret", true).unwrap();
assert_eq!(api.Version(), APIv1);
assert_eq!(APIVersionString(api.version()), "v1");
assert_eq!(token.app_id(), "app-id");
assert_eq!(api.GetAppID(), "app-id");
assert_eq!(api.http().union_app_id(), Some("app-id"));
assert!(api.http().is_sandbox());
let api = api.WithTimeout(Duration::from_secs(7)).unwrap();
assert_eq!(api.http().timeout(), Duration::from_secs(7));
assert_eq!(api.GetAppID(), "app-id");
let api = api.SetDebug(true);
assert!(api.http().debug_enabled());
assert_eq!(api.GetAppID(), "app-id");
assert_eq!(api.TraceID(), "");
}
#[test]
fn options_build_custom_urls() {
let api = BotApi::new(HttpClient::new(30, false).unwrap());
let options = Options::from_options([crate::WithURL("https://example.com/custom")]);
assert_eq!(
api.url_with_options("/channels/1/messages", &options),
"https://example.com/custom"
);
let options = Options::default();
assert_eq!(
api.url_with_options("/channels/1/messages", &options),
format!("{}{}", crate::DEFAULT_API_URL, "/channels/1/messages")
);
}
#[test]
fn hide_tip_option_sets_flag() {
let options = Options::from_options([crate::WithHideTip()]);
assert!(options.hide_tip);
assert!(options.url.is_none());
}
#[test]
fn message_response_accepts_legacy_wrapper() {
let message = BotApi::parse_message_response(serde_json::json!({
"message": {
"id": "msg-1",
"content": "wrapped",
"channel_id": "channel-1"
}
}))
.unwrap();
assert_eq!(message.id.as_deref(), Some("msg-1"));
assert_eq!(message.content.as_deref(), Some("wrapped"));
assert_eq!(message.channel_id.as_deref(), Some("channel-1"));
}
#[test]
fn message_response_keeps_direct_shape() {
let message = BotApi::parse_message_response(serde_json::json!({
"id": "msg-2",
"content": "direct"
}))
.unwrap();
assert_eq!(message.id.as_deref(), Some("msg-2"));
assert_eq!(message.content.as_deref(), Some("direct"));
}
}