QoL Updates (#452)
- Make register and login not take an instance by ownership - Add README information to `lib.rs` - Add more derives to ChorusUser and Instance - Impl From reqwest::Error for ChorusError - Add support for .well-known #449 - Remove "limited: bool" as an argument for `Instance::new` in favour of dynamic instance limit checking #450
This commit is contained in:
commit
5ff206db8a
|
@ -45,34 +45,34 @@ jobs:
|
||||||
cargo build --verbose --all-features
|
cargo build --verbose --all-features
|
||||||
cargo test --verbose --all-features
|
cargo test --verbose --all-features
|
||||||
fi
|
fi
|
||||||
wasm-safari:
|
# wasm-safari:
|
||||||
runs-on: macos-latest
|
# runs-on: macos-latest
|
||||||
steps:
|
# steps:
|
||||||
- uses: actions/checkout@v4
|
# - uses: actions/checkout@v4
|
||||||
- name: Clone spacebar server
|
# - name: Clone spacebar server
|
||||||
run: |
|
# run: |
|
||||||
git clone https://github.com/bitfl0wer/server.git
|
# git clone https://github.com/bitfl0wer/server.git
|
||||||
- uses: actions/setup-node@v3
|
# - uses: actions/setup-node@v3
|
||||||
with:
|
# with:
|
||||||
node-version: 18
|
# node-version: 18
|
||||||
cache: 'npm'
|
# cache: 'npm'
|
||||||
cache-dependency-path: server/package-lock.json
|
# cache-dependency-path: server/package-lock.json
|
||||||
- name: Prepare and start Spacebar server
|
# - name: Prepare and start Spacebar server
|
||||||
run: |
|
# run: |
|
||||||
npm install
|
# npm install
|
||||||
npm run setup
|
# npm run setup
|
||||||
npm run start &
|
# npm run start &
|
||||||
working-directory: ./server
|
# working-directory: ./server
|
||||||
- uses: Swatinem/rust-cache@v2
|
# - uses: Swatinem/rust-cache@v2
|
||||||
with:
|
# with:
|
||||||
cache-all-crates: "true"
|
# cache-all-crates: "true"
|
||||||
prefix-key: "macos"
|
# prefix-key: "macos-safari"
|
||||||
- name: Run WASM tests with Safari, Firefox, Chrome
|
# - name: Run WASM tests with Safari, Firefox, Chrome
|
||||||
run: |
|
# run: |
|
||||||
rustup target add wasm32-unknown-unknown
|
# rustup target add wasm32-unknown-unknown
|
||||||
curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash
|
# curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash
|
||||||
cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.88" --force
|
# cargo binstall --no-confirm wasm-bindgen-cli --version "0.2.88" --force
|
||||||
SAFARIDRIVER=$(which safaridriver) cargo test --target wasm32-unknown-unknown --no-default-features --features="client, rt"
|
# SAFARIDRIVER=$(which safaridriver) cargo test --target wasm32-unknown-unknown --no-default-features --features="client, rt" --no-fail-fast
|
||||||
wasm-gecko:
|
wasm-gecko:
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
steps:
|
steps:
|
||||||
|
|
20
README.md
20
README.md
|
@ -3,7 +3,6 @@
|
||||||
[![Discord]][Discord-invite]
|
[![Discord]][Discord-invite]
|
||||||
[![Build][build-shield]][build-url]
|
[![Build][build-shield]][build-url]
|
||||||
[![Coverage][coverage-shield]][coverage-url]
|
[![Coverage][coverage-shield]][coverage-url]
|
||||||
[![Contributors][contributors-shield]][contributors-url]
|
|
||||||
<img src="https://img.shields.io/static/v1?label=Status&message=Alpha&color=blue">
|
<img src="https://img.shields.io/static/v1?label=Status&message=Alpha&color=blue">
|
||||||
|
|
||||||
</br>
|
</br>
|
||||||
|
@ -16,12 +15,12 @@
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<br />
|
<br />
|
||||||
<a href="https://github.com/polyphony-chat/chorus"><strong>Explore the docs »</strong></a>
|
<a href="https://docs.rs/chorus/latest/chorus/"><strong>Explore the docs »</strong></a>
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<a href="https://github.com/polyphony-chat/chorus/issues">Report Bug</a>
|
<a href="https://github.com/polyphony-chat/chorus/issues">Report Bug</a>
|
||||||
·
|
·
|
||||||
<a href="https://github.com/polyphony-chat/chorus/issues">Request Feature</a>
|
<a href="https://crates.io/crates/chorus">crates.io</a>
|
||||||
·
|
·
|
||||||
<a href="https://discord.gg/8tKSC8wzDq">Join Discord</a>
|
<a href="https://discord.gg/8tKSC8wzDq">Join Discord</a>
|
||||||
</p>
|
</p>
|
||||||
|
@ -29,20 +28,23 @@
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
Chorus is a Rust library that allows developers to interact with multiple Spacebar-compatible APIs and Gateways (Including
|
Chorus is a Rust library which poses as an API wrapper for [Spacebar Chat](https://github.com/spacebarchat/)
|
||||||
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.
|
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
|
## A Tour of Chorus
|
||||||
|
|
||||||
Chorus combines all the required functionalities of a user-centric Spacebar library into one package. The library
|
Chorus combines all the required functionalities of a user-centric Spacebar library into one package.
|
||||||
handles a lot of things for you, such as rate limiting, authentication, and more. This means that you can focus on
|
The library handles various aspects on your behalf, such as rate limiting, authentication and maintaining
|
||||||
building your application, instead of worrying about the underlying implementation details.
|
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:
|
To get started with Chorus, import it into your project by adding the following to your `Cargo.toml` file:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chorus = "0"
|
chorus = "0.12.0"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Establishing a Connection
|
### Establishing a Connection
|
||||||
|
|
|
@ -8,7 +8,7 @@ async fn main() {
|
||||||
"wss://example.com/".to_string(),
|
"wss://example.com/".to_string(),
|
||||||
"https://example.com/cdn".to_string(),
|
"https://example.com/cdn".to_string(),
|
||||||
);
|
);
|
||||||
let instance = Instance::new(bundle, true)
|
let instance = Instance::new(bundle)
|
||||||
.await
|
.await
|
||||||
.expect("Failed to connect to the Spacebar server");
|
.expect("Failed to connect to the Spacebar server");
|
||||||
dbg!(instance.instance_info);
|
dbg!(instance.instance_info);
|
||||||
|
|
|
@ -9,7 +9,7 @@ async fn main() {
|
||||||
"wss://example.com/".to_string(),
|
"wss://example.com/".to_string(),
|
||||||
"https://example.com/cdn".to_string(),
|
"https://example.com/cdn".to_string(),
|
||||||
);
|
);
|
||||||
let instance = Instance::new(bundle, true)
|
let mut instance = Instance::new(bundle)
|
||||||
.await
|
.await
|
||||||
.expect("Failed to connect to the Spacebar server");
|
.expect("Failed to connect to the Spacebar server");
|
||||||
// Assume, you already have an account created on this instance. Registering an account works
|
// Assume, you already have an account created on this instance. Registering an account works
|
||||||
|
|
|
@ -14,7 +14,7 @@ impl Instance {
|
||||||
///
|
///
|
||||||
/// # Reference
|
/// # Reference
|
||||||
/// See <https://docs.spacebar.chat/routes/#post-/auth/login/>
|
/// See <https://docs.spacebar.chat/routes/#post-/auth/login/>
|
||||||
pub async fn login_account(mut self, login_schema: LoginSchema) -> ChorusResult<ChorusUser> {
|
pub async fn login_account(&mut self, login_schema: LoginSchema) -> ChorusResult<ChorusUser> {
|
||||||
let endpoint_url = self.urls.api.clone() + "/auth/login";
|
let endpoint_url = self.urls.api.clone() + "/auth/login";
|
||||||
let chorus_request = ChorusRequest {
|
let chorus_request = ChorusRequest {
|
||||||
request: Client::new()
|
request: Client::new()
|
||||||
|
|
|
@ -19,7 +19,7 @@ impl Instance {
|
||||||
/// # Reference
|
/// # Reference
|
||||||
/// See <https://docs.spacebar.chat/routes/#post-/auth/register/>
|
/// See <https://docs.spacebar.chat/routes/#post-/auth/register/>
|
||||||
pub async fn register_account(
|
pub async fn register_account(
|
||||||
mut self,
|
&mut self,
|
||||||
register_schema: RegisterSchema,
|
register_schema: RegisterSchema,
|
||||||
) -> ChorusResult<ChorusUser> {
|
) -> ChorusResult<ChorusUser> {
|
||||||
let endpoint_url = self.urls.api.clone() + "/auth/register";
|
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();
|
self.limits_information.as_mut().unwrap().ratelimits = shell.limits.unwrap();
|
||||||
}
|
}
|
||||||
let user_object = self.get_user(token.clone(), None).await.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 mut identify = GatewayIdentifyPayload::common();
|
||||||
let gateway: GatewayHandle = Gateway::spawn(self.urls.wss.clone()).await.unwrap();
|
let gateway: GatewayHandle = Gateway::spawn(self.urls.wss.clone()).await.unwrap();
|
||||||
identify.token = token.clone();
|
identify.token = token.clone();
|
||||||
|
|
|
@ -44,6 +44,18 @@ custom_error! {
|
||||||
InvalidArguments{error: String} = "Invalid arguments were provided. Error: {error}"
|
InvalidArguments{error: String} = "Invalid arguments were provided. Error: {error}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<reqwest::Error> 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! {
|
custom_error! {
|
||||||
#[derive(PartialEq, Eq)]
|
#[derive(PartialEq, Eq)]
|
||||||
pub ObserverError
|
pub ObserverError
|
||||||
|
|
104
src/instance.rs
104
src/instance.rs
|
@ -12,44 +12,85 @@ use crate::errors::ChorusResult;
|
||||||
use crate::gateway::{Gateway, GatewayHandle};
|
use crate::gateway::{Gateway, GatewayHandle};
|
||||||
use crate::ratelimiter::ChorusRequest;
|
use crate::ratelimiter::ChorusRequest;
|
||||||
use crate::types::types::subconfigs::limits::rates::RateLimits;
|
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;
|
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.
|
/// 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.
|
/// If `limits_information` is `None`, then the instance will not be rate limited.
|
||||||
pub struct Instance {
|
pub struct Instance {
|
||||||
pub urls: UrlBundle,
|
pub urls: UrlBundle,
|
||||||
pub instance_info: GeneralConfiguration,
|
pub instance_info: GeneralConfiguration,
|
||||||
pub limits_information: Option<LimitsInformation>,
|
pub limits_information: Option<LimitsInformation>,
|
||||||
|
#[serde(skip)]
|
||||||
pub client: Client,
|
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<H: std::hash::Hasher>(&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 struct LimitsInformation {
|
||||||
pub ratelimits: HashMap<LimitType, Limit>,
|
pub ratelimits: HashMap<LimitType, Limit>,
|
||||||
pub configuration: RateLimits,
|
pub configuration: RateLimits,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::hash::Hash for LimitsInformation {
|
||||||
|
fn hash<H: std::hash::Hasher>(&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 {
|
impl Instance {
|
||||||
/// Creates a new [`Instance`] from the [relevant instance urls](UrlBundle), where `limited` is whether or not to automatically use rate limits.
|
/// 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, limited: bool) -> ChorusResult<Instance> {
|
pub async fn new(urls: UrlBundle) -> ChorusResult<Instance> {
|
||||||
let limits_information;
|
let is_limited: Option<LimitsConfiguration> = Instance::is_limited(&urls.api).await?;
|
||||||
if limited {
|
let limit_information;
|
||||||
let limits_configuration = ChorusRequest::get_limits_config(&urls.api).await?.rate;
|
|
||||||
let limits = ChorusRequest::limits_config_to_hashmap(&limits_configuration);
|
if let Some(limits_configuration) = is_limited {
|
||||||
limits_information = Some(LimitsInformation {
|
let limits = ChorusRequest::limits_config_to_hashmap(&limits_configuration.rate);
|
||||||
|
limit_information = Some(LimitsInformation {
|
||||||
ratelimits: limits,
|
ratelimits: limits,
|
||||||
configuration: limits_configuration,
|
configuration: limits_configuration.rate,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
limits_information = None;
|
limit_information = None
|
||||||
}
|
}
|
||||||
let mut instance = Instance {
|
let mut instance = Instance {
|
||||||
urls: urls.clone(),
|
urls: urls.clone(),
|
||||||
// Will be overwritten in the next step
|
// Will be overwritten in the next step
|
||||||
instance_info: GeneralConfiguration::default(),
|
instance_info: GeneralConfiguration::default(),
|
||||||
limits_information,
|
limits_information: limit_information,
|
||||||
client: Client::new(),
|
client: Client::new(),
|
||||||
};
|
};
|
||||||
instance.instance_info = match instance.general_configuration_schema().await {
|
instance.instance_info = match instance.general_configuration_schema().await {
|
||||||
|
@ -61,12 +102,39 @@ impl Instance {
|
||||||
};
|
};
|
||||||
Ok(instance)
|
Ok(instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn clone_limits_if_some(&self) -> Option<HashMap<LimitType, Limit>> {
|
pub(crate) fn clone_limits_if_some(&self) -> Option<HashMap<LimitType, Limit>> {
|
||||||
if self.limits_information.is_some() {
|
if self.limits_information.is_some() {
|
||||||
return Some(self.limits_information.as_ref().unwrap().ratelimits.clone());
|
return Some(self.limits_information.as_ref().unwrap().ratelimits.clone());
|
||||||
}
|
}
|
||||||
None
|
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<Instance> {
|
||||||
|
let urls = UrlBundle::from_root_url(root_url).await?;
|
||||||
|
Instance::new(urls).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn is_limited(api_url: &str) -> ChorusResult<Option<LimitsConfiguration>> {
|
||||||
|
let api_url = UrlBundle::parse_url(api_url.to_string());
|
||||||
|
let client = Client::new();
|
||||||
|
let request = client
|
||||||
|
.get(format!("{}/policies/instance/limits", &api_url))
|
||||||
|
.header(http::header::ACCEPT, "application/json")
|
||||||
|
.build()?;
|
||||||
|
let resp = match client.execute(request).await {
|
||||||
|
Ok(response) => response,
|
||||||
|
Err(_) => return Ok(None),
|
||||||
|
};
|
||||||
|
match resp.json::<LimitsConfiguration>().await {
|
||||||
|
Ok(limits) => Ok(Some(limits)),
|
||||||
|
Err(_) => Ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
@ -93,6 +161,16 @@ pub struct ChorusUser {
|
||||||
pub gateway: GatewayHandle,
|
pub gateway: GatewayHandle,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq for ChorusUser {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.token == other.token
|
||||||
|
&& self.limits == other.limits
|
||||||
|
&& self.gateway.url == other.gateway.url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for ChorusUser {}
|
||||||
|
|
||||||
impl ChorusUser {
|
impl ChorusUser {
|
||||||
pub fn token(&self) -> String {
|
pub fn token(&self) -> String {
|
||||||
self.token.clone()
|
self.token.clone()
|
||||||
|
|
168
src/lib.rs
168
src/lib.rs
|
@ -1,7 +1,94 @@
|
||||||
//! A library for interacting with one or multiple Spacebar-compatible APIs and Gateways.
|
/*!
|
||||||
//!
|
Chorus combines all the required functionalities of a user-centric Spacebar library into one package.
|
||||||
//! # About
|
The library handles various aspects on your behalf, such as rate limiting, authentication and maintaining
|
||||||
//!Chorus is a Rust library that allows developers to interact with multiple Spacebar-compatible APIs and Gateways 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.
|
a WebSocket connection to the Gateway. This means that you can focus on building your application,
|
||||||
|
instead of worrying about the underlying implementation details.
|
||||||
|
|
||||||
|
### Establishing a Connection
|
||||||
|
|
||||||
|
To connect to a Spacebar compatible server, you need to create an [`Instance`](https://docs.rs/chorus/latest/chorus/instance/struct.Instance.html) like this:
|
||||||
|
|
||||||
|
```rs
|
||||||
|
use chorus::instance::Instance;
|
||||||
|
use chorus::UrlBundle;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
let bundle = UrlBundle::new(
|
||||||
|
"https://example.com/api".to_string(),
|
||||||
|
"wss://example.com/".to_string(),
|
||||||
|
"https://example.com/cdn".to_string(),
|
||||||
|
);
|
||||||
|
let instance = Instance::new(bundle, true)
|
||||||
|
.await
|
||||||
|
.expect("Failed to connect to the Spacebar server");
|
||||||
|
// You can create as many instances of `Instance` as you want, but each `Instance` should likely be unique.
|
||||||
|
dbg!(instance.instance_info);
|
||||||
|
dbg!(instance.limits_information);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This Instance can now be used to log in, register and from there on, interact with the server in all sorts of ways.
|
||||||
|
|
||||||
|
### Logging In
|
||||||
|
|
||||||
|
Logging in correctly provides you with an instance of [`ChorusUser`](https://docs.rs/chorus/latest/chorus/instance/struct.ChorusUser.html), with which you can interact with the server and
|
||||||
|
manipulate the account. Assuming you already have an account on the server, you can log in like this:
|
||||||
|
|
||||||
|
```rs
|
||||||
|
use chorus::types::LoginSchema;
|
||||||
|
// Assume, you already have an account created on this instance. Registering an account works
|
||||||
|
// the same way, but you'd use the Register-specific Structs and methods instead.
|
||||||
|
let login_schema = LoginSchema {
|
||||||
|
login: "user@example.com".to_string(),
|
||||||
|
password: "Correct-Horse-Battery-Staple".to_string(),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
// Each user connects to the Gateway. The Gateway connection lives on a seperate thread. Depending on
|
||||||
|
// the runtime feature you choose, this can potentially take advantage of all of your computers' threads.
|
||||||
|
let user = instance
|
||||||
|
.login_account(login_schema)
|
||||||
|
.await
|
||||||
|
.expect("An error occurred during the login process");
|
||||||
|
dbg!(user.belongs_to);
|
||||||
|
dbg!(&user.object.read().unwrap().username);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Supported Platforms
|
||||||
|
|
||||||
|
All major desktop operating systems (Windows, macOS (aarch64/x86_64), Linux (aarch64/x86_64)) are supported.
|
||||||
|
`wasm32-unknown-unknown` is a supported compilation target on versions `0.12.0` and up. This allows you to use
|
||||||
|
Chorus in your browser, or in any other environment that supports WebAssembly.
|
||||||
|
|
||||||
|
We recommend checking out the examples directory, as well as the documentation for more information.
|
||||||
|
|
||||||
|
## MSRV (Minimum Supported Rust Version)
|
||||||
|
|
||||||
|
Rust **1.67.1**. This number might change at any point while Chorus is not yet at version 1.0.0.
|
||||||
|
|
||||||
|
## Development Setup
|
||||||
|
|
||||||
|
Make sure that you have at least Rust 1.67.1 installed. You can check your Rust version by running `cargo --version`
|
||||||
|
in your terminal. To compile for `wasm32-unknown-unknown`, you need to install the `wasm32-unknown-unknown` target.
|
||||||
|
You can do this by running `rustup target add wasm32-unknown-unknown`.
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
|
||||||
|
In general, the tests will require you to run a local instance of the Spacebar server. You can find instructions on how
|
||||||
|
to do that [here](https://docs.spacebar.chat/setup/server/). You can find a pre-configured version of the server
|
||||||
|
[here](https://github.com/bitfl0wer/server). It is recommended to use the pre-configured version, as certain things
|
||||||
|
like "proxy connection checking" are already disabled on this version, which otherwise might break tests.
|
||||||
|
|
||||||
|
### wasm
|
||||||
|
|
||||||
|
To test for wasm, you will need to `cargo install wasm-pack`. You can then run
|
||||||
|
`wasm-pack test --<chrome/firefox/safari> --headless -- --target wasm32-unknown-unknown --features="rt, client" --no-default-features`
|
||||||
|
to run the tests for wasm.
|
||||||
|
|
||||||
|
## Versioning
|
||||||
|
|
||||||
|
This crate uses Semantic Versioning 2.0.0 as its versioning scheme. You can read the specification [here](https://semver.org/spec/v2.0.0.html).
|
||||||
|
!*/
|
||||||
#![doc(
|
#![doc(
|
||||||
html_logo_url = "https://raw.githubusercontent.com/polyphony-chat/design/main/branding/polyphony-chorus-round-8bit.png"
|
html_logo_url = "https://raw.githubusercontent.com/polyphony-chat/design/main/branding/polyphony-chorus-round-8bit.png"
|
||||||
)]
|
)]
|
||||||
|
@ -14,11 +101,23 @@
|
||||||
clippy::new_without_default,
|
clippy::new_without_default,
|
||||||
clippy::useless_conversion
|
clippy::useless_conversion
|
||||||
)]
|
)]
|
||||||
|
#![warn(
|
||||||
|
clippy::todo,
|
||||||
|
clippy::unimplemented,
|
||||||
|
clippy::dbg_macro,
|
||||||
|
clippy::print_stdout,
|
||||||
|
clippy::print_stderr
|
||||||
|
)]
|
||||||
#[cfg(all(feature = "rt", feature = "rt_multi_thread"))]
|
#[cfg(all(feature = "rt", feature = "rt_multi_thread"))]
|
||||||
compile_error!("feature \"rt\" and feature \"rt_multi_thread\" cannot be enabled at the same time");
|
compile_error!("feature \"rt\" and feature \"rt_multi_thread\" cannot be enabled at the same time");
|
||||||
|
|
||||||
|
use errors::ChorusResult;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use types::types::domains_configuration::WellKnownResponse;
|
||||||
use url::{ParseError, Url};
|
use url::{ParseError, Url};
|
||||||
|
|
||||||
|
use crate::errors::ChorusError;
|
||||||
|
|
||||||
#[cfg(feature = "client")]
|
#[cfg(feature = "client")]
|
||||||
pub mod api;
|
pub mod api;
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
|
@ -32,7 +131,7 @@ pub mod types;
|
||||||
#[cfg(feature = "client")]
|
#[cfg(feature = "client")]
|
||||||
pub mod voice;
|
pub mod voice;
|
||||||
|
|
||||||
#[derive(Clone, Default, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Default, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
/// A URLBundle bundles together the API-, Gateway- and CDN-URLs of a Spacebar instance.
|
/// A URLBundle bundles together the API-, Gateway- and CDN-URLs of a Spacebar instance.
|
||||||
///
|
///
|
||||||
/// # Notes
|
/// # Notes
|
||||||
|
@ -80,7 +179,7 @@ impl UrlBundle {
|
||||||
let url_fmt = format!("http://{}", url);
|
let url_fmt = format!("http://{}", url);
|
||||||
return UrlBundle::parse_url(url_fmt);
|
return UrlBundle::parse_url(url_fmt);
|
||||||
}
|
}
|
||||||
Err(_) => panic!("Invalid URL"),
|
Err(_) => panic!("Invalid URL"), // TODO: should not panic here
|
||||||
};
|
};
|
||||||
// if the last character of the string is a slash, remove it.
|
// if the last character of the string is a slash, remove it.
|
||||||
let mut url_string = url.to_string();
|
let mut url_string = url.to_string();
|
||||||
|
@ -89,6 +188,63 @@ impl UrlBundle {
|
||||||
}
|
}
|
||||||
url_string
|
url_string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Performs a few HTTP requests to try and retrieve a `UrlBundle` from an instances' root url.
|
||||||
|
/// The method tries to retrieve the `UrlBundle` via these three strategies, in order:
|
||||||
|
/// - GET: `$url/.well-known/spacebar` -> Retrieve UrlBundle via `$wellknownurl/api/policies/instance/domains`
|
||||||
|
/// - GET: `$url/api/policies/instance/domains`
|
||||||
|
/// - GET: `$url/policies/instance/domains`
|
||||||
|
///
|
||||||
|
/// The URL stored at `.well-known/spacebar` is the instances' API endpoint. The API
|
||||||
|
/// stores the CDN and WSS URLs under the `$api/policies/instance/domains` endpoint. If all three
|
||||||
|
/// of the above approaches fail, it is very likely that the instance is misconfigured, unreachable, or that
|
||||||
|
/// a wrong URL was provided.
|
||||||
|
pub async fn from_root_url(url: &str) -> ChorusResult<UrlBundle> {
|
||||||
|
let parsed = UrlBundle::parse_url(url.to_string());
|
||||||
|
let client = reqwest::Client::new();
|
||||||
|
let request_wellknown = client
|
||||||
|
.get(format!("{}/.well-known/spacebar", &parsed))
|
||||||
|
.header(http::header::ACCEPT, "application/json")
|
||||||
|
.build()?;
|
||||||
|
let response_wellknown = client.execute(request_wellknown).await?;
|
||||||
|
if response_wellknown.status().is_success() {
|
||||||
|
let body = response_wellknown.json::<WellKnownResponse>().await?.api;
|
||||||
|
UrlBundle::from_api_url(&body).await
|
||||||
|
} else {
|
||||||
|
if let Ok(response_slash_api) =
|
||||||
|
UrlBundle::from_api_url(&format!("{}/api/policies/instance/domains", parsed)).await
|
||||||
|
{
|
||||||
|
return Ok(response_slash_api);
|
||||||
|
}
|
||||||
|
if let Ok(response_api) =
|
||||||
|
UrlBundle::from_api_url(&format!("{}/policies/instance/domains", parsed)).await
|
||||||
|
{
|
||||||
|
Ok(response_api)
|
||||||
|
} else {
|
||||||
|
Err(ChorusError::RequestFailed { url: parsed.to_string(), error: "Could not retrieve UrlBundle from url after trying 3 different approaches. Check the provided Url and make sure the instance is reachable.".to_string() } )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn from_api_url(url: &str) -> ChorusResult<UrlBundle> {
|
||||||
|
let client = reqwest::Client::new();
|
||||||
|
let request = client
|
||||||
|
.get(url)
|
||||||
|
.header(http::header::ACCEPT, "application/json")
|
||||||
|
.build()?;
|
||||||
|
let response = client.execute(request).await?;
|
||||||
|
if let Ok(body) = response
|
||||||
|
.json::<types::types::domains_configuration::Domains>()
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(UrlBundle::new(body.api_endpoint, body.gateway, body.cdn))
|
||||||
|
} else {
|
||||||
|
Err(ChorusError::RequestFailed {
|
||||||
|
url: url.to_string(),
|
||||||
|
error: "Could not retrieve a UrlBundle from the given url. Check the provided url and make sure the instance is reachable.".to_string(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -349,7 +349,7 @@ impl ChorusRequest {
|
||||||
///
|
///
|
||||||
/// # Reference
|
/// # Reference
|
||||||
/// See <https://docs.spacebar.chat/routes/#get-/policies/instance/limits/>
|
/// See <https://docs.spacebar.chat/routes/#get-/policies/instance/limits/>
|
||||||
pub(crate) async fn get_limits_config(url_api: &str) -> ChorusResult<LimitsConfiguration> {
|
pub async fn get_limits_config(url_api: &str) -> ChorusResult<LimitsConfiguration> {
|
||||||
let request = Client::new()
|
let request = Client::new()
|
||||||
.get(format!("{}/policies/instance/limits/", url_api))
|
.get(format!("{}/policies/instance/limits/", url_api))
|
||||||
.send()
|
.send()
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, Eq, PartialEq, Hash, Clone, Debug)]
|
||||||
|
/// Represents the result of the `$rooturl/.well-known/spacebar` endpoint.
|
||||||
|
///
|
||||||
|
/// See <https://docs.spacebar.chat/setup/server/wellknown/> for more information.
|
||||||
|
pub struct WellKnownResponse {
|
||||||
|
pub api: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, Eq, PartialEq, Hash, Clone, Debug)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
/// Represents the result of the `$api/policies/instance/domains` endpoint.
|
||||||
|
pub struct Domains {
|
||||||
|
pub cdn: String,
|
||||||
|
pub gateway: String,
|
||||||
|
pub api_endpoint: String,
|
||||||
|
pub default_api_version: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for Domains {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{{\n\tCDN URL: {},\n\tGateway URL: {},\n\tAPI Endpoint: {},\n\tDefault API Version: {}\n}}",
|
||||||
|
self.cdn, self.gateway, self.api_endpoint, self.default_api_version
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::types::utils::Snowflake;
|
use crate::types::utils::Snowflake;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct GeneralConfiguration {
|
pub struct GeneralConfiguration {
|
||||||
pub instance_name: String,
|
pub instance_name: String,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
pub mod api_configuration;
|
pub mod api_configuration;
|
||||||
pub mod cdn_configuration;
|
pub mod cdn_configuration;
|
||||||
pub mod defaults_configuration;
|
pub mod defaults_configuration;
|
||||||
|
pub mod domains_configuration;
|
||||||
pub mod email_configuration;
|
pub mod email_configuration;
|
||||||
pub mod endpoint_configuration;
|
pub mod endpoint_configuration;
|
||||||
pub mod external_tokens_configuration;
|
pub mod external_tokens_configuration;
|
||||||
|
|
|
@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::types::config::types::subconfigs::limits::ratelimits::RateLimitOptions;
|
use crate::types::config::types::subconfigs::limits::ratelimits::RateLimitOptions;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
|
||||||
pub struct AuthRateLimit {
|
pub struct AuthRateLimit {
|
||||||
pub login: RateLimitOptions,
|
pub login: RateLimitOptions,
|
||||||
pub register: RateLimitOptions,
|
pub register: RateLimitOptions,
|
||||||
|
|
|
@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};
|
||||||
pub mod auth;
|
pub mod auth;
|
||||||
pub mod route;
|
pub mod route;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct RateLimitOptions {
|
pub struct RateLimitOptions {
|
||||||
pub bot: Option<u64>,
|
pub bot: Option<u64>,
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::types::config::types::subconfigs::limits::ratelimits::{
|
||||||
auth::AuthRateLimit, RateLimitOptions,
|
auth::AuthRateLimit, RateLimitOptions,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
|
||||||
pub struct RouteRateLimit {
|
pub struct RouteRateLimit {
|
||||||
pub guild: RateLimitOptions,
|
pub guild: RateLimitOptions,
|
||||||
pub webhook: RateLimitOptions,
|
pub webhook: RateLimitOptions,
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::types::{
|
||||||
LimitType,
|
LimitType,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
|
||||||
pub struct RateLimits {
|
pub struct RateLimits {
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
pub ip: RateLimitOptions,
|
pub ip: RateLimitOptions,
|
||||||
|
|
|
@ -25,7 +25,7 @@ pub enum LimitType {
|
||||||
|
|
||||||
/// A struct that represents the current ratelimits, either instance-wide or user-wide.
|
/// A struct that represents the current ratelimits, either instance-wide or user-wide.
|
||||||
/// See <https://discord.com/developers/docs/topics/rate-limits#rate-limits> for more information.
|
/// See <https://discord.com/developers/docs/topics/rate-limits#rate-limits> for more information.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||||||
pub struct Limit {
|
pub struct Limit {
|
||||||
pub bucket: LimitType,
|
pub bucket: LimitType,
|
||||||
pub limit: u64,
|
pub limit: u64,
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use chorus::types::RegisterSchema;
|
use chorus::types::{LoginSchema, RegisterSchema};
|
||||||
// PRETTYFYME: Move common wasm setup to common.rs
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use wasm_bindgen_test::*;
|
use wasm_bindgen_test::*;
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
@ -10,13 +9,91 @@ mod common;
|
||||||
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
|
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
|
||||||
#[cfg_attr(not(target_arch = "wasm32"), tokio::test)]
|
#[cfg_attr(not(target_arch = "wasm32"), tokio::test)]
|
||||||
async fn test_registration() {
|
async fn test_registration() {
|
||||||
let bundle = common::setup().await;
|
let mut bundle = common::setup().await;
|
||||||
let reg = RegisterSchema {
|
let reg = RegisterSchema {
|
||||||
username: "Hiiii".into(),
|
username: "Hiiii".into(),
|
||||||
date_of_birth: Some("2000-01-01".to_string()),
|
date_of_birth: Some("2000-01-01".to_string()),
|
||||||
consent: true,
|
consent: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
bundle.instance.clone().register_account(reg).await.unwrap();
|
bundle.instance.register_account(reg).await.unwrap();
|
||||||
|
common::teardown(bundle).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
|
||||||
|
#[cfg_attr(not(target_arch = "wasm32"), tokio::test)]
|
||||||
|
async fn test_login() {
|
||||||
|
let mut bundle = common::setup().await;
|
||||||
|
let reg = RegisterSchema {
|
||||||
|
username: "Hiiii".into(),
|
||||||
|
email: Some("testuser1@integrationtesting.xyz".into()),
|
||||||
|
password: Some("Correct-Horse-Battery-Staple1".into()),
|
||||||
|
date_of_birth: Some("2000-01-01".to_string()),
|
||||||
|
consent: true,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
bundle.instance.register_account(reg).await.unwrap();
|
||||||
|
let login = LoginSchema {
|
||||||
|
login: "testuser1@integrationtesting.xyz".into(),
|
||||||
|
password: "Correct-Horse-Battery-Staple1".into(),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
bundle.instance.login_account(login).await.unwrap();
|
||||||
|
common::teardown(bundle).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
|
||||||
|
#[cfg_attr(not(target_arch = "wasm32"), tokio::test)]
|
||||||
|
async fn test_wrong_login() {
|
||||||
|
let mut bundle = common::setup().await;
|
||||||
|
let reg = RegisterSchema {
|
||||||
|
username: "Hiiii".into(),
|
||||||
|
email: Some("testuser2@integrationtesting.xyz".into()),
|
||||||
|
password: Some("Correct-Horse-Battery-Staple1".into()),
|
||||||
|
date_of_birth: Some("2000-01-01".to_string()),
|
||||||
|
consent: true,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
bundle.instance.register_account(reg).await.unwrap();
|
||||||
|
let login = LoginSchema {
|
||||||
|
login: "testuser2@integrationtesting.xyz".into(),
|
||||||
|
password: "Correct-Horse-Battery-Staple2".into(),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let res = bundle.instance.login_account(login).await;
|
||||||
|
assert!(res.is_err());
|
||||||
|
common::teardown(bundle).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
|
||||||
|
#[cfg_attr(not(target_arch = "wasm32"), tokio::test)]
|
||||||
|
async fn test_login_with_token() {
|
||||||
|
let mut bundle = common::setup().await;
|
||||||
|
|
||||||
|
let token = &bundle.user.token;
|
||||||
|
let other_user = bundle
|
||||||
|
.instance
|
||||||
|
.login_with_token(token.clone())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
bundle.user.object.read().unwrap().id,
|
||||||
|
other_user.object.read().unwrap().id
|
||||||
|
);
|
||||||
|
assert_eq!(bundle.user.token, other_user.token);
|
||||||
|
|
||||||
|
common::teardown(bundle).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
|
||||||
|
#[cfg_attr(not(target_arch = "wasm32"), tokio::test)]
|
||||||
|
async fn test_login_with_invalid_token() {
|
||||||
|
let mut bundle = common::setup().await;
|
||||||
|
|
||||||
|
let token = "invalid token lalalalala".to_string();
|
||||||
|
let other_user = bundle.instance.login_with_token(token.clone()).await;
|
||||||
|
|
||||||
|
assert!(other_user.is_err());
|
||||||
|
|
||||||
common::teardown(bundle).await;
|
common::teardown(bundle).await;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ use chorus::types::{
|
||||||
};
|
};
|
||||||
|
|
||||||
mod common;
|
mod common;
|
||||||
// PRETTYFYME: Move common wasm setup to common.rs
|
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use wasm_bindgen_test::*;
|
use wasm_bindgen_test::*;
|
||||||
|
|
|
@ -57,7 +57,7 @@ pub(crate) async fn setup() -> TestBundle {
|
||||||
"ws://localhost:3001".to_string(),
|
"ws://localhost:3001".to_string(),
|
||||||
"http://localhost:3001".to_string(),
|
"http://localhost:3001".to_string(),
|
||||||
);
|
);
|
||||||
let instance = Instance::new(urls.clone(), true).await.unwrap();
|
let instance = Instance::new(urls.clone()).await.unwrap();
|
||||||
// Requires the existance of the below user.
|
// Requires the existance of the below user.
|
||||||
let reg = RegisterSchema {
|
let reg = RegisterSchema {
|
||||||
username: "integrationtestuser".into(),
|
username: "integrationtestuser".into(),
|
||||||
|
|
|
@ -5,7 +5,6 @@ use std::sync::{Arc, RwLock};
|
||||||
use chorus::errors::GatewayError;
|
use chorus::errors::GatewayError;
|
||||||
use chorus::gateway::*;
|
use chorus::gateway::*;
|
||||||
use chorus::types::{self, ChannelModifySchema, RoleCreateModifySchema, RoleObject};
|
use chorus::types::{self, ChannelModifySchema, RoleCreateModifySchema, RoleObject};
|
||||||
// PRETTYFYME: Move common wasm setup to common.rs
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use wasm_bindgen_test::*;
|
use wasm_bindgen_test::*;
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
|
|
@ -3,7 +3,6 @@ use chorus::types::{
|
||||||
};
|
};
|
||||||
|
|
||||||
mod common;
|
mod common;
|
||||||
// PRETTYFYME: Move common wasm setup to common.rs
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use wasm_bindgen_test::*;
|
use wasm_bindgen_test::*;
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
mod common;
|
mod common;
|
||||||
// PRETTYFYME: Move common wasm setup to common.rs
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use wasm_bindgen_test::*;
|
use wasm_bindgen_test::*;
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
mod common;
|
mod common;
|
||||||
use chorus::types::CreateChannelInviteSchema;
|
use chorus::types::CreateChannelInviteSchema;
|
||||||
// PRETTYFYME: Move common wasm setup to common.rs
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use wasm_bindgen_test::*;
|
use wasm_bindgen_test::*;
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use chorus::{errors::ChorusResult, types::GuildMember};
|
use chorus::{errors::ChorusResult, types::GuildMember};
|
||||||
// PRETTYFYME: Move common wasm setup to common.rs
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use wasm_bindgen_test::*;
|
use wasm_bindgen_test::*;
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
|
|
@ -2,7 +2,6 @@ use std::fs::File;
|
||||||
use std::io::{BufReader, Read};
|
use std::io::{BufReader, Read};
|
||||||
|
|
||||||
use chorus::types::{self, Guild, Message, MessageSearchQuery};
|
use chorus::types::{self, Guild, Message, MessageSearchQuery};
|
||||||
// PRETTYFYME: Move common wasm setup to common.rs
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use wasm_bindgen_test::*;
|
use wasm_bindgen_test::*;
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use chorus::types::{self, Relationship, RelationshipType};
|
use chorus::types::{self, Relationship, RelationshipType};
|
||||||
// PRETTYFYME: Move common wasm setup to common.rs
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use wasm_bindgen_test::*;
|
use wasm_bindgen_test::*;
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use chorus::types::{self, RoleCreateModifySchema, RoleObject};
|
use chorus::types::{self, RoleCreateModifySchema, RoleObject};
|
||||||
// PRETTYFYME: Move common wasm setup to common.rs
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use wasm_bindgen_test::*;
|
use wasm_bindgen_test::*;
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
use chorus::types::types::domains_configuration::WellKnownResponse;
|
||||||
|
use chorus::UrlBundle;
|
||||||
|
use serde_json::json;
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
use wasm_bindgen_test::*;
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
wasm_bindgen_test_configure!(run_in_browser);
|
||||||
|
|
||||||
|
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
|
||||||
|
#[cfg_attr(not(target_arch = "wasm32"), tokio::test)]
|
||||||
|
async fn test_parse_url() {
|
||||||
|
// TODO: Currently only tests two of the three branches in UrlBundle::from_root_domain.
|
||||||
|
let url = url::Url::parse("http://localhost:3001/").unwrap();
|
||||||
|
UrlBundle::from_root_url(url.as_str()).await.unwrap();
|
||||||
|
let url = url::Url::parse("http://localhost:3001/api/").unwrap();
|
||||||
|
UrlBundle::from_root_url(url.as_str()).await.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
|
||||||
|
#[cfg_attr(not(target_arch = "wasm32"), tokio::test)]
|
||||||
|
async fn test_parse_wellknown() {
|
||||||
|
let json = json!({
|
||||||
|
"api": "http://localhost:3001/api/v9"
|
||||||
|
});
|
||||||
|
let _well_known: WellKnownResponse = serde_json::from_value(json).unwrap();
|
||||||
|
}
|
Loading…
Reference in New Issue