chore: replace async-std with tokio (#813)

Signed-off-by: Zomatree <me@zomatree.live>
This commit is contained in:
Zomatree
2026-06-24 13:38:20 +01:00
committed by GitHub
parent a15a542f43
commit 01c7d925b0
35 changed files with 703 additions and 1150 deletions

1725
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -23,11 +23,11 @@ async-trait = "0.1.89"
tokio = "1.49.0" tokio = "1.49.0"
async-channel = "2.3.1" async-channel = "2.3.1"
futures = "0.3.32" futures = "0.3.32"
async-std = "1.8.0"
async-tungstenite = "0.17.0" async-tungstenite = "0.17.0"
futures-locks = "0.7.1" futures-locks = "0.7.1"
async-lock = "2.8.0" async-lock = "2.8.0"
async-recursion = "1.0.4" async-recursion = "1.0.4"
tokio-util = { version = "0.7.18" }
# Error Handling # Error Handling
anyhow = "1.0.100" anyhow = "1.0.100"
@@ -89,7 +89,7 @@ log = "0.4.29"
pretty_env_logger = "0.4.0" pretty_env_logger = "0.4.0"
# Redis # Redis
redis-kiss = "0.1.4" redis-kiss = { version = "0.1.4", default-features = false }
fred = "8.0.1" fred = "8.0.1"
# Serialisation # Serialisation
@@ -160,8 +160,8 @@ opentelemetry-appender-tracing = "0.31.1"
lapin = "4.7.1" lapin = "4.7.1"
# Voice # Voice
livekit-api = "0.4.4" livekit-api = "=0.4.23"
livekit-protocol = "0.7.4" livekit-protocol = "=0.7.7"
livekit-runtime = "0.4.0" livekit-runtime = "0.4.0"
# Other Utilities # Other Utilities

View File

@@ -14,7 +14,7 @@ sentry = { workspace = true }
lru = { workspace = true } lru = { workspace = true }
ulid = { workspace = true } ulid = { workspace = true }
once_cell = { workspace = true } once_cell = { workspace = true }
redis-kiss = { workspace = true } redis-kiss = { workspace = true, default-features = false, features = ["tokio-runtime"] }
lru_time_cache = { workspace = true } lru_time_cache = { workspace = true }
async-channel = { workspace = true } async-channel = { workspace = true }
@@ -30,8 +30,9 @@ serde = { workspace = true }
# async # async
futures = { workspace = true } futures = { workspace = true }
async-tungstenite = { workspace = true, features = ["async-std-runtime"] } async-tungstenite = { workspace = true, features = ["tokio-runtime"] }
async-std = { workspace = true } tokio = { workspace = true }
tokio-util = { workspace = true, features = ["compat"] }
# core # core
revolt-result = { workspace = true } revolt-result = { workspace = true }

View File

@@ -2,7 +2,7 @@ use std::{
collections::{HashMap, HashSet}, num::NonZeroUsize, sync::Arc, time::Duration collections::{HashMap, HashSet}, num::NonZeroUsize, sync::Arc, time::Duration
}; };
use async_std::sync::{Mutex, RwLock}; use tokio::sync::{Mutex, RwLock};
use lru::LruCache; use lru::LruCache;
use lru_time_cache::{LruCache as LruTimeCache, TimedEntry}; use lru_time_cache::{LruCache as LruTimeCache, TimedEntry};
use revolt_database::{Channel, Member, Server, User}; use revolt_database::{Channel, Member, Server, User};

View File

