Skip to content
This repository was archived by the owner on Jan 2, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,10 @@ async fn main() {

// This instance will later need to be shared across threads and users, so we'll
// store it inside of the `Shared` type (note the `into_shared()` method call)
let instance = Instance::new("https://example.com", None)
let instance = Instance::new("https://example.com")
.await
.expect("Failed to connect to the Spacebar server")
.into_shared();
.into_shared();

// You can create as many instances of `Instance` as you want, but each `Instance` should likely be unique.

Expand Down
33 changes: 31 additions & 2 deletions examples/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use chorus::{instance::Instance, types::IntoShared};
use chorus::{
gateway::{GatewayEncoding, GatewayOptions, GatewayTransportCompression},
instance::{Instance, InstanceBuilder, InstanceSoftware},
types::IntoShared,
};

#[tokio::main(flavor = "current_thread")]
async fn main() {
// This instance will later need to be shared across threads and users, so we'll
// store it inside of the `Shared` type (note the `into_shared()` method call)
let instance = Instance::new("https://example.com", None)
let instance = Instance::new("https://example.com")
.await
.expect("Failed to connect to the Spacebar server")
.into_shared();
Expand All @@ -21,4 +25,29 @@ async fn main() {

dbg!(&instance_lock.instance_info);
dbg!(&instance_lock.limits_information);

// The above way is the easiest to create an instance, but you may want more options
//
// To do so, you can use InstanceBuilder:
let instance = InstanceBuilder::new("https://other-example.com".to_string())
// Customize how our gateway connections will be made
.with_gateway_options(GatewayOptions {
encoding: GatewayEncoding::Json,

// Explicitly disables Gateway compression, if we want to
transport_compression: GatewayTransportCompression::None,
})
// Skip fetching ratelimits and instance info, we know we our sever doesn't support that
.skip_optional_requests(true)
// Skip automatically detecting the software, we know which it is
.with_software(InstanceSoftware::Other)
// Once we're ready we call build
.build()
.await
.expect("Failed to connect to the Spacebar server")
.into_shared();

let instance_lock = instance.read().unwrap();
dbg!(&instance_lock.instance_info);
dbg!(&instance_lock.limits_information);
}
4 changes: 3 additions & 1 deletion examples/login.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,19 @@ use chorus::types::{IntoShared, LoginSchema};

#[tokio::main(flavor = "current_thread")]
async fn main() {
let instance = Instance::new("https://example.com/", None)
let instance = Instance::new("https://example.com/")
.await
.expect("Failed to connect to the Spacebar server")
.into_shared();

// 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. Each users' Gateway connection lives on a separate thread. Depending on
// the runtime feature you choose, this can potentially take advantage of all of your computers' threads.
//
Expand Down
19 changes: 14 additions & 5 deletions src/api/auth/login.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,17 @@ impl Instance {
instance: Shared<Instance>,
login_schema: LoginSchema,
) -> ChorusResult<ChorusUser> {
let endpoint_url = instance.read().unwrap().urls.api.clone() + "/auth/login";
let instance_read = instance.read().unwrap();

let endpoint_url = instance_read.urls.api.clone() + "/auth/login";
let chorus_request = ChorusRequest {
request: Client::new().post(endpoint_url).json(&login_schema),
limit_type: LimitType::AuthLogin,
}
// Note: yes, this is still sent even for login and register
.with_client_properties(&ClientProperties::default());
.with_client_properties(&instance_read.default_client_properties);

drop(instance_read);

// We do not have a user yet, and the UserRateLimits will not be affected by a login
// request (since login is an instance wide limit), which is why we are just cloning the
Expand All @@ -58,15 +62,19 @@ impl Instance {
authenticator: MfaAuthenticationType,
schema: VerifyMFALoginSchema,
) -> ChorusResult<ChorusUser> {
let instance_read = instance.read().unwrap();

let endpoint_url =
instance.read().unwrap().urls.api.clone() + "/auth/mfa/" + &authenticator.to_string();
instance_read.urls.api.clone() + "/auth/mfa/" + &authenticator.to_string();

let chorus_request = ChorusRequest {
request: Client::new().post(endpoint_url).json(&schema),
limit_type: LimitType::AuthLogin,
}
// Note: yes, this is still sent even for login and register
.with_client_properties(&ClientProperties::default());
.with_client_properties(&instance_read.default_client_properties);

drop(instance_read);

let mut user = ChorusUser::shell(instance, "None").await;

Expand Down Expand Up @@ -108,7 +116,8 @@ impl Instance {
.header("Content-Type", "application/json")
.json(&schema),
limit_type: LimitType::Ip,
};
}
.with_client_properties(&self.default_client_properties);

let send_mfa_sms_response = chorus_request
.send_anonymous_and_deserialize_response::<SendMfaSmsResponse>(self)
Expand Down
8 changes: 6 additions & 2 deletions src/api/auth/register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,17 @@ impl Instance {
instance: Shared<Instance>,
register_schema: RegisterSchema,
) -> ChorusResult<ChorusUser> {
let endpoint_url = instance.read().unwrap().urls.api.clone() + "/auth/register";
let instance_read = instance.read().unwrap();

let endpoint_url = instance_read.urls.api.clone() + "/auth/register";
let chorus_request = ChorusRequest {
request: Client::new().post(endpoint_url).json(&register_schema),
limit_type: LimitType::AuthRegister,
}
// Note: yes, this is still sent even for login and register
.with_client_properties(&ClientProperties::default());
.with_client_properties(&instance_read.default_client_properties);

drop(instance_read);

// We do not have a user yet, and the UserRateLimits will not be affected by a login
// request (since register is an instance wide limit), which is why we are just cloning
Expand Down
6 changes: 4 additions & 2 deletions src/api/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ impl Instance {
let chorus_request = ChorusRequest {
request: Client::new().get(url),
limit_type: LimitType::Global,
};
}
.with_client_properties(&self.default_client_properties);

chorus_request
.send_anonymous_and_deserialize_response(self)
Expand All @@ -46,7 +47,8 @@ impl Instance {
let chorus_request = ChorusRequest {
request: Client::new().get(url.clone()),
limit_type: LimitType::Global,
};
}
.with_client_properties(&self.default_client_properties);

chorus_request
.send_anonymous_and_deserialize_response(self)
Expand Down
3 changes: 2 additions & 1 deletion src/api/policies/instance/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ impl Instance {
let chorus_request = ChorusRequest {
request: self.client.get(&url),
limit_type: LimitType::Global,
};
}
.with_client_properties(&self.default_client_properties);

chorus_request
.send_anonymous_and_deserialize_response(self)
Expand Down
12 changes: 12 additions & 0 deletions src/gateway/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ use pubserve::Publisher;
use super::*;
use crate::types;

/// Subscribable events the [Gateway] emits.
///
/// Most of these are received via a websocket connection.
///
/// Receiving a [GatewayError] from `error` means the connection was closed.
#[derive(Default, Debug, Clone)]
pub struct Events {
pub application: Application,
Expand All @@ -31,6 +36,13 @@ pub struct Events {
pub error: Publisher<GatewayError>,
}

impl Events {
/// Returns a new [Events] struct with no subscribed observers
pub fn empty() -> Events {
Events::default()
}
}

#[derive(Default, Debug, Clone)]
pub struct Application {
pub command_permissions_update: Publisher<types::ApplicationCommandPermissionsUpdate>,
Expand Down
Loading