use super::{config::Config, Shard};
use std::{
error::Error,
fmt::{Display, Formatter, Result as FmtResult},
sync::Arc,
};
use twilight_gateway_queue::{LocalQueue, Queue};
use twilight_http::Client as HttpClient;
use twilight_model::gateway::{payload::update_status::UpdateStatusInfo, Intents};
#[derive(Debug)]
pub enum LargeThresholdError {
TooFew {
value: u64,
},
TooMany {
value: u64,
},
}
impl Display for LargeThresholdError {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
Self::TooFew { .. } => f.write_str("provided large threshold value is fewer than 50"),
Self::TooMany { .. } => f.write_str("provided large threshold value is more than 250"),
}
}
}
impl Error for LargeThresholdError {}
#[derive(Debug)]
pub enum ShardIdError {
IdTooLarge {
id: u64,
total: u64,
},
}
impl Display for ShardIdError {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match self {
Self::IdTooLarge { id, total } => f.write_fmt(format_args!(
"provided shard ID {} is larger than the total {}",
id, total,
)),
}
}
}
impl Error for ShardIdError {}
#[derive(Clone, Debug)]
pub struct ShardBuilder(pub(crate) Config);
impl ShardBuilder {
pub fn new(token: impl Into<String>, intents: Intents) -> Self {
Self::_new(token.into(), intents)
}
fn _new(mut token: String, intents: Intents) -> Self {
if !token.starts_with("Bot ") {
token.insert_str(0, "Bot ");
}
Self(Config {
gateway_url: None,
http_client: HttpClient::new(token.clone()),
intents,
large_threshold: 250,
presence: None,
queue: Arc::new(Box::new(LocalQueue::new())),
shard: [0, 1],
token,
session_id: None,
sequence: None,
})
}
pub fn build(self) -> Shard {
Shard::new_with_config(self.0)
}
pub fn gateway_url(mut self, gateway_url: Option<String>) -> Self {
self.0.gateway_url = gateway_url;
self
}
pub fn http_client(mut self, http_client: HttpClient) -> Self {
self.0.http_client = http_client;
self
}
pub fn large_threshold(mut self, large_threshold: u64) -> Result<Self, LargeThresholdError> {
match large_threshold {
0..=49 => {
return Err(LargeThresholdError::TooFew {
value: large_threshold,
})
}
50..=250 => {}
251..=u64::MAX => {
return Err(LargeThresholdError::TooMany {
value: large_threshold,
})
}
}
self.0.large_threshold = large_threshold;
Ok(self)
}
pub fn presence(mut self, presence: UpdateStatusInfo) -> Self {
self.0.presence.replace(presence);
self
}
pub fn queue(mut self, queue: Arc<Box<dyn Queue>>) -> Self {
self.0.queue = queue;
self
}
pub fn shard(mut self, shard_id: u64, shard_total: u64) -> Result<Self, ShardIdError> {
if shard_id >= shard_total {
return Err(ShardIdError::IdTooLarge {
id: shard_id,
total: shard_total,
});
}
self.0.shard = [shard_id, shard_total];
Ok(self)
}
}
impl<T: Into<String>> From<(T, Intents)> for ShardBuilder {
fn from((token, intents): (T, Intents)) -> Self {
Self::new(token, intents)
}
}
#[cfg(test)]
mod tests {
use super::{LargeThresholdError, ShardBuilder, ShardIdError};
use crate::Intents;
use static_assertions::{assert_fields, assert_impl_all};
use std::{error::Error, fmt::Debug};
assert_fields!(LargeThresholdError::TooFew: value);
assert_fields!(LargeThresholdError::TooMany: value);
assert_impl_all!(LargeThresholdError: Debug, Error, Send, Sync);
assert_impl_all!(
ShardBuilder: Clone,
Debug,
From<(String, Intents)>,
Send,
Sync
);
assert_fields!(ShardIdError::IdTooLarge: id, total);
assert_impl_all!(ShardIdError: Debug, Error, Send, Sync);
}