@@ -1,6 +1,6 @@
use std::env; use std::env;
use async_std::net::TcpListener; use tokio::net::TcpListener;
use revolt_presence::clear_region; use revolt_presence::clear_region;
#[macro_use] #[macro_use]
@@ -12,7 +12,7 @@ pub mod events;
mod database; mod database;
mod websocket; mod websocket;
#[async_std::main] #[tokio::main]
async fn main() { async fn main() {
// Configure requirements for Bonfire. // Configure requirements for Bonfire.
revolt_config::configure!(events); revolt_config::configure!(events);
@@ -33,7 +33,7 @@ async fn main() {
// Start accepting new connections and spawn a client for each connection. // Start accepting new connections and spawn a client for each connection.
while let Ok((stream, addr)) = listener.accept().await { while let Ok((stream, addr)) = listener.accept().await {
async_std::task::spawn(async move { tokio::task::spawn(async move {
info!("User connected from {addr:?}"); info!("User connected from {addr:?}");
websocket::client(database::get_db(), stream, addr).await; websocket::client(database::get_db(), stream, addr).await;
info!("User disconnected from {addr:?}"); info!("User disconnected from {addr:?}");

View File

@@ -21,11 +21,12 @@ use revolt_database::{
}; };
use revolt_presence::{create_session, delete_session}; use revolt_presence::{create_session, delete_session};
use async_std::{ use tokio::{
net::TcpStream, net::TcpStream,
sync::{Mutex, RwLock}, sync::{Mutex, RwLock},
task::spawn, task::spawn,
}; };
use tokio_util::compat::{TokioAsyncReadCompatExt, Compat};
use revolt_result::create_error; use revolt_result::create_error;
use sentry::Level; use sentry::Level;
@@ -33,8 +34,8 @@ use crate::config::{ProtocolConfiguration, WebsocketHandshakeCallback};
use crate::events::state::{State, SubscriptionStateChange}; use crate::events::state::{State, SubscriptionStateChange};
use revolt_models::v0; use revolt_models::v0;
type WsReader = SplitStream<WebSocketStream<TcpStream>>; type WsReader = SplitStream<WebSocketStream<Compat<TcpStream>>>;
type WsWriter = SplitSink<WebSocketStream<TcpStream>, async_tungstenite::tungstenite::Message>; type WsWriter = SplitSink<WebSocketStream<Compat<TcpStream>>, async_tungstenite::tungstenite::Message>;
/// Start a new WebSocket client worker given access to the database, /// Start a new WebSocket client worker given access to the database,
/// the relevant TCP stream and the remote address of the client. /// the relevant TCP stream and the remote address of the client.
@@ -44,7 +45,7 @@ pub async fn client(db: &'static Database, stream: TcpStream, addr: SocketAddr)
// e.g. wss://example.com?format=json&version=1 // e.g. wss://example.com?format=json&version=1
let (sender, receiver) = oneshot::channel(); let (sender, receiver) = oneshot::channel();
let Ok(ws) = async_tungstenite::accept_hdr_async_with_config( let Ok(ws) = async_tungstenite::accept_hdr_async_with_config(
stream, stream.compat(),
WebsocketHandshakeCallback::from(sender), WebsocketHandshakeCallback::from(sender),
None, None,
) )

View File

@@ -13,7 +13,7 @@ repository = "https://github.com/stoatchat/stoatchat"
anyhow = ["dep:sentry-anyhow"] anyhow = ["dep:sentry-anyhow"]
report-macros = ["revolt-result"] report-macros = ["revolt-result"]
sentry = ["dep:sentry"] sentry = ["dep:sentry"]
test = ["async-std"] test = ["tokio"]
default = ["sentry"] default = ["sentry"]
[dependencies] [dependencies]
@@ -26,7 +26,7 @@ serde = { workspace = true }
# Async # Async
futures-locks = { workspace = true } futures-locks = { workspace = true }
async-std = { workspace = true, features = ["attributes"], optional = true } tokio = { workspace = true, optional = true }
# Logging # Logging
log = { workspace = true } log = { workspace = true }

View File

@@ -586,7 +586,7 @@ macro_rules! configure {
mod tests { mod tests {
use crate::init; use crate::init;
#[async_std::test] #[tokio::test]
async fn it_works() { async fn it_works() {
init().await; init().await;
} }

View File

@@ -15,7 +15,7 @@ mongodb = ["dep:mongodb", "bson"]
# ... Other # ... Other
tasks = ["isahc", "linkify", "url-escape"] tasks = ["isahc", "linkify", "url-escape"]
async-std-runtime = ["async-std"] tokio-runtime = ["tokio"]
rocket-impl = [ rocket-impl = [
"rocket", "rocket",
"schemars", "schemars",
@@ -27,7 +27,7 @@ redis-is-patched = ["revolt-presence/redis-is-patched"]
voice = ["livekit-api", "livekit-protocol", "livekit-runtime"] voice = ["livekit-api", "livekit-protocol", "livekit-runtime"]
# Default Features # Default Features
default = ["mongodb", "async-std-runtime", "tasks"] default = ["mongodb", "tokio-runtime", "tasks"]
[dependencies] [dependencies]
# Core # Core
@@ -64,7 +64,7 @@ serde = { workspace = true }
iso8601-timestamp = { workspace = true, features = ["serde", "bson"] } iso8601-timestamp = { workspace = true, features = ["serde", "bson"] }
# Events # Events
redis-kiss = { workspace = true } redis-kiss = { workspace = true, default-features = false, features = ["tokio-runtime"] }
# Database # Database
bson = { workspace = true, optional = true } bson = { workspace = true, optional = true }
@@ -81,7 +81,7 @@ async-trait = { workspace = true }
async-recursion = { workspace = true } async-recursion = { workspace = true }
# Async # Async
async-std = { workspace = true, features = ["attributes"], optional = true } tokio = { workspace = true, optional = true }
# Axum Impl # Axum Impl
axum = { workspace = true, optional = true } axum = { workspace = true, optional = true }

View File

@@ -25,8 +25,8 @@ pub use mongodb;
#[macro_use] #[macro_use]
extern crate bson; extern crate bson;
#[cfg(not(feature = "async-std-runtime"))] #[cfg(not(feature = "tokio-runtime"))]
compile_error!("async-std-runtime feature must be enabled."); compile_error!("tokio-runtime feature must be enabled.");
#[macro_export] #[macro_export]
#[cfg(debug_assertions)] #[cfg(debug_assertions)]

View File

@@ -11,7 +11,7 @@ auto_derived!(
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
#[async_std::test] #[tokio::test]
async fn migrate() { async fn migrate() {
database_test!(|db| async move { database_test!(|db| async move {
// Initialise the database // Initialise the database

View File

@@ -452,7 +452,7 @@ pub async fn run_migrations(db: &MongoDb, revision: i32) -> i32 {
warn!("This is a destructive operation and will wipe existing permission data (excl. defaults for SendMessage)."); warn!("This is a destructive operation and will wipe existing permission data (excl. defaults for SendMessage).");
warn!("Taking a backup is advised."); warn!("Taking a backup is advised.");
warn!("Continuing in 10 seconds..."); warn!("Continuing in 10 seconds...");
async_std::task::sleep(Duration::from_secs(10)).await; tokio::time::sleep(Duration::from_secs(10)).await;
let servers = db.col::<Document>("servers"); let servers = db.col::<Document>("servers");
let mut cursor = servers.find(doc! {}).await.unwrap(); let mut cursor = servers.find(doc! {}).await.unwrap();

View File

@@ -164,7 +164,7 @@ impl Bot {
mod tests { mod tests {
use crate::{Bot, FieldsBot, PartialBot, User}; use crate::{Bot, FieldsBot, PartialBot, User};
#[async_std::test] #[tokio::test]
async fn crud() { async fn crud() {
database_test!(|db| async move { database_test!(|db| async move {
let owner = User::create(&db, "Owner".to_string(), None, None) let owner = User::create(&db, "Owner".to_string(), None, None)

View File

@@ -128,7 +128,7 @@ impl Webhook {
mod tests { mod tests {
use crate::{FieldsWebhook, PartialWebhook, Webhook}; use crate::{FieldsWebhook, PartialWebhook, Webhook};
#[async_std::test] #[tokio::test]
async fn crud() { async fn crud() {
database_test!(|db| async move { database_test!(|db| async move {
let webhook_id = "webhook"; let webhook_id = "webhook";

View File

@@ -787,7 +787,7 @@ mod tests {
use crate::{fixture, util::permissions::DatabasePermissionQuery}; use crate::{fixture, util::permissions::DatabasePermissionQuery};
#[async_std::test] #[tokio::test]
async fn permissions_group_channel() { async fn permissions_group_channel() {
database_test!(|db| async move { database_test!(|db| async move {
fixture!(db, "group_with_members", fixture!(db, "group_with_members",
@@ -813,7 +813,7 @@ mod tests {
}); });
} }
#[async_std::test] #[tokio::test]
async fn permissions_text_channel() { async fn permissions_text_channel() {
database_test!(|db| async move { database_test!(|db| async move {
fixture!(db, "server_with_roles", fixture!(db, "server_with_roles",

View File

@@ -320,7 +320,7 @@ mod tests {
use crate::{Member, PartialMember, RemovalIntention, Server, User}; use crate::{Member, PartialMember, RemovalIntention, Server, User};
#[async_std::test] #[tokio::test]
async fn muted_member_rejoin() { async fn muted_member_rejoin() {
database_test!(|db| async move { database_test!(|db| async move {
match db { match db {

View File

@@ -420,7 +420,7 @@ mod tests {
use crate::{fixture, util::permissions::DatabasePermissionQuery}; use crate::{fixture, util::permissions::DatabasePermissionQuery};
#[async_std::test] #[tokio::test]
async fn permissions() { async fn permissions() {
database_test!(|db| async move { database_test!(|db| async move {
fixture!(db, "server_with_roles", fixture!(db, "server_with_roles",

View File

@@ -926,7 +926,7 @@ mod tests {
assert!(User::validate_username(username_https).is_err()); assert!(User::validate_username(username_https).is_err());
} }
#[async_std::test] #[tokio::test]
async fn username_sanitisation_clean() { async fn username_sanitisation_clean() {
let username_clean = "Test"; let username_clean = "Test";
@@ -936,7 +936,7 @@ mod tests {
assert_eq!(username_clean, username_clean_sanitised.unwrap()); assert_eq!(username_clean, username_clean_sanitised.unwrap());
} }
#[async_std::test] #[tokio::test]
async fn username_sanitisation_homoglyphs() { async fn username_sanitisation_homoglyphs() {
let username_homoglyphs = "𝔽𝕌Ňℕy"; let username_homoglyphs = "𝔽𝕌Ňℕy";
@@ -947,7 +947,7 @@ mod tests {
assert_eq!("funny", username_homoglyphs_sanitised); assert_eq!("funny", username_homoglyphs_sanitised);
} }
#[async_std::test] #[tokio::test]
async fn username_sanitisation_padding() { async fn username_sanitisation_padding() {
let username_padding = "a"; let username_padding = "a";
@@ -956,7 +956,7 @@ mod tests {
assert_eq!("a_", username); assert_eq!("a_", username);
} }
#[async_std::test] #[tokio::test]
async fn create_user() { async fn create_user() {
use revolt_result::Result; use revolt_result::Result;

View File

@@ -305,6 +305,6 @@ pub async fn worker(db: Database, amqp: AMQP) {
} }
// Sleep for an arbitrary amount of time. // Sleep for an arbitrary amount of time.
async_std::task::sleep(Duration::from_secs(1)).await; tokio::time::sleep(Duration::from_secs(1)).await;
} }
} }

View File

@@ -82,6 +82,6 @@ pub async fn worker(db: Database) {
} }
// Sleep for an arbitrary amount of time. // Sleep for an arbitrary amount of time.
async_std::task::sleep(Duration::from_secs(1)).await; tokio::time::sleep(Duration::from_secs(1)).await;
} }
} }

View File

@@ -2,7 +2,7 @@
use crate::{Database, AMQP}; use crate::{Database, AMQP};
use async_std::task; use tokio::task;
use std::time::Instant; use std::time::Instant;
const WORKER_COUNT: usize = 5; const WORKER_COUNT: usize = 5;

View File

@@ -7,11 +7,11 @@ use revolt_config::config;
use revolt_result::Result; use revolt_result::Result;
use async_lock::Semaphore; use async_lock::Semaphore;
use async_std::task::spawn;
use deadqueue::limited::Queue; use deadqueue::limited::Queue;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use revolt_models::v0::Embed; use revolt_models::v0::Embed;
use std::{collections::HashSet, sync::Arc}; use std::{collections::HashSet, sync::Arc};
use tokio::task::spawn;
use isahc::prelude::*; use isahc::prelude::*;
@@ -159,6 +159,7 @@ pub async fn generate(
.await .await
.into_iter() .into_iter()
.flatten() .flatten()
.flatten()
.collect::<Vec<Embed>>(); .collect::<Vec<Embed>>();
// Prevent database update when no embeds are found. // Prevent database update when no embeds are found.

View File

@@ -5,7 +5,7 @@ use revolt_result::{create_error, Result};
#[cfg(feature = "rocket-impl")] #[cfg(feature = "rocket-impl")]
use revolt_result::Error; use revolt_result::Error;
use async_std::sync::Mutex; use tokio::sync::Mutex;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};

View File

@@ -18,7 +18,7 @@ try-from-primitive = ["dep:num_enum"]
[dev-dependencies] [dev-dependencies]
# Async # Async
async-std = { workspace = true, features = ["attributes"] } tokio = { workspace = true }
[dependencies] [dependencies]
# Core # Core

View File

@@ -4,7 +4,7 @@ use crate::{
DEFAULT_PERMISSION_SERVER, DEFAULT_PERMISSION_VIEW_ONLY, DEFAULT_PERMISSION_SERVER, DEFAULT_PERMISSION_VIEW_ONLY,
}; };
#[async_std::test] #[tokio::test]
async fn validate_user_permissions() { async fn validate_user_permissions() {
/// Scenario in which we are friends with a user /// Scenario in which we are friends with a user
/// and we have a DM channel open with them /// and we have a DM channel open with them
@@ -102,7 +102,7 @@ async fn validate_user_permissions() {
} }
} }
#[async_std::test] #[tokio::test]
async fn validate_group_permissions() { async fn validate_group_permissions() {
/// Scenario in which we are in a group channel with only talking permission /// Scenario in which we are in a group channel with only talking permission
struct Scenario {} struct Scenario {}
@@ -202,7 +202,7 @@ async fn validate_group_permissions() {
} }
} }
#[async_std::test] #[tokio::test]
async fn validate_server_permissions() { async fn validate_server_permissions() {
/// Scenario in which we are in a server channel where: /// Scenario in which we are in a server channel where:
/// - the server grants reading history and sending messages by default /// - the server grants reading history and sending messages by default
@@ -314,7 +314,7 @@ async fn validate_server_permissions() {
} }
} }
#[async_std::test] #[tokio::test]
async fn validate_timed_out_member() { async fn validate_timed_out_member() {
/// Scenario in which we are in a server that we have been timed out from /// Scenario in which we are in a server that we have been timed out from
struct Scenario {} struct Scenario {}

View File

@@ -14,7 +14,7 @@ redis-is-patched = []
[dev-dependencies] [dev-dependencies]
# Async # Async
async-std = { workspace = true, features = ["attributes"] } tokio = { workspace = true }
# Config for loading Redis URI # Config for loading Redis URI
revolt-config = { workspace = true } revolt-config = { workspace = true }
@@ -26,4 +26,4 @@ rand = { workspace = true }
once_cell = { workspace = true } once_cell = { workspace = true }
# Redis # Redis
redis-kiss = { workspace = true } redis-kiss = { workspace = true, default-features = false, features = ["tokio-runtime"] }

View File

@@ -195,7 +195,7 @@ mod tests {
use crate::{clear_region, create_session, delete_session, filter_online, is_online}; use crate::{clear_region, create_session, delete_session, filter_online, is_online};
use rand::Rng; use rand::Rng;
#[async_std::test] #[tokio::test]
async fn it_works() { async fn it_works() {
revolt_config::config().await; revolt_config::config().await;

View File

@@ -18,7 +18,7 @@ tokio = { workspace = true }
futures = { workspace = true } futures = { workspace = true }
# Redis # Redis
redis-kiss = { workspace = true } redis-kiss = { workspace = true, default-features = false, features = ["tokio-runtime"] }
# RabbitMQ # RabbitMQ
lapin = { workspace = true } lapin = { workspace = true }

View File

@@ -20,7 +20,7 @@ fcm_v1 = { workspace = true }
web-push = { workspace = true } web-push = { workspace = true }
isahc = { workspace = true, features = ["json"], optional = true } isahc = { workspace = true, features = ["json"], optional = true }
revolt_a2 = { workspace = true, features = ["ring"] } revolt_a2 = { workspace = true, features = ["ring"] }
redis-kiss = { workspace = true } redis-kiss = { workspace = true, default-features = false, features = ["tokio-runtime"] }
tokio = { workspace = true } tokio = { workspace = true }
async-trait = { workspace = true } async-trait = { workspace = true }
ulid = { workspace = true } ulid = { workspace = true }

View File

@@ -13,7 +13,7 @@ log = { workspace = true }
sentry = { workspace = true } sentry = { workspace = true }
lru = { workspace = true } lru = { workspace = true }
ulid = { workspace = true } ulid = { workspace = true }
redis-kiss = { workspace = true } redis-kiss = { workspace = true, default-features = false, features = ["tokio-runtime"] }
chrono = { workspace = true } chrono = { workspace = true }
# Serde # Serde
@@ -27,11 +27,6 @@ rocket_empty = { workspace = true }
# Async # Async
futures = { workspace = true } futures = { workspace = true }
async-std = { workspace = true, features = [
"tokio1",
"tokio02",
"attributes",
] }
# Core # Core
revolt-result = { workspace = true, features = ["rocket"] } revolt-result = { workspace = true, features = ["rocket"] }

View File

@@ -11,7 +11,7 @@ publish = false
[dependencies] [dependencies]
# Test # Test
rand = { workspace = true } rand = { workspace = true }
redis-kiss = { workspace = true } redis-kiss = { workspace = true, default-features = false, features = ["tokio-runtime"] }
# Utility # Utility
lru = { workspace = true } lru = { workspace = true }
@@ -42,11 +42,7 @@ futures = { workspace = true }
chrono = { workspace = true } chrono = { workspace = true }
async-channel = { workspace = true } async-channel = { workspace = true }
reqwest = { workspace = true, features = ["json"] } reqwest = { workspace = true, features = ["json"] }
async-std = { workspace = true, features = [ tokio = { workspace = true }
"tokio1",
"tokio02",
"attributes",
] }
# internal util # internal util
lettre = { workspace = true } lettre = { workspace = true }

View File

@@ -2,7 +2,7 @@
//! POST /account/create //! POST /account/create
use std::time::Duration; use std::time::Duration;
use async_std::task::sleep; use tokio::time::sleep;
use revolt_config::config; use revolt_config::config;
use revolt_database::{ use revolt_database::{
util::{ util::{

View File

@@ -2,7 +2,7 @@
//! POST /account/reverify //! POST /account/reverify
use std::time::Duration; use std::time::Duration;
use async_std::task::sleep; use tokio::time::sleep;
use rocket::{serde::json::Json, State}; use rocket::{serde::json::Json, State};
use rocket_empty::EmptyResponse; use rocket_empty::EmptyResponse;
use revolt_result::Result; use revolt_result::Result;

View File

@@ -2,7 +2,7 @@
//! POST /account/reset_password //! POST /account/reset_password
use std::time::Duration; use std::time::Duration;
use async_std::task::sleep; use tokio::time::sleep;
use rocket::serde::json::Json; use rocket::serde::json::Json;
use rocket::State; use rocket::State;
use rocket_empty::EmptyResponse; use rocket_empty::EmptyResponse;

View File

@@ -3,7 +3,7 @@
use std::ops::Add; use std::ops::Add;
use std::time::Duration; use std::time::Duration;
use async_std::task::sleep; use tokio::time::sleep;
use iso8601_timestamp::Timestamp; use iso8601_timestamp::Timestamp;
use revolt_database::{ use revolt_database::{
util::{email::normalise_email, password::assert_safe}, util::{email::normalise_email, password::assert_safe},