Skip to content

Commit

Permalink
Add compatibility features for tokio 0.2 and 1.0 (#1180)
Browse files Browse the repository at this point in the history
This permits one to use `0.10` whilst still depending on tokio `0.2`. They can later migrate to tokio `1.0` once they have the chance. 

Co-authored-by: Ken Swenson <[email protected]>
  • Loading branch information
Lakelezz and Flat authored Jan 9, 2021
1 parent 9a97f9b commit 580d6de
Show file tree
Hide file tree
Showing 14 changed files with 141 additions and 33 deletions.
62 changes: 55 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ features = ["json", "multipart", "stream"]
optional = true
version = "0.11"

# Tokio v0.2
[dependencies.reqwest_compat]
package = "reqwest"
default-features = false
features = ["json", "stream"]
optional = true
version = "0.10"

[dependencies.serenity-voice-model]
path = "./voice-model"
version = "0.1"
Expand All @@ -65,6 +73,14 @@ features = ["tokio-runtime"]
optional = true
version = "0.11"

# Tokio v0.2
[dependencies.async-tungstenite_compat]
package = "async-tungstenite"
default-features = false
features = ["tokio-runtime"]
optional = true
version = "0.9"

[dependencies.typemap_rev]
optional = true
version = "0.1.3"
Expand All @@ -77,11 +93,25 @@ version = "^2.1"
optional = true
version = "1.0"

[dependencies.bytes_compat]
package = "bytes"
optional = true
version = "0.5"

[dependencies.tokio]
version = "1.0"
default-features = false
version = "1"
default-features = true
optional = true
features = ["fs", "macros", "rt", "sync", "time"]

# Tokio v0.2
[dependencies.tokio_compat]
package = "tokio"
version = "0.2"
optional = true
default-features = true
features = ["fs", "macros", "rt-core", "sync", "time", "stream"]

[dependencies.futures]
version = "0.3"
default-features = false
Expand All @@ -95,26 +125,44 @@ version = "0.2"
package = "http"

[features]
default = ["builder", "cache", "client", "framework", "gateway", "model", "http", "standard_framework", "utils", "rustls_backend"]
default_native_tls = ["builder", "cache", "client", "framework", "gateway", "model", "http", "standard_framework", "utils", "native_tls_backend"]
# Defaults with different backends
default = ["default_no_backend", "rustls_backend"]
default_native_tls = ["default_no_backend", "native_tls_backend"]
default_tokio_0_2 = ["default_no_backend", "rustls_tokio_0_2_backend"]
default_native_tls_tokio_0_2 = ["default_no_backend", "native_tls_tokio_0_2_backend"]

# Serenity requires a backend, this picks all default features without a backend.
default_no_backend = ["builder", "cache", "client", "framework", "gateway", "model", "http", "standard_framework", "utils"]

builder = ["utils"]
cache = []
collector = ["gateway", "model"]
client = ["http", "typemap_rev"]
extras = []
framework = ["client", "model", "utils"]
gateway = ["flate2", "http", "url", "utils"]
http = ["url", "bytes"]
http = ["url"]
absolute_ratelimits = ["http"]
rustls_backend = ["reqwest/rustls-tls", "async-tungstenite/tokio-rustls"]
native_tls_backend = ["reqwest/native-tls", "async-tungstenite/tokio-native-tls"]
model = ["builder", "http"]
voice-model = ["serenity-voice-model"]
standard_framework = ["framework", "uwl", "command_attr", "static_assertions"]
unstable_discord_api = []
utils = ["base64"]
voice = ["client", "model"]

# Backends to pick from:
# - Rustls Backends
rustls_backend = ["reqwest/rustls-tls", "async-tungstenite/tokio-rustls", "tokio", "rustls_backend_marker", "bytes"]
rustls_tokio_0_2_backend = ["reqwest_compat/rustls-tls", "async-tungstenite_compat/tokio-rustls", "tokio_compat", "bytes_compat", "rustls_backend_marker"]
# Marks that a Rustls backend is active
rustls_backend_marker = []

# - Native TLS Backends
native_tls_backend = ["reqwest/native-tls", "async-tungstenite/tokio-native-tls", "tokio", "bytes", "native_tls_backend_marker"]
native_tls_tokio_0_2_backend = ["reqwest_compat/native-tls", "async-tungstenite_compat/tokio-native-tls", "tokio_compat", "bytes_compat", "native_tls_backend_marker"]
# Marks that a Native TLS backend is active
native_tls_backend_marker = []

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,15 @@ version = "0.10"
The default features are: `builder`, `cache`, `client`, `framework`, `gateway`,
`http`, `model`, `standard_framework`, `utils`, and `rustls_backend`.

There are these alternative default features, they require to set `default-features = false`:

- **default_tokio_0_2**: Uses the default backend with `tokio` version `0.2`.
- **default_native_tls**: Uses `native_tls_backend` instead of the default `rustls_backend`.
- **default_native_tls_tokio_0_2**: Uses `native_tls_backend` with `tokio` version `0.2`.
- **default_no_backend**: Excludes the default backend, pick your own backend instead.

If you are unsure which to pick, use the default features by not setting `default-features = false`.

The following is a full list of features:

- **builder**: The builders used in conjunction with models' methods.
Expand Down Expand Up @@ -158,6 +167,10 @@ TLS implementation.
- **native_tls_backend**: Uses SChannel on Windows, Secure Transport on macOS,
and OpenSSL on other platforms.

If you need to use `tokio` version `0.2` use the backends below:

- **rustls_tokio_0_2_backend**: Combines **rustls_backend** with `tokio` version `0.2`.
- **native_tls_tokio_0_2_backend**: Combines **native_tls_backend** with `tokio` version `0.2`.

If you want all of the default features except for `cache` for example, you can
list all but that:
Expand Down
2 changes: 1 addition & 1 deletion build.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#[cfg(all(any(feature = "http", feature = "gateway"),
not(any(feature = "rustls_backend", feature = "native_tls_backend"))))]
not(any(feature = "rustls_backend_marker", feature = "native_tls_backend_marker"))))]
compile_error!("You have the `http` or `gateway` feature enabled, \
either the `rustls_backend` or `native_tls_backend` feature must be
selected to let Serenity use `http` or `gateway`.\n\
Expand Down
8 changes: 7 additions & 1 deletion src/client/bridge/gateway/shard_queuer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,13 @@ use futures::{
StreamExt,
channel::mpsc::{UnboundedSender as Sender, UnboundedReceiver as Receiver},
};
use tokio::time::{sleep, timeout, Duration, Instant};
#[cfg(all(feature = "tokio_compat", not(feature = "tokio")))]
use tokio::time::delay_for as sleep;

#[cfg(feature = "tokio")]
use tokio::time::sleep;

use tokio::time::{timeout, Duration, Instant};
use crate::client::{EventHandler, RawEventHandler};
use super::{
GatewayIntents,
Expand Down
7 changes: 6 additions & 1 deletion src/collector/message_collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,13 @@ use tokio::{
UnboundedReceiver as Receiver,
UnboundedSender as Sender,
},
time::{Sleep, sleep},
};
#[cfg(all(feature = "tokio_compat", not(feature = "tokio")))]
use tokio::time::{Delay as Sleep, delay_for as sleep};

#[cfg(feature = "tokio")]
use tokio::time::{Sleep, sleep};

use futures::{
future::BoxFuture,
stream::{Stream, StreamExt},
Expand Down
6 changes: 5 additions & 1 deletion src/collector/reaction_collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use tokio::{
UnboundedReceiver as Receiver,
UnboundedSender as Sender,
},
time::{Sleep, sleep},
};
use futures::{
future::BoxFuture,
Expand All @@ -23,6 +22,11 @@ use crate::{
model::channel::Reaction,
model::id::UserId,
};
#[cfg(all(feature = "tokio_compat", not(feature = "tokio")))]
use tokio::time::{Delay as Sleep, delay_for as sleep};

#[cfg(feature = "tokio")]
use tokio::time::{Sleep, sleep};

macro_rules! impl_reaction_collector {
($($name:ident;)*) => {
Expand Down
10 changes: 5 additions & 5 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::client::ClientError;
use crate::gateway::GatewayError;
#[cfg(feature = "http")]
use crate::http::HttpError;
#[cfg(all(feature = "gateway", feature = "rustls_backend", not(feature = "native_tls_backend")))]
#[cfg(all(feature = "gateway", feature = "rustls_backend_marker", not(feature = "native_tls_backend_marker")))]
use crate::internal::ws_impl::RustlsError;

/// The common result type between most library functions.
Expand Down Expand Up @@ -91,7 +91,7 @@ pub enum Error {
#[cfg(feature = "http")]
Http(Box<HttpError>),
/// An error occuring in rustls
#[cfg(all(feature = "gateway", feature = "rustls_backend", not(feature = "native_tls_backend")))]
#[cfg(all(feature = "gateway", feature = "rustls_backend_marker", not(feature = "native_tls_backend_marker")))]
Rustls(RustlsError),
/// An error from the `tungstenite` crate.
#[cfg(feature = "gateway")]
Expand Down Expand Up @@ -123,7 +123,7 @@ impl From<ModelError> for Error {
fn from(e: ModelError) -> Error { Error::Model(e) }
}

#[cfg(all(feature = "gateway", feature = "rustls_backend", not(feature = "native_tls_backend")))]
#[cfg(all(feature = "gateway", feature = "rustls_backend_marker", not(feature = "native_tls_backend_marker")))]
impl From<RustlsError> for Error {
fn from(e: RustlsError) -> Error { Error::Rustls(e) }
}
Expand Down Expand Up @@ -166,7 +166,7 @@ impl Display for Error {
Error::Gateway(inner) => fmt::Display::fmt(&inner, f),
#[cfg(feature = "http")]
Error::Http(inner) => fmt::Display::fmt(&inner, f),
#[cfg(all(feature = "gateway", not(feature = "native_tls_backend")))]
#[cfg(all(feature = "gateway", not(feature = "native_tls_backend_marker")))]
Error::Rustls(inner) => fmt::Display::fmt(&inner, f),
#[cfg(feature = "gateway")]
Error::Tungstenite(inner) => fmt::Display::fmt(&inner, f),
Expand All @@ -189,7 +189,7 @@ impl StdError for Error {
Error::Gateway(inner) => Some(inner),
#[cfg(feature = "http")]
Error::Http(inner) => Some(inner),
#[cfg(all(feature = "gateway", feature = "rustls_backend", not(feature = "native_tls_backend")))]
#[cfg(all(feature = "gateway", feature = "rustls_backend_marker", not(feature = "native_tls_backend_marker")))]
Error::Rustls(inner) => Some(inner),
#[cfg(feature = "gateway")]
Error::Tungstenite(inner) => Some(inner),
Expand Down
8 changes: 7 additions & 1 deletion src/framework/standard/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ use crate::model::guild::Member;
#[cfg(all(feature = "cache", feature = "http", feature = "model"))]
use crate::model::{guild::Role, id::RoleId};

#[cfg(all(feature = "tokio_compat", not(feature = "tokio")))]
use tokio::time::delay_for as sleep;

#[cfg(feature = "tokio")]
use tokio::time::sleep;

/// An enum representing all possible fail conditions under which a command won't
/// be executed.
#[derive(Debug)]
Expand Down Expand Up @@ -297,7 +303,7 @@ impl StandardFramework {
}

match duration {
Some(duration) => tokio::time::sleep(duration).await,
Some(duration) => sleep(duration).await,
None => break,
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/gateway/shard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ use async_tungstenite::tungstenite::{
use url::Url;
use tracing::{error, debug, info, trace, warn, instrument};

#[cfg(all(feature = "rustls_backend", not(feature = "native_tls_backend")))]
#[cfg(all(feature = "rustls_backend_marker", not(feature = "native_tls_backend_marker")))]
use crate::internal::ws_impl::create_rustls_client;

#[cfg(feature = "native_tls_backend")]
#[cfg(feature = "native_tls_backend_marker")]
use crate::internal::ws_impl::create_native_tls_client;

/// A Shard is a higher-level handler for a websocket connection to Discord's
Expand Down Expand Up @@ -838,14 +838,14 @@ impl Shard {
}
}

#[cfg(all(feature = "rustls_backend", not(feature = "native_tls_backend")))]
#[cfg(all(feature = "rustls_backend_marker", not(feature = "native_tls_backend_marker")))]
async fn connect(base_url: &str) -> Result<WsStream> {
let url = build_gateway_url(base_url)?;

Ok(create_rustls_client(url).await?)
}

#[cfg(feature = "native_tls_backend")]
#[cfg(feature = "native_tls_backend_marker")]
async fn connect(base_url: &str) -> Result<WsStream> {
let url = build_gateway_url(base_url)?;

Expand Down
7 changes: 4 additions & 3 deletions src/http/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ use tokio::{
io::AsyncReadExt,
fs::File,
};

use crate::http::routing::Route;
use percent_encoding::{
utf8_percent_encode,
Expand Down Expand Up @@ -183,7 +184,7 @@ impl Http {

let mut headers = Headers::new();
headers.insert(CONTENT_TYPE, HeaderValue::from_static(&"application/json"));

let response = self.request(Request {
body: Some(&body),
headers: Some(headers),
Expand Down Expand Up @@ -2179,12 +2180,12 @@ impl Http {
}
}

#[cfg(not(feature = "native_tls_backend"))]
#[cfg(not(feature = "native_tls_backend_marker"))]
fn configure_client_backend(builder: ClientBuilder) -> ClientBuilder {
builder.use_rustls_tls()
}

#[cfg(feature = "native_tls_backend")]
#[cfg(feature = "native_tls_backend_marker")]
fn configure_client_backend(builder: ClientBuilder) -> ClientBuilder {
builder.use_native_tls()
}
Expand Down
9 changes: 8 additions & 1 deletion src/http/ratelimiting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,14 @@ use std::{
i64,
f64,
};
use tokio::time::{sleep, Duration};
use tokio::time::{Duration};

#[cfg(all(feature = "tokio_compat", not(feature = "tokio")))]
use tokio::time::delay_for as sleep;

#[cfg(feature = "tokio")]
use tokio::time::sleep;

use super::{HttpError, Request};
use tracing::{debug, instrument};

Expand Down
8 changes: 7 additions & 1 deletion src/http/typing.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
use crate::{error::Result, http::Http};
use std::sync::Arc;
use tokio::{sync::oneshot::{self, Sender, error::TryRecvError}, time::{sleep, Duration}};
use tokio::{sync::oneshot::{self, Sender, error::TryRecvError}, time::Duration};

#[cfg(all(feature = "tokio_compat", not(feature = "tokio")))]
use tokio::time::delay_for as sleep;

#[cfg(feature = "tokio")]
use tokio::time::sleep;

/// A struct to start typing in a [`Channel`] for an indefinite period of time.
///
Expand Down
Loading

0 comments on commit 580d6de

Please sign in to comment.