Compare commits

..

1 Commits

Author SHA1 Message Date
kozabrada123 23b7635a7a
Merge f0dbd3410f into cb3551dcd4 2024-08-25 19:51:15 +00:00
23 changed files with 266 additions and 252 deletions

70
Cargo.lock generated
View File

@ -83,7 +83,7 @@ checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.76", "syn 2.0.75",
] ]
[[package]] [[package]]
@ -215,9 +215,9 @@ checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.1.14" version = "1.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50d2eb3cd3d1bf4529e31c215ee6f93ec5a3d536d9f578f93d9d33ee19562932" checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48"
dependencies = [ dependencies = [
"shlex", "shlex",
] ]
@ -286,7 +286,7 @@ version = "0.5.0"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"quote", "quote",
"syn 2.0.76", "syn 2.0.75",
] ]
[[package]] [[package]]
@ -457,7 +457,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"strsim", "strsim",
"syn 2.0.76", "syn 2.0.75",
] ]
[[package]] [[package]]
@ -468,7 +468,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
dependencies = [ dependencies = [
"darling_core", "darling_core",
"quote", "quote",
"syn 2.0.76", "syn 2.0.75",
] ]
[[package]] [[package]]
@ -584,15 +584,15 @@ dependencies = [
[[package]] [[package]]
name = "fastrand" name = "fastrand"
version = "2.1.1" version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
[[package]] [[package]]
name = "flate2" name = "flate2"
version = "1.0.33" version = "1.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" checksum = "9c0596c1eac1f9e04ed902702e9878208b336edc9d6fddc8a48387349bab3666"
dependencies = [ dependencies = [
"crc32fast", "crc32fast",
"miniz_oxide 0.8.0", "miniz_oxide 0.8.0",
@ -691,7 +691,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.76", "syn 2.0.75",
] ]
[[package]] [[package]]
@ -1601,7 +1601,7 @@ dependencies = [
"proc-macro-crate", "proc-macro-crate",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.76", "syn 2.0.75",
] ]
[[package]] [[package]]
@ -1659,9 +1659,9 @@ dependencies = [
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.37" version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@ -2004,9 +2004,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.209" version = "1.0.208"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
@ -2024,20 +2024,20 @@ dependencies = [
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.209" version = "1.0.208"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.76", "syn 2.0.75",
] ]
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.127" version = "1.0.125"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed"
dependencies = [ dependencies = [
"itoa", "itoa",
"memchr", "memchr",
@ -2053,7 +2053,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.76", "syn 2.0.75",
] ]
[[package]] [[package]]
@ -2095,7 +2095,7 @@ dependencies = [
"darling", "darling",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.76", "syn 2.0.75",
] ]
[[package]] [[package]]
@ -2289,7 +2289,7 @@ dependencies = [
"quote", "quote",
"sqlx-core", "sqlx-core",
"sqlx-macros-core", "sqlx-macros-core",
"syn 2.0.76", "syn 2.0.75",
] ]
[[package]] [[package]]
@ -2312,7 +2312,7 @@ dependencies = [
"sqlx-mysql", "sqlx-mysql",
"sqlx-postgres", "sqlx-postgres",
"sqlx-sqlite", "sqlx-sqlite",
"syn 2.0.76", "syn 2.0.75",
"tempfile", "tempfile",
"tokio", "tokio",
"url", "url",
@ -2382,7 +2382,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ae3447aced07f8bc71d73dc8dd1c6d25c2f4d10ea62a22ceabc12af8410d7e2" checksum = "0ae3447aced07f8bc71d73dc8dd1c6d25c2f4d10ea62a22ceabc12af8410d7e2"
dependencies = [ dependencies = [
"quote", "quote",
"syn 2.0.76", "syn 2.0.75",
] ]
[[package]] [[package]]
@ -2487,9 +2487,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.76" version = "2.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525" checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -2562,7 +2562,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.76", "syn 2.0.75",
] ]
[[package]] [[package]]
@ -2635,7 +2635,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.76", "syn 2.0.75",
] ]
[[package]] [[package]]
@ -2730,7 +2730,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.76", "syn 2.0.75",
] ]
[[package]] [[package]]
@ -2929,7 +2929,7 @@ dependencies = [
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.76", "syn 2.0.75",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -2963,7 +2963,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.76", "syn 2.0.75",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -2997,7 +2997,7 @@ checksum = "4b8220be1fa9e4c889b30fd207d4906657e7e90b12e0e6b0c8b8d8709f5de021"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.76", "syn 2.0.75",
] ]
[[package]] [[package]]
@ -3299,7 +3299,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.76", "syn 2.0.75",
] ]
[[package]] [[package]]

View File

@ -23,9 +23,9 @@ voice_gateway = []
sqlx-pg-uint = ["dep:sqlx-pg-uint", "sqlx-pg-uint/serde"] sqlx-pg-uint = ["dep:sqlx-pg-uint", "sqlx-pg-uint/serde"]
[dependencies] [dependencies]
tokio = { version = "1.39.3", features = ["macros", "sync"] } tokio = { version = "1.38.1", features = ["macros", "sync"] }
serde = { version = "1.0.209", features = ["derive", "rc"] } serde = { version = "1.0.208", features = ["derive", "rc"] }
serde_json = { version = "1.0.127", features = ["raw_value"] } serde_json = { version = "1.0.120", features = ["raw_value"] }
serde-aux = "4.5.0" serde-aux = "4.5.0"
serde_with = "3.9.0" serde_with = "3.9.0"
serde_repr = "0.1.19" serde_repr = "0.1.19"
@ -36,7 +36,7 @@ reqwest = { features = [
], version = "=0.11.26", default-features = false } ], version = "=0.11.26", default-features = false }
url = "2.5.2" url = "2.5.2"
chrono = { version = "0.4.38", features = ["serde"] } chrono = { version = "0.4.38", features = ["serde"] }
regex = "1.10.6" regex = "1.10.5"
custom_error = "1.9.2" custom_error = "1.9.2"
futures-util = "0.3.30" futures-util = "0.3.30"
http = "0.2.12" http = "0.2.12"
@ -64,7 +64,7 @@ discortp = { version = "0.5.0", optional = true, features = [
] } ] }
crypto_secretbox = { version = "0.1.1", optional = true } crypto_secretbox = { version = "0.1.1", optional = true }
rand = "0.8.5" rand = "0.8.5"
flate2 = { version = "1.0.33", optional = true } flate2 = { version = "1.0.30", optional = true }
webpki-roots = "0.26.3" webpki-roots = "0.26.3"
pubserve = { version = "1.1.0", features = ["async", "send"] } pubserve = { version = "1.1.0", features = ["async", "send"] }
sqlx-pg-uint = { version = "0.5.0", features = ["serde"], optional = true } sqlx-pg-uint = { version = "0.5.0", features = ["serde"], optional = true }

