@@ -29,20 +28,23 @@
-Chorus is a Rust library that allows developers to interact with multiple Spacebar-compatible APIs and Gateways (Including
-Discord.com) simultaneously. The library provides a simple and efficient way to communicate with these services, making it easier for developers to build applications that rely on them. Chorus is open-source and welcomes contributions from the community.
+Chorus is a Rust library which poses as an API wrapper for [Spacebar Chat](https://github.com/spacebarchat/)
+and Discord. It is designed to be easy to use, and to be compatible with both Discord and Spacebar Chat.
+
+You can establish as many connections to as many servers as you want, and you can use them all at the same time.
## A Tour of Chorus
-Chorus combines all the required functionalities of a user-centric Spacebar library into one package. The library
-handles a lot of things for you, such as rate limiting, authentication, and more. This means that you can focus on
-building your application, instead of worrying about the underlying implementation details.
+Chorus combines all the required functionalities of a user-centric Spacebar library into one package.
+The library handles various aspects on your behalf, such as rate limiting, authentication and maintaining
+a WebSocket connection to the Gateway. This means that you can focus on building your application,
+instead of worrying about the underlying implementation details.
To get started with Chorus, import it into your project by adding the following to your `Cargo.toml` file:
```toml
[dependencies]
-chorus = "0"
+chorus = "0.12.0"
```
### Establishing a Connection
diff --git a/examples/instance.rs b/examples/instance.rs
index d2a042f..b8f8518 100644
--- a/examples/instance.rs
+++ b/examples/instance.rs
@@ -8,7 +8,7 @@ async fn main() {
"wss://example.com/".to_string(),
"https://example.com/cdn".to_string(),
);
- let instance = Instance::new(bundle, true)
+ let instance = Instance::new(bundle)
.await
.expect("Failed to connect to the Spacebar server");
dbg!(instance.instance_info);
diff --git a/examples/login.rs b/examples/login.rs
index b06eade..18b5db4 100644
--- a/examples/login.rs
+++ b/examples/login.rs
@@ -9,7 +9,7 @@ async fn main() {
"wss://example.com/".to_string(),
"https://example.com/cdn".to_string(),
);
- let instance = Instance::new(bundle, true)
+ let mut instance = Instance::new(bundle)
.await
.expect("Failed to connect to the Spacebar server");
// Assume, you already have an account created on this instance. Registering an account works
diff --git a/src/api/auth/login.rs b/src/api/auth/login.rs
index 1d9fc8a..ff99be8 100644
--- a/src/api/auth/login.rs
+++ b/src/api/auth/login.rs
@@ -14,7 +14,7 @@ impl Instance {
///
/// # Reference
/// See
- pub async fn login_account(mut self, login_schema: LoginSchema) -> ChorusResult {
+ pub async fn login_account(&mut self, login_schema: LoginSchema) -> ChorusResult {
let endpoint_url = self.urls.api.clone() + "/auth/login";
let chorus_request = ChorusRequest {
request: Client::new()
diff --git a/src/api/auth/register.rs b/src/api/auth/register.rs
index 2ea7d57..aa0b483 100644
--- a/src/api/auth/register.rs
+++ b/src/api/auth/register.rs
@@ -19,7 +19,7 @@ impl Instance {
/// # Reference
/// See
pub async fn register_account(
- mut self,
+ &mut self,
register_schema: RegisterSchema,
) -> ChorusResult {
let endpoint_url = self.urls.api.clone() + "/auth/register";
@@ -43,7 +43,7 @@ impl Instance {
self.limits_information.as_mut().unwrap().ratelimits = shell.limits.unwrap();
}
let user_object = self.get_user(token.clone(), None).await.unwrap();
- let settings = ChorusUser::get_settings(&token, &self.urls.api.clone(), &mut self).await?;
+ let settings = ChorusUser::get_settings(&token, &self.urls.api.clone(), self).await?;
let mut identify = GatewayIdentifyPayload::common();
let gateway: GatewayHandle = Gateway::spawn(self.urls.wss.clone()).await.unwrap();
identify.token = token.clone();
diff --git a/src/errors.rs b/src/errors.rs
index 4099a6b..c20ac64 100644
--- a/src/errors.rs
+++ b/src/errors.rs
@@ -44,6 +44,18 @@ custom_error! {
InvalidArguments{error: String} = "Invalid arguments were provided. Error: {error}"
}
+impl From for ChorusError {
+ fn from(value: reqwest::Error) -> Self {
+ ChorusError::RequestFailed {
+ url: match value.url() {
+ Some(url) => url.to_string(),
+ None => "None".to_string(),
+ },
+ error: value.to_string(),
+ }
+ }
+}
+
custom_error! {
#[derive(PartialEq, Eq)]
pub ObserverError
diff --git a/src/instance.rs b/src/instance.rs
index 4ce4338..cd9eb76 100644
--- a/src/instance.rs
+++ b/src/instance.rs
@@ -12,44 +12,85 @@ use crate::errors::ChorusResult;
use crate::gateway::{Gateway, GatewayHandle};
use crate::ratelimiter::ChorusRequest;
use crate::types::types::subconfigs::limits::rates::RateLimits;
-use crate::types::{GeneralConfiguration, Limit, LimitType, User, UserSettings};
+use crate::types::{
+ GeneralConfiguration, Limit, LimitType, LimitsConfiguration, User, UserSettings,
+};
use crate::UrlBundle;
-#[derive(Debug, Clone, Default)]
+#[derive(Debug, Clone, Default, Serialize, Deserialize)]
/// The [`Instance`]; what you will be using to perform all sorts of actions on the Spacebar server.
/// If `limits_information` is `None`, then the instance will not be rate limited.
pub struct Instance {
pub urls: UrlBundle,
pub instance_info: GeneralConfiguration,
pub limits_information: Option,
+ #[serde(skip)]
pub client: Client,
}
-#[derive(Debug, Clone, Serialize, Deserialize, Default)]
+impl PartialEq for Instance {
+ fn eq(&self, other: &Self) -> bool {
+ self.urls == other.urls
+ && self.instance_info == other.instance_info
+ && self.limits_information == other.limits_information
+ }
+}
+
+impl Eq for Instance {}
+
+impl std::hash::Hash for Instance {
+ fn hash(&self, state: &mut H) {
+ self.urls.hash(state);
+ self.instance_info.hash(state);
+ if let Some(inf) = &self.limits_information {
+ inf.hash(state);
+ }
+ }
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize, Default, Eq)]
pub struct LimitsInformation {
pub ratelimits: HashMap,
pub configuration: RateLimits,
}
+impl std::hash::Hash for LimitsInformation {
+ fn hash(&self, state: &mut H) {
+ for (k, v) in self.ratelimits.iter() {
+ k.hash(state);
+ v.hash(state);
+ }
+ self.configuration.hash(state);
+ }
+}
+
+impl PartialEq for LimitsInformation {
+ fn eq(&self, other: &Self) -> bool {
+ self.ratelimits.iter().eq(other.ratelimits.iter())
+ && self.configuration == other.configuration
+ }
+}
+
impl Instance {
- /// Creates a new [`Instance`] from the [relevant instance urls](UrlBundle), where `limited` is whether or not to automatically use rate limits.
- pub async fn new(urls: UrlBundle, limited: bool) -> ChorusResult {
- let limits_information;
- if limited {
- let limits_configuration = ChorusRequest::get_limits_config(&urls.api).await?.rate;
- let limits = ChorusRequest::limits_config_to_hashmap(&limits_configuration);
- limits_information = Some(LimitsInformation {
+ /// Creates a new [`Instance`] from the [relevant instance urls](UrlBundle), where `limited` is whether Chorus will track and enforce rate limits for this instance.
+ pub async fn new(urls: UrlBundle) -> ChorusResult {
+ let is_limited: Option = Instance::is_limited(&urls.api).await?;
+ let limit_information;
+
+ if let Some(limits_configuration) = is_limited {
+ let limits = ChorusRequest::limits_config_to_hashmap(&limits_configuration.rate);
+ limit_information = Some(LimitsInformation {
ratelimits: limits,
- configuration: limits_configuration,
+ configuration: limits_configuration.rate,
});
} else {
- limits_information = None;
+ limit_information = None
}
let mut instance = Instance {
urls: urls.clone(),
// Will be overwritten in the next step
instance_info: GeneralConfiguration::default(),
- limits_information,
+ limits_information: limit_information,
client: Client::new(),
};
instance.instance_info = match instance.general_configuration_schema().await {
@@ -61,12 +102,39 @@ impl Instance {
};
Ok(instance)
}
+
pub(crate) fn clone_limits_if_some(&self) -> Option> {
if self.limits_information.is_some() {
return Some(self.limits_information.as_ref().unwrap().ratelimits.clone());
}
None
}
+
+ /// Creates a new [`Instance`] by trying to get the [relevant instance urls](UrlBundle) from a root url.
+ /// Shorthand for `Instance::new(UrlBundle::from_root_domain(root_domain).await?)`.
+ ///
+ /// If `limited` is `true`, then Chorus will track and enforce rate limits for this instance.
+ pub async fn from_root_url(root_url: &str) -> ChorusResult {
+ let urls = UrlBundle::from_root_url(root_url).await?;
+ Instance::new(urls).await
+ }
+
+ pub async fn is_limited(api_url: &str) -> ChorusResult