Compare commits
8 Commits
f0dbd3410f
...
411db01786
Author | SHA1 | Date |
---|---|---|
bitfl0wer | 411db01786 | |
Flori | 76186a08f0 | |
bitfl0wer | d846ce9948 | |
bitfl0wer | e316372631 | |
bitfl0wer | 72c5d13eaf | |
bitfl0wer | 05b9f1c801 | |
Flori | 9926f8ab94 | |
Flori | 5bee907733 |
|
@ -83,7 +83,7 @@ checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.76",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -215,9 +215,9 @@ checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50"
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.1.13"
|
||||
version = "1.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48"
|
||||
checksum = "50d2eb3cd3d1bf4529e31c215ee6f93ec5a3d536d9f578f93d9d33ee19562932"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
|
@ -286,7 +286,7 @@ version = "0.5.0"
|
|||
dependencies = [
|
||||
"async-trait",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.76",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -457,7 +457,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.76",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -468,7 +468,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
|
|||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.76",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -584,15 +584,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.1.0"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
|
||||
checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.32"
|
||||
version = "1.0.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c0596c1eac1f9e04ed902702e9878208b336edc9d6fddc8a48387349bab3666"
|
||||
checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide 0.8.0",
|
||||
|
@ -691,7 +691,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.76",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1601,7 +1601,7 @@ dependencies = [
|
|||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.76",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1659,9 +1659,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.36"
|
||||
version = "1.0.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
||||
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
@ -2004,9 +2004,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.208"
|
||||
version = "1.0.209"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2"
|
||||
checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
@ -2024,20 +2024,20 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.208"
|
||||
version = "1.0.209"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf"
|
||||
checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.76",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.125"
|
||||
version = "1.0.127"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed"
|
||||
checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
|
@ -2053,7 +2053,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.76",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2095,7 +2095,7 @@ dependencies = [
|
|||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.76",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2289,7 +2289,7 @@ dependencies = [
|
|||
"quote",
|
||||
"sqlx-core",
|
||||
"sqlx-macros-core",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.76",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2312,7 +2312,7 @@ dependencies = [
|
|||
"sqlx-mysql",
|
||||
"sqlx-postgres",
|
||||
"sqlx-sqlite",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.76",
|
||||
"tempfile",
|
||||
"tokio",
|
||||
"url",
|
||||
|
@ -2382,7 +2382,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "0ae3447aced07f8bc71d73dc8dd1c6d25c2f4d10ea62a22ceabc12af8410d7e2"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.76",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2487,9 +2487,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.75"
|
||||
version = "2.0.76"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9"
|
||||
checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -2562,7 +2562,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.76",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2635,7 +2635,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.76",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2730,7 +2730,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.76",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2929,7 +2929,7 @@ dependencies = [
|
|||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.76",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
|
@ -2963,7 +2963,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.76",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
@ -2997,7 +2997,7 @@ checksum = "4b8220be1fa9e4c889b30fd207d4906657e7e90b12e0e6b0c8b8d8709f5de021"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.76",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3299,7 +3299,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.75",
|
||||
"syn 2.0.76",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
10
Cargo.toml
10
Cargo.toml
|
@ -23,9 +23,9 @@ voice_gateway = []
|
|||
sqlx-pg-uint = ["dep:sqlx-pg-uint", "sqlx-pg-uint/serde"]
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1.38.1", features = ["macros", "sync"] }
|
||||
serde = { version = "1.0.208", features = ["derive", "rc"] }
|
||||
serde_json = { version = "1.0.120", features = ["raw_value"] }
|
||||
tokio = { version = "1.39.3", features = ["macros", "sync"] }
|
||||
serde = { version = "1.0.209", features = ["derive", "rc"] }
|
||||
serde_json = { version = "1.0.127", features = ["raw_value"] }
|
||||
serde-aux = "4.5.0"
|
||||
serde_with = "3.9.0"
|
||||
serde_repr = "0.1.19"
|
||||
|
@ -36,7 +36,7 @@ reqwest = { features = [
|
|||
], version = "=0.11.26", default-features = false }
|
||||
url = "2.5.2"
|
||||
chrono = { version = "0.4.38", features = ["serde"] }
|
||||
regex = "1.10.5"
|
||||
regex = "1.10.6"
|
||||
custom_error = "1.9.2"
|
||||
futures-util = "0.3.30"
|
||||
http = "0.2.12"
|
||||
|
@ -64,7 +64,7 @@ discortp = { version = "0.5.0", optional = true, features = [
|
|||
] }
|
||||
crypto_secretbox = { version = "0.1.1", optional = true }
|
||||
rand = "0.8.5"
|
||||
flate2 = { version = "1.0.30", optional = true }
|
||||
flate2 = { version = "1.0.33", optional = true }
|
||||
webpki-roots = "0.26.3"
|
||||
pubserve = { version = "1.1.0", features = ["async", "send"] }
|
||||
sqlx-pg-uint = { version = "0.5.0", features = ["serde"], optional = true }
|
||||
|
|
130
README.md
130
README.md
|
@ -28,14 +28,15 @@
|
|||
|
||||
</div>
|
||||
|
||||
Chorus is a Rust library which poses as an API wrapper for [Spacebar Chat](https://github.com/spacebarchat/)
|
||||
and Discord. It is designed to be easy to use, and to be compatible with both Discord and Spacebar Chat.
|
||||
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
|
||||
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 a user-centric Spacebar library into one package.
|
||||
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
|
||||
a WebSocket connection to the Gateway. This means that you can focus on building your application,
|
||||
instead of worrying about the underlying implementation details.
|
||||
|
@ -44,19 +45,19 @@ To get started with Chorus, import it into your project by adding the following
|
|||
|
||||
```toml
|
||||
[dependencies]
|
||||
chorus = "0.15.0"
|
||||
chorus = "0.16.0"
|
||||
```
|
||||
|
||||
### 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:
|
||||
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:
|
||||
|
||||
```rs
|
||||
use chorus::instance::Instance;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let instance = Instance::new("https://example.com")
|
||||
let instance = Instance::new("https://example.com", None)
|
||||
.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.
|
||||
|
@ -81,7 +82,7 @@ let login_schema = LoginSchema {
|
|||
password: "Correct-Horse-Battery-Staple".to_string(),
|
||||
..Default::default()
|
||||
};
|
||||
// Each user connects to the Gateway. The Gateway connection lives on a separate thread. Depending on
|
||||
// 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.
|
||||
let user = instance
|
||||
.login_account(login_schema)
|
||||
|
@ -148,98 +149,23 @@ This crate uses Semantic Versioning 2.0.0 as its versioning scheme. You can read
|
|||
|
||||
See [CONTRIBUTING.md](./CONTRIBUTING.md).
|
||||
|
||||
<details>
|
||||
<summary>Progress Tracker/Roadmap</summary>
|
||||
|
||||
### Core Functionality
|
||||
- [x] Rate Limiter (hint: couldn't be fully tested due to [an Issue with the Spacebar Server](https://github.com/spacebarchat/server/issues/1022))
|
||||
- [x] [Login (the conventional way)](https://github.com/polyphony-chat/chorus/issues/1)
|
||||
- [ ] [2FA](https://github.com/polyphony-chat/chorus/issues/40)
|
||||
- [x] [Registration](https://github.com/polyphony-chat/chorus/issues/1)
|
||||
|
||||
### Messaging
|
||||
- [x] [Sending messages](https://github.com/polyphony-chat/chorus/issues/23)
|
||||
- [x] [Events (Message, User, Channel, etc.)](https://github.com/polyphony-chat/chorus/issues/51)
|
||||
- [x] Channel creation
|
||||
- [x] Channel deletion
|
||||
- [x] [Channel management (name, description, icon, etc.)](https://github.com/polyphony-chat/chorus/issues/48)
|
||||
- [x] [Join and Leave Guilds](https://github.com/polyphony-chat/chorus/issues/45)
|
||||
- [x] [Start DMs](https://github.com/polyphony-chat/chorus/issues/45)
|
||||
- [x] [Group DM creation, deletion and member management](https://github.com/polyphony-chat/chorus/issues/89)
|
||||
- [ ] [Deleting messages](https://github.com/polyphony-chat/chorus/issues/91)
|
||||
- [ ] [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>
|
||||
[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
|
||||
|
|
|
@ -52,7 +52,7 @@ impl Subscriber<GatewayReady> for ExampleObserver {
|
|||
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
async fn main() {
|
||||
let gateway_websocket_url = GATEWAY_URL.to_string();
|
||||
let gateway_websocket_url = GATEWAY_URL;
|
||||
|
||||
// These options specify the encoding format, compression, etc
|
||||
//
|
||||
|
|
|
@ -25,8 +25,8 @@ use wasmtimer::tokio::sleep;
|
|||
/// This example creates a simple gateway connection and a session with an Identify event
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
async fn main() {
|
||||
let gateway_websocket_url = GATEWAY_URL.to_string();
|
||||
|
||||
let gateway_websocket_url = GATEWAY_URL;
|
||||
|
||||
// These options specify the encoding format, compression, etc
|
||||
//
|
||||
// For most cases the defaults should work, though some implementations
|
||||
|
@ -34,7 +34,9 @@ async fn main() {
|
|||
let options = GatewayOptions::default();
|
||||
|
||||
// Initiate the gateway connection, starting a listener in one thread and a heartbeat handler in another
|
||||
let gateway = Gateway::spawn(gateway_websocket_url, options).await.unwrap();
|
||||
let gateway = Gateway::spawn(gateway_websocket_url, options)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// At this point, we are connected to the server and are sending heartbeats, however we still haven't authenticated
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ use chorus::instance::Instance;
|
|||
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
async fn main() {
|
||||
let instance = Instance::new("https://example.com/")
|
||||
let instance = Instance::new("https://example.com/", None)
|
||||
.await
|
||||
.expect("Failed to connect to the Spacebar server");
|
||||
dbg!(instance.instance_info);
|
||||
|
|
|
@ -7,7 +7,7 @@ use chorus::types::LoginSchema;
|
|||
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
async fn main() {
|
||||
let mut instance = Instance::new("https://example.com/")
|
||||
let mut instance = Instance::new("https://example.com/", None)
|
||||
.await
|
||||
.expect("Failed to connect to the Spacebar server");
|
||||
// Assume, you already have an account created on this instance. Registering an account works
|
||||
|
|
|
@ -30,13 +30,12 @@ impl Instance {
|
|||
// 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
|
||||
// instances' limits to pass them on as user_rate_limits later.
|
||||
let mut user =
|
||||
ChorusUser::shell(Arc::new(RwLock::new(self.clone())), "None".to_string()).await;
|
||||
|
||||
let mut user = ChorusUser::shell(Arc::new(RwLock::new(self.clone())), "None").await;
|
||||
|
||||
let login_result = chorus_request
|
||||
.deserialize_response::<LoginResult>(&mut user)
|
||||
.await?;
|
||||
user.set_token(login_result.token);
|
||||
user.set_token(&login_result.token);
|
||||
user.settings = login_result.settings;
|
||||
|
||||
let object = User::get(&mut user, None).await?;
|
||||
|
|
|
@ -22,9 +22,8 @@ pub mod register;
|
|||
|
||||
impl Instance {
|
||||
/// Logs into an existing account on the spacebar server, using only a token.
|
||||
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;
|
||||
pub async fn login_with_token(&mut self, token: &str) -> ChorusResult<ChorusUser> {
|
||||
let mut user = ChorusUser::shell(Arc::new(RwLock::new(self.clone())), token).await;
|
||||
|
||||
let object = User::get(&mut user, None).await?;
|
||||
let settings = User::get_settings(&mut user).await?;
|
||||
|
|
|
@ -37,14 +37,13 @@ impl Instance {
|
|||
// 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
|
||||
// the instances' limits to pass them on as user_rate_limits later.
|
||||
let mut user =
|
||||
ChorusUser::shell(Arc::new(RwLock::new(self.clone())), "None".to_string()).await;
|
||||
|
||||
let mut user = ChorusUser::shell(Arc::new(RwLock::new(self.clone())), "None").await;
|
||||
|
||||
let token = chorus_request
|
||||
.deserialize_response::<Token>(&mut user)
|
||||
.await?
|
||||
.token;
|
||||
user.set_token(token);
|
||||
user.set_token(&token);
|
||||
|
||||
let object = User::get(&mut user, None).await?;
|
||||
let settings = User::get_settings(&mut user).await?;
|
||||
|
|
|
@ -112,7 +112,7 @@ impl Message {
|
|||
let result = request.send_request(user).await?;
|
||||
let result_json = result.json::<Value>().await.unwrap();
|
||||
if !result_json.is_object() {
|
||||
return Err(search_error(result_json.to_string()));
|
||||
return Err(search_error(result_json.to_string().as_str()));
|
||||
}
|
||||
let value_map = result_json.as_object().unwrap();
|
||||
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
|
||||
if !value_map.contains_key("code") || !value_map.contains_key("retry_after") {
|
||||
return Err(search_error(result_json.to_string()));
|
||||
return Err(search_error(result_json.to_string().as_str()));
|
||||
}
|
||||
let code = value_map.get("code").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: String) -> ChorusError {
|
||||
fn search_error(result_text: &str) -> ChorusError {
|
||||
ChorusError::InvalidResponse {
|
||||
error: format!(
|
||||
"Got unexpected Response, or Response which is not valid JSON. Response: \n{}",
|
||||
|
|
|
@ -9,8 +9,10 @@ use futures_util::{
|
|||
};
|
||||
use tokio::net::TcpStream;
|
||||
use tokio_tungstenite::{
|
||||
connect_async_tls_with_config, tungstenite, Connector, MaybeTlsStream, WebSocketStream,
|
||||
connect_async_tls_with_config, connect_async_with_config, tungstenite, Connector,
|
||||
MaybeTlsStream, WebSocketStream,
|
||||
};
|
||||
use url::Url;
|
||||
|
||||
use crate::gateway::{GatewayMessage, RawGatewayMessage};
|
||||
|
||||
|
@ -32,38 +34,60 @@ impl TungsteniteBackend {
|
|||
pub async fn connect(
|
||||
websocket_url: &str,
|
||||
) -> Result<(TungsteniteSink, TungsteniteStream), TungsteniteBackendError> {
|
||||
let certs = webpki_roots::TLS_SERVER_ROOTS;
|
||||
let roots = rustls::RootCertStore {
|
||||
roots: certs
|
||||
.iter()
|
||||
.map(|cert| {
|
||||
rustls::OwnedTrustAnchor::from_subject_spki_name_constraints(
|
||||
cert.subject.to_vec(),
|
||||
cert.subject_public_key_info.to_vec(),
|
||||
cert.name_constraints.as_ref().map(|der| der.to_vec()),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
};
|
||||
let (websocket_stream, _) = match connect_async_tls_with_config(
|
||||
websocket_url,
|
||||
None,
|
||||
false,
|
||||
Some(Connector::Rustls(
|
||||
rustls::ClientConfig::builder()
|
||||
.with_safe_defaults()
|
||||
.with_root_certificates(roots)
|
||||
.with_no_client_auth()
|
||||
.into(),
|
||||
)),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(websocket_stream) => websocket_stream,
|
||||
Err(e) => return Err(TungsteniteBackendError::TungsteniteError { error: e }),
|
||||
};
|
||||
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())
|
||||
Ok(websocket_stream.split())
|
||||
} else if websocket_url_parsed.scheme() == "wss" {
|
||||
let certs = webpki_roots::TLS_SERVER_ROOTS;
|
||||
let roots = rustls::RootCertStore {
|
||||
roots: certs
|
||||
.iter()
|
||||
.map(|cert| {
|
||||
rustls::OwnedTrustAnchor::from_subject_spki_name_constraints(
|
||||
cert.subject.to_vec(),
|
||||
cert.subject_public_key_info.to_vec(),
|
||||
cert.name_constraints.as_ref().map(|der| der.to_vec()),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
};
|
||||
let (websocket_stream, _) = match connect_async_tls_with_config(
|
||||
websocket_url,
|
||||
None,
|
||||
false,
|
||||
Some(Connector::Rustls(
|
||||
rustls::ClientConfig::builder()
|
||||
.with_safe_defaults()
|
||||
.with_root_certificates(roots)
|
||||
.with_no_client_auth()
|
||||
.into(),
|
||||
)),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(websocket_stream) => websocket_stream,
|
||||
Err(e) => return Err(TungsteniteBackendError::TungsteniteError { error: e }),
|
||||
};
|
||||
|
||||
Ok(websocket_stream.split())
|
||||
} else {
|
||||
Err(TungsteniteBackendError::TungsteniteError {
|
||||
error: tungstenite::error::Error::Url(
|
||||
tungstenite::error::UrlError::UnsupportedUrlScheme,
|
||||
),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ impl Gateway {
|
|||
/// # Note
|
||||
/// The websocket url should begin with the prefix wss:// or ws:// (for unsecure connections)
|
||||
pub async fn spawn(
|
||||
websocket_url: String,
|
||||
websocket_url: &str,
|
||||
options: GatewayOptions,
|
||||
) -> Result<GatewayHandle, GatewayError> {
|
||||
let url = options.add_to_url(websocket_url);
|
||||
|
|
|
@ -25,8 +25,8 @@ impl GatewayOptions {
|
|||
/// Adds the options to an existing gateway url
|
||||
///
|
||||
/// Returns the new url
|
||||
pub(crate) fn add_to_url(&self, url: String) -> String {
|
||||
let mut url = url;
|
||||
pub(crate) fn add_to_url(&self, url: &str) -> String {
|
||||
let mut url = url.to_string();
|
||||
|
||||
let mut parameters = Vec::with_capacity(2);
|
||||
|
||||
|
|
|
@ -69,8 +69,13 @@ impl Instance {
|
|||
|
||||
/// 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()`].
|
||||
pub async fn from_url_bundle(urls: UrlBundle) -> ChorusResult<Instance> {
|
||||
pub async fn from_url_bundle(
|
||||
urls: UrlBundle,
|
||||
options: Option<GatewayOptions>,
|
||||
) -> ChorusResult<Instance> {
|
||||
let is_limited: Option<LimitsConfiguration> = Instance::is_limited(&urls.api).await?;
|
||||
let limit_information;
|
||||
|
||||
|
@ -89,7 +94,7 @@ impl Instance {
|
|||
instance_info: GeneralConfiguration::default(),
|
||||
limits_information: limit_information,
|
||||
client: Client::new(),
|
||||
gateway_options: GatewayOptions::default(),
|
||||
gateway_options: options.unwrap_or_default(),
|
||||
};
|
||||
instance.instance_info = match instance.general_configuration_schema().await {
|
||||
Ok(schema) => schema,
|
||||
|
@ -103,14 +108,16 @@ impl Instance {
|
|||
|
||||
/// 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?)`.
|
||||
pub async fn new(root_url: &str) -> ChorusResult<Instance> {
|
||||
pub async fn new(root_url: &str, options: Option<GatewayOptions>) -> ChorusResult<Instance> {
|
||||
let urls = UrlBundle::from_root_url(root_url).await?;
|
||||
Instance::from_url_bundle(urls).await
|
||||
Instance::from_url_bundle(urls, options).await
|
||||
}
|
||||
|
||||
pub async fn is_limited(api_url: &str) -> ChorusResult<Option<LimitsConfiguration>> {
|
||||
let api_url = UrlBundle::parse_url(api_url.to_string());
|
||||
let api_url = UrlBundle::parse_url(api_url);
|
||||
let client = Client::new();
|
||||
let request = client
|
||||
.get(format!("{}/policies/instance/limits", &api_url))
|
||||
|
@ -163,8 +170,8 @@ impl ChorusUser {
|
|||
self.token.clone()
|
||||
}
|
||||
|
||||
pub fn set_token(&mut self, token: String) {
|
||||
self.token = token;
|
||||
pub fn set_token(&mut self, token: &str) {
|
||||
self.token = token.to_string();
|
||||
}
|
||||
|
||||
/// Creates a new [ChorusUser] from existing data.
|
||||
|
@ -195,16 +202,15 @@ impl ChorusUser {
|
|||
/// 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
|
||||
/// first.
|
||||
pub(crate) async fn shell(instance: Shared<Instance>, token: String) -> ChorusUser {
|
||||
pub(crate) async fn shell(instance: Shared<Instance>, token: &str) -> ChorusUser {
|
||||
let settings = Arc::new(RwLock::new(UserSettings::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
|
||||
let gateway = Gateway::spawn(wss_url, GatewayOptions::default())
|
||||
.await
|
||||
.unwrap();
|
||||
let gateway = Gateway::spawn(wss_url, gateway_options).await.unwrap();
|
||||
ChorusUser {
|
||||
token,
|
||||
token: token.to_string(),
|
||||
belongs_to: instance.clone(),
|
||||
limits: instance
|
||||
.read()
|
||||
|
|
88
src/lib.rs
88
src/lib.rs
|
@ -3,27 +3,29 @@
|
|||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
/*!
|
||||
Chorus combines all the required functionalities of a user-centric Spacebar library into one package.
|
||||
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
|
||||
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
|
||||
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:
|
||||
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:
|
||||
|
||||
```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)
|
||||
let instance = Instance::new("https://example.com")
|
||||
.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.
|
||||
|
@ -36,7 +38,7 @@ This Instance can now be used to log in, register and from there on, interact wi
|
|||
|
||||
### 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
|
||||
Logging in correctly provides you with an instance of `ChorusUser`, 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
|
||||
|
@ -48,7 +50,7 @@ let login_schema = LoginSchema {
|
|||
password: "Correct-Horse-Battery-Staple".to_string(),
|
||||
..Default::default()
|
||||
};
|
||||
// Each user connects to the Gateway. The Gateway connection lives on a separate thread. Depending on
|
||||
// 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.
|
||||
let user = instance
|
||||
.login_account(login_schema)
|
||||
|
@ -64,15 +66,33 @@ 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
|
||||
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.
|
||||
To compile for `wasm32-unknown-unknown`, execute the following command:
|
||||
|
||||
```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)
|
||||
|
||||
Rust **1.67.1**. This number might change at any point while Chorus is not yet at version 1.0.0.
|
||||
Rust **1.70.0**. 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`
|
||||
Make sure that you have at least Rust 1.70.0 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`.
|
||||
|
||||
|
@ -86,12 +106,16 @@ like "proxy connection checking" are already disabled on this version, which oth
|
|||
### 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`
|
||||
`wasm-pack test --<chrome/firefox/safari> --headless -- --target wasm32-unknown-unknown --features="rt, client, voice_gateway" --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).
|
||||
|
||||
## Contributing
|
||||
|
||||
See [CONTRIBUTING.md](./CONTRIBUTING.md).
|
||||
!*/
|
||||
#![doc(
|
||||
html_logo_url = "https://raw.githubusercontent.com/polyphony-chat/design/main/branding/polyphony-chorus-round-8bit.png"
|
||||
|
@ -186,7 +210,7 @@ pub struct UrlBundle {
|
|||
|
||||
impl UrlBundle {
|
||||
/// Creates a new UrlBundle from the relevant urls.
|
||||
pub fn new(root: String, api: String, wss: String, cdn: String) -> Self {
|
||||
pub fn new(root: &str, api: &str, wss: &str, cdn: &str) -> Self {
|
||||
Self {
|
||||
root: UrlBundle::parse_url(root),
|
||||
api: UrlBundle::parse_url(api),
|
||||
|
@ -203,17 +227,17 @@ impl UrlBundle {
|
|||
/// let url = parse_url("localhost:3000");
|
||||
/// ```
|
||||
/// `-> Outputs "http://localhost:3000".`
|
||||
pub fn parse_url(url: String) -> String {
|
||||
let url = match Url::parse(&url) {
|
||||
pub fn parse_url(url: &str) -> String {
|
||||
let url = match Url::parse(url) {
|
||||
Ok(url) => {
|
||||
if url.scheme() == "localhost" {
|
||||
return UrlBundle::parse_url(format!("http://{}", url));
|
||||
return UrlBundle::parse_url(&format!("http://{}", url));
|
||||
}
|
||||
url
|
||||
}
|
||||
Err(ParseError::RelativeUrlWithoutBase) => {
|
||||
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
|
||||
};
|
||||
|
@ -236,7 +260,7 @@ impl UrlBundle {
|
|||
/// 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 parsed = UrlBundle::parse_url(url);
|
||||
let client = reqwest::Client::new();
|
||||
let request_wellknown = client
|
||||
.get(format!("{}/.well-known/spacebar", &parsed))
|
||||
|
@ -274,10 +298,10 @@ impl UrlBundle {
|
|||
.await
|
||||
{
|
||||
Ok(UrlBundle::new(
|
||||
url.to_string(),
|
||||
body.api_endpoint,
|
||||
body.gateway,
|
||||
body.cdn,
|
||||
url,
|
||||
&body.api_endpoint,
|
||||
&body.gateway,
|
||||
&body.cdn,
|
||||
))
|
||||
} else {
|
||||
Err(ChorusError::RequestFailed {
|
||||
|
@ -294,13 +318,13 @@ mod lib {
|
|||
|
||||
#[test]
|
||||
fn test_parse_url() {
|
||||
let mut result = UrlBundle::parse_url(String::from("localhost:3000/"));
|
||||
assert_eq!(result, String::from("http://localhost:3000"));
|
||||
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"));
|
||||
let mut result = UrlBundle::parse_url("localhost:3000/");
|
||||
assert_eq!(result, "http://localhost:3000");
|
||||
result = UrlBundle::parse_url("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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,8 +9,8 @@ use jsonwebtoken::{
|
|||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub fn generate_token(id: &Snowflake, email: String, jwt_key: &str) -> String {
|
||||
let claims = Claims::new(&email, id);
|
||||
pub fn generate_token(id: &Snowflake, email: &str, jwt_key: &str) -> String {
|
||||
let claims = Claims::new(email, id);
|
||||
|
||||
build_token(&claims, jwt_key).unwrap()
|
||||
}
|
||||
|
|
|
@ -59,6 +59,12 @@ impl From<u64> for Snowflake {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Snowflake> for u64 {
|
||||
fn from(item: Snowflake) -> Self {
|
||||
item.0
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::Serialize for Snowflake {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
|
|
|
@ -41,7 +41,7 @@ pub struct VoiceGateway {
|
|||
|
||||
impl VoiceGateway {
|
||||
#[allow(clippy::new_ret_no_self)]
|
||||
pub async fn spawn(websocket_url: String) -> Result<VoiceGatewayHandle, VoiceGatewayError> {
|
||||
pub async fn spawn(websocket_url: &str) -> Result<VoiceGatewayHandle, VoiceGatewayError> {
|
||||
// Append the needed things to the websocket url
|
||||
let processed_url = format!("wss://{}/?v=7", websocket_url);
|
||||
trace!("VGW: Connecting to {}", processed_url.clone());
|
||||
|
@ -110,7 +110,7 @@ impl VoiceGateway {
|
|||
});
|
||||
|
||||
Ok(VoiceGatewayHandle {
|
||||
url: websocket_url.clone(),
|
||||
url: websocket_url.to_string(),
|
||||
events: shared_events,
|
||||
websocket_send: shared_websocket_send.clone(),
|
||||
kill_send: kill_send.clone(),
|
||||
|
|
|
@ -72,7 +72,7 @@ impl VoiceGatewayHandle {
|
|||
|
||||
/// Sends a speaking event to the gateway
|
||||
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");
|
||||
|
||||
|
|
|
@ -79,11 +79,7 @@ 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();
|
||||
let other_user = bundle.instance.login_with_token(token).await.unwrap();
|
||||
assert_eq!(
|
||||
bundle.user.object.read().unwrap().id,
|
||||
other_user.object.read().unwrap().id
|
||||
|
@ -98,8 +94,8 @@ async fn test_login_with_token() {
|
|||
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;
|
||||
let token = "invalid token lalalalala";
|
||||
let other_user = bundle.instance.login_with_token(token).await;
|
||||
|
||||
assert!(other_user.is_err());
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ use chorus::{
|
|||
instance::{ChorusUser, Instance},
|
||||
types::{
|
||||
Channel, ChannelCreateSchema, Guild, GuildCreateSchema, RegisterSchema,
|
||||
RoleCreateModifySchema, RoleObject, Shared
|
||||
RoleCreateModifySchema, RoleObject, Shared,
|
||||
},
|
||||
UrlBundle,
|
||||
};
|
||||
|
@ -50,7 +50,7 @@ impl TestBundle {
|
|||
limits: self.user.limits.clone(),
|
||||
settings: self.user.settings.clone(),
|
||||
object: self.user.object.clone(),
|
||||
gateway: Gateway::spawn(self.instance.urls.wss.clone(), GatewayOptions::default())
|
||||
gateway: Gateway::spawn(&self.instance.urls.wss, GatewayOptions::default())
|
||||
.await
|
||||
.unwrap(),
|
||||
}
|
||||
|
@ -59,11 +59,16 @@ impl TestBundle {
|
|||
|
||||
// Set up a test by creating an Instance and a User. Reduces Test boilerplate.
|
||||
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 _ = simple_logger::SimpleLogger::with_level(
|
||||
simple_logger::SimpleLogger::new(),
|
||||
log::LevelFilter::Debug,
|
||||
)
|
||||
.init();
|
||||
|
||||
let instance = Instance::new("http://localhost:3001/api").await.unwrap();
|
||||
let instance = Instance::new("http://localhost:3001/api", None)
|
||||
.await
|
||||
.unwrap();
|
||||
// Requires the existence of the below user.
|
||||
let reg = RegisterSchema {
|
||||
username: "integrationtestuser".into(),
|
||||
|
@ -121,10 +126,10 @@ pub(crate) async fn setup() -> TestBundle {
|
|||
.unwrap();
|
||||
|
||||
let urls = UrlBundle::new(
|
||||
"http://localhost:3001/api".to_string(),
|
||||
"http://localhost:3001/api".to_string(),
|
||||
"ws://localhost:3001/".to_string(),
|
||||
"http://localhost:3001".to_string(),
|
||||
"http://localhost:3001/api",
|
||||
"http://localhost:3001/api",
|
||||
"ws://localhost:3001/",
|
||||
"http://localhost:3001",
|
||||
);
|
||||
TestBundle {
|
||||
urls,
|
||||
|
|
|
@ -31,7 +31,7 @@ use wasmtimer::tokio::sleep;
|
|||
async fn test_gateway_establish() {
|
||||
let bundle = common::setup().await;
|
||||
|
||||
let _: GatewayHandle = Gateway::spawn(bundle.urls.wss.clone(), GatewayOptions::default())
|
||||
let _: GatewayHandle = Gateway::spawn(&bundle.urls.wss, GatewayOptions::default())
|
||||
.await
|
||||
.unwrap();
|
||||
common::teardown(bundle).await
|
||||
|
@ -55,7 +55,7 @@ impl Subscriber<GatewayReady> for GatewayReadyObserver {
|
|||
async fn test_gateway_authenticate() {
|
||||
let bundle = common::setup().await;
|
||||
|
||||
let gateway: GatewayHandle = Gateway::spawn(bundle.urls.wss.clone(), GatewayOptions::default())
|
||||
let gateway: GatewayHandle = Gateway::spawn(&bundle.urls.wss, GatewayOptions::default())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
|
Loading…
Reference in New Issue