130
README.md
View File

@ -28,15 +28,14 @@
</div> </div>
Chorus is a Rust library which poses as an API wrapper for [Spacebar Chat](https://github.com/spacebarchat/), Chorus is a Rust library which poses as an API wrapper for [Spacebar Chat](https://github.com/spacebarchat/)
Discord and our own Polyphony. Its high-level API is designed to be easy to use, while still providing the and Discord. It is designed to be easy to use, and to be compatible with both Discord and Spacebar Chat.
flexibility one would expect from a library like this.
You can establish as many connections to as many servers as you want, and you can use them all at the same time. 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 an API wrapper for chat services into one modular library. 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 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, a WebSocket connection to the Gateway. This means that you can focus on building your application,
instead of worrying about the underlying implementation details. instead of worrying about the underlying implementation details.
@ -45,19 +44,19 @@ To get started with Chorus, import it into your project by adding the following
```toml ```toml
[dependencies] [dependencies]
chorus = "0.16.0" chorus = "0.15.0"
``` ```
### Establishing a Connection ### Establishing a Connection
To connect to a Polyphony/Spacebar compatible server, you'll need to create an [`Instance`](https://docs.rs/chorus/latest/chorus/instance/struct.Instance.html) like this: 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 ```rs
use chorus::instance::Instance; use chorus::instance::Instance;
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
let instance = Instance::new("https://example.com", None) let instance = Instance::new("https://example.com")
.await .await
.expect("Failed to connect to the Spacebar server"); .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. // You can create as many instances of `Instance` as you want, but each `Instance` should likely be unique.
@ -82,7 +81,7 @@ let login_schema = LoginSchema {
password: "Correct-Horse-Battery-Staple".to_string(), password: "Correct-Horse-Battery-Staple".to_string(),
..Default::default() ..Default::default()
}; };
// Each user connects to the Gateway. Each users' Gateway connection lives on a separate thread. Depending on // Each user connects to the Gateway. The 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. // the runtime feature you choose, this can potentially take advantage of all of your computers' threads.
let user = instance let user = instance
.login_account(login_schema) .login_account(login_schema)
@ -149,23 +148,98 @@ This crate uses Semantic Versioning 2.0.0 as its versioning scheme. You can read
See [CONTRIBUTING.md](./CONTRIBUTING.md). See [CONTRIBUTING.md](./CONTRIBUTING.md).
[Rust]: https://img.shields.io/badge/Rust-orange?style=plastic&logo=rust <details>
[Rust-url]: https://www.rust-lang.org/ <summary>Progress Tracker/Roadmap</summary>
[build-shield]: https://img.shields.io/github/actions/workflow/status/polyphony-chat/chorus/build_and_test.yml?style=flat
[build-url]: https://github.com/polyphony-chat/chorus/blob/main/.github/workflows/build_and_test.yml ### Core Functionality
[clippy-shield]: https://img.shields.io/github/actions/workflow/status/polyphony-chat/chorus/clippy.yml?style=flat - [x] Rate Limiter (hint: couldn't be fully tested due to [an Issue with the Spacebar Server](https://github.com/spacebarchat/server/issues/1022))
[clippy-url]: https://github.com/polyphony-chat/chorus/blob/main/.github/workflows/clippy.yml - [x] [Login (the conventional way)](https://github.com/polyphony-chat/chorus/issues/1)
[contributors-shield]: https://img.shields.io/github/contributors/polyphony-chat/chorus.svg?style=flat - [ ] [2FA](https://github.com/polyphony-chat/chorus/issues/40)
[contributors-url]: https://github.com/polyphony-chat/chorus/graphs/contributors - [x] [Registration](https://github.com/polyphony-chat/chorus/issues/1)
[coverage-shield]: https://coveralls.io/repos/github/polyphony-chat/chorus/badge.svg?branch=main
[coverage-url]: https://coveralls.io/github/polyphony-chat/chorus?branch=main ### Messaging
[forks-shield]: https://img.shields.io/github/forks/polyphony-chat/chorus.svg?style=flat - [x] [Sending messages](https://github.com/polyphony-chat/chorus/issues/23)
[forks-url]: https://github.com/polyphony-chat/chorus/network/members - [x] [Events (Message, User, Channel, etc.)](https://github.com/polyphony-chat/chorus/issues/51)
[stars-shield]: https://img.shields.io/github/stars/polyphony-chat/chorus.svg?style=flat - [x] Channel creation
[stars-url]: https://github.com/polyphony-chat/chorus/stargazers - [x] Channel deletion
[issues-shield]: https://img.shields.io/github/issues/polyphony-chat/chorus.svg?style=flat - [x] [Channel management (name, description, icon, etc.)](https://github.com/polyphony-chat/chorus/issues/48)
[issues-url]: https://github.com/polyphony-chat/chorus/issues - [x] [Join and Leave Guilds](https://github.com/polyphony-chat/chorus/issues/45)
[license-shield]: https://img.shields.io/github/license/polyphony-chat/chorus.svg?style=f;at - [x] [Start DMs](https://github.com/polyphony-chat/chorus/issues/45)
[license-url]: https://github.com/polyphony-chat/chorus/blob/master/LICENSE - [x] [Group DM creation, deletion and member management](https://github.com/polyphony-chat/chorus/issues/89)
[Discord]: https://dcbadge.vercel.app/api/server/m3FpcapGDD?style=flat - [ ] [Deleting messages](https://github.com/polyphony-chat/chorus/issues/91)
[Discord-invite]: https://discord.com/invite/m3FpcapGDD - [ ] [Message threads](https://github.com/polyphony-chat/chorus/issues/90)
- [x] [Reactions](https://github.com/polyphony-chat/chorus/issues/85)
- [ ] Message Search
- [ ] Message history
- [ ] Emoji
- [ ] Stickers
- [ ] [Forum channels](https://github.com/polyphony-chat/chorus/issues/90)
### User Management
- [ ] [User profile customization](https://github.com/polyphony-chat/chorus/issues/41)
- [x] Gettings users and user profiles
- [x] [Friend requests](https://github.com/polyphony-chat/chorus/issues/92)
- [x] [Blocking users](https://github.com/polyphony-chat/chorus/issues/92)
- [ ] User presence (online, offline, idle, etc.)
- [ ] User status (custom status, etc.)
- [x] Account deletion
### Additional Features
- [ ] Server discovery
- [ ] Server templates
### Voice and Video
- [ ] [Voice chat support](https://github.com/polyphony-chat/chorus/issues/49)
- [ ] [Video chat support](https://github.com/polyphony-chat/chorus/issues/49)
### Permissions and Roles
- [x] [Role management](https://github.com/polyphony-chat/chorus/issues/46) (creation, deletion, modification)
- [x] [Permission management](https://github.com/polyphony-chat/chorus/issues/46) (assigning and revoking permissions)
- [x] [Channel-specific permissions](https://github.com/polyphony-chat/chorus/issues/88)
- [x] Role-based access control
### Guild Management
- [x] Guild creation
- [x] Guild deletion
- [ ] [Guild settings (name, description, icon, etc.)](https://github.com/polyphony-chat/chorus/issues/43)
- [ ] Guild invites
### Moderation
- [ ] Channel moderation (slow mode, etc.)
- [ ] User sanctions (mute, kick, ban)
- [ ] Audit logs
### Embeds and Rich Content
- [x] Sending rich content in messages (links, images, videos)
- [ ] Customizing embed appearance (title, description, color, fields)
### Webhooks
- [ ] Webhook creation and management
- [ ] Handling incoming webhook events
### Documentation and Examples
- [ ] Comprehensive documentation
- [ ] Example usage and code snippets
- [ ] Tutorials and guides
[Rust]: https://img.shields.io/badge/Rust-orange?style=plastic&logo=rust
[Rust-url]: https://www.rust-lang.org/
[build-shield]: https://img.shields.io/github/actions/workflow/status/polyphony-chat/chorus/build_and_test.yml?style=flat
[build-url]: https://github.com/polyphony-chat/chorus/blob/main/.github/workflows/build_and_test.yml
[clippy-shield]: https://img.shields.io/github/actions/workflow/status/polyphony-chat/chorus/clippy.yml?style=flat
[clippy-url]: https://github.com/polyphony-chat/chorus/blob/main/.github/workflows/clippy.yml
[contributors-shield]: https://img.shields.io/github/contributors/polyphony-chat/chorus.svg?style=flat
[contributors-url]: https://github.com/polyphony-chat/chorus/graphs/contributors
[coverage-shield]: https://coveralls.io/repos/github/polyphony-chat/chorus/badge.svg?branch=main
[coverage-url]: https://coveralls.io/github/polyphony-chat/chorus?branch=main
[forks-shield]: https://img.shields.io/github/forks/polyphony-chat/chorus.svg?style=flat
[forks-url]: https://github.com/polyphony-chat/chorus/network/members
[stars-shield]: https://img.shields.io/github/stars/polyphony-chat/chorus.svg?style=flat
[stars-url]: https://github.com/polyphony-chat/chorus/stargazers
[issues-shield]: https://img.shields.io/github/issues/polyphony-chat/chorus.svg?style=flat
[issues-url]: https://github.com/polyphony-chat/chorus/issues
[license-shield]: https://img.shields.io/github/license/polyphony-chat/chorus.svg?style=f;at
[license-url]: https://github.com/polyphony-chat/chorus/blob/master/LICENSE
[Discord]: https://dcbadge.vercel.app/api/server/m3FpcapGDD?style=flat
[Discord-invite]: https://discord.com/invite/m3FpcapGDD
</details>

View File

@ -52,7 +52,7 @@ impl Subscriber<GatewayReady> for ExampleObserver {
#[tokio::main(flavor = "current_thread")] #[tokio::main(flavor = "current_thread")]
async fn main() { async fn main() {
let gateway_websocket_url = GATEWAY_URL; let gateway_websocket_url = GATEWAY_URL.to_string();
// These options specify the encoding format, compression, etc // These options specify the encoding format, compression, etc
// //

View File

@ -25,7 +25,7 @@ use wasmtimer::tokio::sleep;
/// This example creates a simple gateway connection and a session with an Identify event /// This example creates a simple gateway connection and a session with an Identify event
#[tokio::main(flavor = "current_thread")] #[tokio::main(flavor = "current_thread")]
async fn main() { async fn main() {
let gateway_websocket_url = GATEWAY_URL; let gateway_websocket_url = GATEWAY_URL.to_string();
// These options specify the encoding format, compression, etc // These options specify the encoding format, compression, etc
// //
@ -34,9 +34,7 @@ async fn main() {
let options = GatewayOptions::default(); let options = GatewayOptions::default();
// Initiate the gateway connection, starting a listener in one thread and a heartbeat handler in another // Initiate the gateway connection, starting a listener in one thread and a heartbeat handler in another
let gateway = Gateway::spawn(gateway_websocket_url, options) let gateway = Gateway::spawn(gateway_websocket_url, options).await.unwrap();
.await
.unwrap();
// At this point, we are connected to the server and are sending heartbeats, however we still haven't authenticated // At this point, we are connected to the server and are sending heartbeats, however we still haven't authenticated

View File

@ -6,7 +6,7 @@ use chorus::instance::Instance;
#[tokio::main(flavor = "current_thread")] #[tokio::main(flavor = "current_thread")]
async fn main() { async fn main() {
let instance = Instance::new("https://example.com/", None) let instance = Instance::new("https://example.com/")
.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);

View File

@ -7,7 +7,7 @@ use chorus::types::LoginSchema;
#[tokio::main(flavor = "current_thread")] #[tokio::main(flavor = "current_thread")]
async fn main() { async fn main() {
let mut instance = Instance::new("https://example.com/", None) let mut instance = Instance::new("https://example.com/")
.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

View File

@ -30,12 +30,13 @@ impl Instance {
// We do not have a user yet, and the UserRateLimits will not be affected by a login // 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 // request (since login is an instance wide limit), which is why we are just cloning the
// instances' limits to pass them on as user_rate_limits later. // instances' limits to pass them on as user_rate_limits later.
let mut user = ChorusUser::shell(Arc::new(RwLock::new(self.clone())), "None").await; let mut user =
ChorusUser::shell(Arc::new(RwLock::new(self.clone())), "None".to_string()).await;
let login_result = chorus_request let login_result = chorus_request
.deserialize_response::<LoginResult>(&mut user) .deserialize_response::<LoginResult>(&mut user)
.await?; .await?;
user.set_token(&login_result.token); user.set_token(login_result.token);
user.settings = login_result.settings; user.settings = login_result.settings;
let object = User::get(&mut user, None).await?; let object = User::get(&mut user, None).await?;

View File

@ -22,8 +22,9 @@ pub mod register;
impl Instance { impl Instance {
/// Logs into an existing account on the spacebar server, using only a token. /// Logs into an existing account on the spacebar server, using only a token.
pub async fn login_with_token(&mut self, token: &str) -> ChorusResult<ChorusUser> { pub async fn login_with_token(&mut self, token: String) -> ChorusResult<ChorusUser> {
let mut user = ChorusUser::shell(Arc::new(RwLock::new(self.clone())), token).await; let mut user =
ChorusUser::shell(Arc::new(RwLock::new(self.clone())), token).await;
let object = User::get(&mut user, None).await?; let object = User::get(&mut user, None).await?;
let settings = User::get_settings(&mut user).await?; let settings = User::get_settings(&mut user).await?;

View File

@ -37,13 +37,14 @@ impl Instance {
// We do not have a user yet, and the UserRateLimits will not be affected by a login // 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 // request (since register is an instance wide limit), which is why we are just cloning
// the instances' limits to pass them on as user_rate_limits later. // the instances' limits to pass them on as user_rate_limits later.
let mut user = ChorusUser::shell(Arc::new(RwLock::new(self.clone())), "None").await; let mut user =
ChorusUser::shell(Arc::new(RwLock::new(self.clone())), "None".to_string()).await;
let token = chorus_request let token = chorus_request
.deserialize_response::<Token>(&mut user) .deserialize_response::<Token>(&mut user)
.await? .await?
.token; .token;
user.set_token(&token); user.set_token(token);
let object = User::get(&mut user, None).await?; let object = User::get(&mut user, None).await?;
let settings = User::get_settings(&mut user).await?; let settings = User::get_settings(&mut user).await?;

View File

@ -112,7 +112,7 @@ impl Message {
let result = request.send_request(user).await?; let result = request.send_request(user).await?;
let result_json = result.json::<Value>().await.unwrap(); let result_json = result.json::<Value>().await.unwrap();
if !result_json.is_object() { if !result_json.is_object() {
return Err(search_error(result_json.to_string().as_str())); return Err(search_error(result_json.to_string()));
} }
let value_map = result_json.as_object().unwrap(); let value_map = result_json.as_object().unwrap();
if let Some(messages) = value_map.get("messages") { if let Some(messages) = value_map.get("messages") {
@ -123,7 +123,7 @@ impl Message {
} }
// The code below might be incorrect. We'll cross that bridge when we come to it // The code below might be incorrect. We'll cross that bridge when we come to it
if !value_map.contains_key("code") || !value_map.contains_key("retry_after") { if !value_map.contains_key("code") || !value_map.contains_key("retry_after") {
return Err(search_error(result_json.to_string().as_str())); return Err(search_error(result_json.to_string()));
} }
let code = value_map.get("code").unwrap().as_u64().unwrap(); let code = value_map.get("code").unwrap().as_u64().unwrap();
let retry_after = value_map.get("retry_after").unwrap().as_u64().unwrap(); let retry_after = value_map.get("retry_after").unwrap().as_u64().unwrap();
@ -482,7 +482,7 @@ impl Message {
} }
} }
fn search_error(result_text: &str) -> ChorusError { fn search_error(result_text: String) -> ChorusError {
ChorusError::InvalidResponse { ChorusError::InvalidResponse {
error: format!( error: format!(
"Got unexpected Response, or Response which is not valid JSON. Response: \n{}", "Got unexpected Response, or Response which is not valid JSON. Response: \n{}",

View File

@ -9,10 +9,8 @@ use futures_util::{
}; };
use tokio::net::TcpStream; use tokio::net::TcpStream;
use tokio_tungstenite::{ use tokio_tungstenite::{
connect_async_tls_with_config, connect_async_with_config, tungstenite, Connector, connect_async_tls_with_config, tungstenite, Connector, MaybeTlsStream, WebSocketStream,
MaybeTlsStream, WebSocketStream,
}; };
use url::Url;
use crate::gateway::{GatewayMessage, RawGatewayMessage}; use crate::gateway::{GatewayMessage, RawGatewayMessage};
@ -34,21 +32,6 @@ impl TungsteniteBackend {
pub async fn connect( pub async fn connect(
websocket_url: &str, websocket_url: &str,
) -> Result<(TungsteniteSink, TungsteniteStream), TungsteniteBackendError> { ) -> Result<(TungsteniteSink, TungsteniteStream), TungsteniteBackendError> {
let websocket_url_parsed =
Url::parse(websocket_url).map_err(|_| TungsteniteBackendError::TungsteniteError {
error: tungstenite::error::Error::Url(
tungstenite::error::UrlError::UnsupportedUrlScheme,
),
})?;
if websocket_url_parsed.scheme() == "ws" {
let (websocket_stream, _) =
match connect_async_with_config(websocket_url, None, false).await {
Ok(websocket_stream) => websocket_stream,
Err(e) => return Err(TungsteniteBackendError::TungsteniteError { error: e }),
};
Ok(websocket_stream.split())
} else if websocket_url_parsed.scheme() == "wss" {
let certs = webpki_roots::TLS_SERVER_ROOTS; let certs = webpki_roots::TLS_SERVER_ROOTS;
let roots = rustls::RootCertStore { let roots = rustls::RootCertStore {
roots: certs roots: certs
@ -81,13 +64,6 @@ impl TungsteniteBackend {
}; };
Ok(websocket_stream.split()) Ok(websocket_stream.split())
} else {
Err(TungsteniteBackendError::TungsteniteError {
error: tungstenite::error::Error::Url(
tungstenite::error::UrlError::UnsupportedUrlScheme,
),
})
}
} }
} }

View File

@ -48,7 +48,7 @@ impl Gateway {
/// # Note /// # Note
/// The websocket url should begin with the prefix wss:// or ws:// (for unsecure connections) /// The websocket url should begin with the prefix wss:// or ws:// (for unsecure connections)
pub async fn spawn( pub async fn spawn(
websocket_url: &str, websocket_url: String,
options: GatewayOptions, options: GatewayOptions,
) -> Result<GatewayHandle, GatewayError> { ) -> Result<GatewayHandle, GatewayError> {
let url = options.add_to_url(websocket_url); let url = options.add_to_url(websocket_url);

View File

@ -25,8 +25,8 @@ impl GatewayOptions {
/// Adds the options to an existing gateway url /// Adds the options to an existing gateway url
/// ///
/// Returns the new url /// Returns the new url
pub(crate) fn add_to_url(&self, url: &str) -> String { pub(crate) fn add_to_url(&self, url: String) -> String {
let mut url = url.to_string(); let mut url = url;
let mut parameters = Vec::with_capacity(2); let mut parameters = Vec::with_capacity(2);

View File

@ -69,13 +69,8 @@ impl Instance {
/// Creates a new [`Instance`] from the [relevant instance urls](UrlBundle). /// Creates a new [`Instance`] from the [relevant instance urls](UrlBundle).
/// ///
/// If `options` is `None`, the default [`GatewayOptions`] will be used.
///
/// To create an Instance from one singular url, use [`Instance::new()`]. /// To create an Instance from one singular url, use [`Instance::new()`].
pub async fn from_url_bundle( pub async fn from_url_bundle(urls: UrlBundle) -> ChorusResult<Instance> {
urls: UrlBundle,
options: Option<GatewayOptions>,
) -> ChorusResult<Instance> {
let is_limited: Option<LimitsConfiguration> = Instance::is_limited(&urls.api).await?; let is_limited: Option<LimitsConfiguration> = Instance::is_limited(&urls.api).await?;
let limit_information; let limit_information;
@ -94,7 +89,7 @@ impl Instance {
instance_info: GeneralConfiguration::default(), instance_info: GeneralConfiguration::default(),
limits_information: limit_information, limits_information: limit_information,
client: Client::new(), client: Client::new(),
gateway_options: options.unwrap_or_default(), gateway_options: GatewayOptions::default(),
}; };
instance.instance_info = match instance.general_configuration_schema().await { instance.instance_info = match instance.general_configuration_schema().await {
Ok(schema) => schema, Ok(schema) => schema,
@ -108,16 +103,14 @@ impl Instance {
/// Creates a new [`Instance`] by trying to get the [relevant instance urls](UrlBundle) from a root url. /// Creates a new [`Instance`] by trying to get the [relevant instance urls](UrlBundle) from a root url.
/// ///
/// If `options` is `None`, the default [`GatewayOptions`] will be used.
///
/// Shorthand for `Instance::from_url_bundle(UrlBundle::from_root_domain(root_domain).await?)`. /// Shorthand for `Instance::from_url_bundle(UrlBundle::from_root_domain(root_domain).await?)`.
pub async fn new(root_url: &str, options: Option<GatewayOptions>) -> ChorusResult<Instance> { pub async fn new(root_url: &str) -> ChorusResult<Instance> {
let urls = UrlBundle::from_root_url(root_url).await?; let urls = UrlBundle::from_root_url(root_url).await?;
Instance::from_url_bundle(urls, options).await Instance::from_url_bundle(urls).await
} }
pub async fn is_limited(api_url: &str) -> ChorusResult<Option<LimitsConfiguration>> { pub async fn is_limited(api_url: &str) -> ChorusResult<Option<LimitsConfiguration>> {
let api_url = UrlBundle::parse_url(api_url); let api_url = UrlBundle::parse_url(api_url.to_string());
let client = Client::new(); let client = Client::new();
let request = client let request = client
.get(format!("{}/policies/instance/limits", &api_url)) .get(format!("{}/policies/instance/limits", &api_url))
@ -170,8 +163,8 @@ impl ChorusUser {
self.token.clone() self.token.clone()
} }
pub fn set_token(&mut self, token: &str) { pub fn set_token(&mut self, token: String) {
self.token = token.to_string(); self.token = token;
} }
/// Creates a new [ChorusUser] from existing data. /// Creates a new [ChorusUser] from existing data.
@ -202,15 +195,16 @@ impl ChorusUser {
/// registering or logging in to the Instance, where you do not yet have a User object, but still /// registering or logging in to the Instance, where you do not yet have a User object, but still
/// need to make a RateLimited request. To use the [`GatewayHandle`], you will have to identify /// need to make a RateLimited request. To use the [`GatewayHandle`], you will have to identify
/// first. /// first.
pub(crate) async fn shell(instance: Shared<Instance>, token: &str) -> ChorusUser { pub(crate) async fn shell(instance: Shared<Instance>, token: String) -> ChorusUser {
let settings = Arc::new(RwLock::new(UserSettings::default())); let settings = Arc::new(RwLock::new(UserSettings::default()));
let object = Arc::new(RwLock::new(User::default())); let object = Arc::new(RwLock::new(User::default()));
let wss_url = &instance.read().unwrap().urls.wss.clone(); let wss_url = instance.read().unwrap().urls.wss.clone();
let gateway_options = instance.read().unwrap().gateway_options;
// Dummy gateway object // Dummy gateway object
let gateway = Gateway::spawn(wss_url, gateway_options).await.unwrap(); let gateway = Gateway::spawn(wss_url, GatewayOptions::default())
.await
.unwrap();
ChorusUser { ChorusUser {
token: token.to_string(), token,
belongs_to: instance.clone(), belongs_to: instance.clone(),
limits: instance limits: instance
.read() .read()

View File

@ -3,29 +3,27 @@
// file, You can obtain one at http://mozilla.org/MPL/2.0/. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
/*! /*!
Chorus is a Rust library which poses as an API wrapper for [Spacebar Chat](https://github.com/spacebarchat/), Chorus combines all the required functionalities of a user-centric Spacebar library into one package.
Discord and our own Polyphony. Its high-level API is designed to be easy to use, while still providing the
flexibility one would expect from a library like this.
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 an API wrapper for chat services into one modular library.
The library handles various aspects on your behalf, such as rate limiting, authentication and maintaining 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, a WebSocket connection to the Gateway. This means that you can focus on building your application,
instead of worrying about the underlying implementation details. instead of worrying about the underlying implementation details.
### Establishing a Connection ### Establishing a Connection
To connect to a Polyphony/Spacebar compatible server, you'll need to create an [`Instance`](https://docs.rs/chorus/latest/chorus/instance/struct.Instance.html) like this: 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 ```rs
use chorus::instance::Instance; use chorus::instance::Instance;
use chorus::UrlBundle;
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
let instance = Instance::new("https://example.com") 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)
.await .await
.expect("Failed to connect to the Spacebar server"); .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. // You can create as many instances of `Instance` as you want, but each `Instance` should likely be unique.
@ -38,7 +36,7 @@ This Instance can now be used to log in, register and from there on, interact wi
### Logging In ### Logging In
Logging in correctly provides you with an instance of `ChorusUser`, with which you can interact with the server and 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: manipulate the account. Assuming you already have an account on the server, you can log in like this:
```rs ```rs
@ -50,7 +48,7 @@ let login_schema = LoginSchema {
password: "Correct-Horse-Battery-Staple".to_string(), password: "Correct-Horse-Battery-Staple".to_string(),
..Default::default() ..Default::default()
}; };
// Each user connects to the Gateway. Each users' Gateway connection lives on a separate thread. Depending on // Each user connects to the Gateway. The 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. // the runtime feature you choose, this can potentially take advantage of all of your computers' threads.
let user = instance let user = instance
.login_account(login_schema) .login_account(login_schema)
@ -66,33 +64,15 @@ All major desktop operating systems (Windows, macOS (aarch64/x86_64), Linux (aar
`wasm32-unknown-unknown` is a supported compilation target on versions `0.12.0` and up. This allows you to use `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. Chorus in your browser, or in any other environment that supports WebAssembly.
To compile for `wasm32-unknown-unknown`, execute the following command: We recommend checking out the examples directory, as well as the documentation for more information.
```sh
cargo build --target=wasm32-unknown-unknown --no-default-features
```
The following features are supported on `wasm32-unknown-unknown`:
| Feature | WASM Support |
| ----------------- | ------------ |
| `client` | |
| `rt` | |
| `rt-multi-thread` | |
| `backend` | |
| `voice` | |
| `voice_udp` | |
| `voice_gateway` | |
We recommend checking out the "examples" directory, as well as the documentation for more information.
## MSRV (Minimum Supported Rust Version) ## MSRV (Minimum Supported Rust Version)
Rust **1.70.0**. This number might change at any point while Chorus is not yet at version 1.0.0. Rust **1.67.1**. This number might change at any point while Chorus is not yet at version 1.0.0.
## Development Setup ## Development Setup
Make sure that you have at least Rust 1.70.0 installed. You can check your Rust version by running `cargo --version` 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. 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`. You can do this by running `rustup target add wasm32-unknown-unknown`.
@ -106,16 +86,12 @@ like "proxy connection checking" are already disabled on this version, which oth
### wasm ### wasm
To test for wasm, you will need to `cargo install wasm-pack`. You can then run 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, voice_gateway" --no-default-features` `wasm-pack test --<chrome/firefox/safari> --headless -- --target wasm32-unknown-unknown --features="rt, client" --no-default-features`
to run the tests for wasm. to run the tests for wasm.
## Versioning ## 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). 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).
## Contributing
See [CONTRIBUTING.md](./CONTRIBUTING.md).
!*/ !*/
#![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"
@ -210,7 +186,7 @@ pub struct UrlBundle {
impl UrlBundle { impl UrlBundle {
/// Creates a new UrlBundle from the relevant urls. /// Creates a new UrlBundle from the relevant urls.
pub fn new(root: &str, api: &str, wss: &str, cdn: &str) -> Self { pub fn new(root: String, api: String, wss: String, cdn: String) -> Self {
Self { Self {
root: UrlBundle::parse_url(root), root: UrlBundle::parse_url(root),
api: UrlBundle::parse_url(api), api: UrlBundle::parse_url(api),
@ -227,17 +203,17 @@ impl UrlBundle {
/// let url = parse_url("localhost:3000"); /// let url = parse_url("localhost:3000");
/// ``` /// ```
/// `-> Outputs "http://localhost:3000".` /// `-> Outputs "http://localhost:3000".`
pub fn parse_url(url: &str) -> String { pub fn parse_url(url: String) -> String {
let url = match Url::parse(url) { let url = match Url::parse(&url) {
Ok(url) => { Ok(url) => {
if url.scheme() == "localhost" { if url.scheme() == "localhost" {
return UrlBundle::parse_url(&format!("http://{}", url)); return UrlBundle::parse_url(format!("http://{}", url));
} }
url url
} }
Err(ParseError::RelativeUrlWithoutBase) => { Err(ParseError::RelativeUrlWithoutBase) => {
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"), // TODO: should not panic here Err(_) => panic!("Invalid URL"), // TODO: should not panic here
}; };
@ -260,7 +236,7 @@ impl UrlBundle {
/// of the above approaches fail, it is very likely that the instance is misconfigured, unreachable, or that /// of the above approaches fail, it is very likely that the instance is misconfigured, unreachable, or that
/// a wrong URL was provided. /// a wrong URL was provided.
pub async fn from_root_url(url: &str) -> ChorusResult<UrlBundle> { pub async fn from_root_url(url: &str) -> ChorusResult<UrlBundle> {
let parsed = UrlBundle::parse_url(url); let parsed = UrlBundle::parse_url(url.to_string());
let client = reqwest::Client::new(); let client = reqwest::Client::new();
let request_wellknown = client let request_wellknown = client
.get(format!("{}/.well-known/spacebar", &parsed)) .get(format!("{}/.well-known/spacebar", &parsed))
@ -298,10 +274,10 @@ impl UrlBundle {
.await .await
{ {
Ok(UrlBundle::new( Ok(UrlBundle::new(
url, url.to_string(),
&body.api_endpoint, body.api_endpoint,
&body.gateway, body.gateway,
&body.cdn, body.cdn,
)) ))
} else { } else {
Err(ChorusError::RequestFailed { Err(ChorusError::RequestFailed {
@ -318,13 +294,13 @@ mod lib {
#[test] #[test]
fn test_parse_url() { fn test_parse_url() {
let mut result = UrlBundle::parse_url("localhost:3000/"); let mut result = UrlBundle::parse_url(String::from("localhost:3000/"));
assert_eq!(result, "http://localhost:3000"); assert_eq!(result, String::from("http://localhost:3000"));
result = UrlBundle::parse_url("https://some.url.com/"); result = UrlBundle::parse_url(String::from("https://some.url.com/"));
assert_eq!(result, String::from("https://some.url.com"));
result = UrlBundle::parse_url(String::from("https://some.url.com/"));
assert_eq!(result, String::from("https://some.url.com"));
result = UrlBundle::parse_url(String::from("https://some.url.com"));
assert_eq!(result, String::from("https://some.url.com")); assert_eq!(result, String::from("https://some.url.com"));
result = UrlBundle::parse_url("https://some.url.com/");
assert_eq!(result, "https://some.url.com");
result = UrlBundle::parse_url("https://some.url.com");
assert_eq!(result, "https://some.url.com");
} }
} }

View File

@ -9,8 +9,8 @@ use jsonwebtoken::{
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
pub fn generate_token(id: &Snowflake, email: &str, jwt_key: &str) -> String { pub fn generate_token(id: &Snowflake, email: String, jwt_key: &str) -> String {
let claims = Claims::new(email, id); let claims = Claims::new(&email, id);
build_token(&claims, jwt_key).unwrap() build_token(&claims, jwt_key).unwrap()
} }

View File

@ -59,12 +59,6 @@ impl From<u64> for Snowflake {
} }
} }
impl From<Snowflake> for u64 {
fn from(item: Snowflake) -> Self {
item.0
}
}
impl serde::Serialize for Snowflake { impl serde::Serialize for Snowflake {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where

View File

@ -41,7 +41,7 @@ pub struct VoiceGateway {
impl VoiceGateway { impl VoiceGateway {
#[allow(clippy::new_ret_no_self)] #[allow(clippy::new_ret_no_self)]
pub async fn spawn(websocket_url: &str) -> Result<VoiceGatewayHandle, VoiceGatewayError> { pub async fn spawn(websocket_url: String) -> Result<VoiceGatewayHandle, VoiceGatewayError> {
// Append the needed things to the websocket url // Append the needed things to the websocket url
let processed_url = format!("wss://{}/?v=7", websocket_url); let processed_url = format!("wss://{}/?v=7", websocket_url);
trace!("VGW: Connecting to {}", processed_url.clone()); trace!("VGW: Connecting to {}", processed_url.clone());
@ -110,7 +110,7 @@ impl VoiceGateway {
}); });
Ok(VoiceGatewayHandle { Ok(VoiceGatewayHandle {
url: websocket_url.to_string(), url: websocket_url.clone(),
events: shared_events, events: shared_events,
websocket_send: shared_websocket_send.clone(), websocket_send: shared_websocket_send.clone(),
kill_send: kill_send.clone(), kill_send: kill_send.clone(),

View File

@ -72,7 +72,7 @@ impl VoiceGatewayHandle {
/// Sends a speaking event to the gateway /// Sends a speaking event to the gateway
pub async fn send_speaking(&self, to_send: Speaking) { pub async fn send_speaking(&self, to_send: Speaking) {
let to_send_value = serde_json::to_value(to_send).unwrap(); let to_send_value = serde_json::to_value(&to_send).unwrap();
trace!("VGW: Sending Speaking"); trace!("VGW: Sending Speaking");

View File

@ -79,7 +79,11 @@ async fn test_login_with_token() {
let mut bundle = common::setup().await; let mut bundle = common::setup().await;
let token = &bundle.user.token; let token = &bundle.user.token;
let other_user = bundle.instance.login_with_token(token).await.unwrap(); let other_user = bundle
.instance
.login_with_token(token.clone())
.await
.unwrap();
assert_eq!( assert_eq!(
bundle.user.object.read().unwrap().id, bundle.user.object.read().unwrap().id,
other_user.object.read().unwrap().id other_user.object.read().unwrap().id
@ -94,8 +98,8 @@ async fn test_login_with_token() {
async fn test_login_with_invalid_token() { async fn test_login_with_invalid_token() {
let mut bundle = common::setup().await; let mut bundle = common::setup().await;
let token = "invalid token lalalalala"; let token = "invalid token lalalalala".to_string();
let other_user = bundle.instance.login_with_token(token).await; let other_user = bundle.instance.login_with_token(token.clone()).await;
assert!(other_user.is_err()); assert!(other_user.is_err());

View File

@ -10,7 +10,7 @@ use chorus::{
instance::{ChorusUser, Instance}, instance::{ChorusUser, Instance},
types::{ types::{
Channel, ChannelCreateSchema, Guild, GuildCreateSchema, RegisterSchema, Channel, ChannelCreateSchema, Guild, GuildCreateSchema, RegisterSchema,
RoleCreateModifySchema, RoleObject, Shared, RoleCreateModifySchema, RoleObject, Shared
}, },
UrlBundle, UrlBundle,
}; };
@ -50,7 +50,7 @@ impl TestBundle {
limits: self.user.limits.clone(), limits: self.user.limits.clone(),
settings: self.user.settings.clone(), settings: self.user.settings.clone(),
object: self.user.object.clone(), object: self.user.object.clone(),
gateway: Gateway::spawn(&self.instance.urls.wss, GatewayOptions::default()) gateway: Gateway::spawn(self.instance.urls.wss.clone(), GatewayOptions::default())
.await .await
.unwrap(), .unwrap(),
} }
@ -59,16 +59,11 @@ impl TestBundle {
// Set up a test by creating an Instance and a User. Reduces Test boilerplate. // Set up a test by creating an Instance and a User. Reduces Test boilerplate.
pub(crate) async fn setup() -> TestBundle { pub(crate) async fn setup() -> TestBundle {
// So we can get logs when tests fail
let _ = simple_logger::SimpleLogger::with_level(
simple_logger::SimpleLogger::new(),
log::LevelFilter::Debug,
)
.init();
let instance = Instance::new("http://localhost:3001/api", None) // So we can get logs when tests fail
.await let _ = simple_logger::SimpleLogger::with_level(simple_logger::SimpleLogger::new(), log::LevelFilter::Debug).init();
.unwrap();
let instance = Instance::new("http://localhost:3001/api").await.unwrap();
// Requires the existence of the below user. // Requires the existence of the below user.
let reg = RegisterSchema { let reg = RegisterSchema {
username: "integrationtestuser".into(), username: "integrationtestuser".into(),
@ -126,10 +121,10 @@ pub(crate) async fn setup() -> TestBundle {
.unwrap(); .unwrap();
let urls = UrlBundle::new( let urls = UrlBundle::new(
"http://localhost:3001/api", "http://localhost:3001/api".to_string(),
"http://localhost:3001/api", "http://localhost:3001/api".to_string(),
"ws://localhost:3001/", "ws://localhost:3001/".to_string(),
"http://localhost:3001", "http://localhost:3001".to_string(),
); );
TestBundle { TestBundle {
urls, urls,

View File

@ -31,7 +31,7 @@ use wasmtimer::tokio::sleep;
async fn test_gateway_establish() { async fn test_gateway_establish() {
let bundle = common::setup().await; let bundle = common::setup().await;
let _: GatewayHandle = Gateway::spawn(&bundle.urls.wss, GatewayOptions::default()) let _: GatewayHandle = Gateway::spawn(bundle.urls.wss.clone(), GatewayOptions::default())
.await .await
.unwrap(); .unwrap();
common::teardown(bundle).await common::teardown(bundle).await
@ -55,7 +55,7 @@ impl Subscriber<GatewayReady> for GatewayReadyObserver {
async fn test_gateway_authenticate() { async fn test_gateway_authenticate() {
let bundle = common::setup().await; let bundle = common::setup().await;
let gateway: GatewayHandle = Gateway::spawn(&bundle.urls.wss, GatewayOptions::default()) let gateway: GatewayHandle = Gateway::spawn(bundle.urls.wss.clone(), GatewayOptions::default())
.await .await
.unwrap(); .unwrap();