feat(wasm): Wasm equivalent of get_runtime_handle and corresponding tokio types (#5089)

Adds a Wasm equivalent of the get_runtime_handle method provided by
tokio, as well as Handle/Runtime types that can be used on either Wasm
or non-Wasm platforms interchangeably.

Dependent on https://github.com/matrix-org/matrix-rust-sdk/pull/5088
<!-- description of the changes in this PR -->

- [ ] Public API changes documented in changelogs (optional)

<!-- Sign-off, if not part of the commits -->
<!-- See CONTRIBUTING.md if you don't know what this is -->
Signed-off-by: Daniel Salinas

---------

Signed-off-by: Daniel Salinas <zzorba@users.noreply.github.com>
Co-authored-by: Daniel Salinas <danielsalinas@Daniels-MacBook-Pro-2.local>
Co-authored-by: Daniel Salinas <danielsalinas@daniels-mbp-2.myfiosgateway.com>
Co-authored-by: Jonas Platte <jplatte+git@posteo.de>
Co-authored-by: Ivan Enderlin <ivan@mnt.io>
This commit is contained in:
Daniel Salinas
2025-06-05 02:07:01 -04:00
committed by GitHub
parent 0777e6e08a
commit a3225e5cd7
16 changed files with 130 additions and 21 deletions
Generated
+2
View File
@@ -2980,8 +2980,10 @@ version = "0.11.0"
dependencies = [
"assert_matches",
"assert_matches2",
"async-compat",
"eyeball-im",
"futures-core",
"futures-executor",
"futures-util",
"getrandom 0.2.15",
"gloo-timers",
+1
View File
@@ -25,6 +25,7 @@ as_variant = "1.3.0"
assert-json-diff = "2.0.2"
assert_matches = "1.5.0"
assert_matches2 = "0.1.2"
async-compat = "0.2.4"
async-rx = "0.1.3"
async-stream = "0.3.5"
async-trait = "0.1.85"
+3 -2
View File
@@ -7,7 +7,6 @@ use std::{
};
use anyhow::{anyhow, Context as _};
use async_compat::get_runtime_handle;
use futures_util::pin_mut;
use matrix_sdk::{
authentication::oauth::{
@@ -41,7 +40,9 @@ use matrix_sdk::{
AuthApi, AuthSession, Client as MatrixClient, SessionChange, SessionTokens,
STATE_STORE_DATABASE_NAME,
};
use matrix_sdk_common::{stream::StreamExt, SendOutsideWasm, SyncOutsideWasm};
use matrix_sdk_common::{
runtime::get_runtime_handle, stream::StreamExt, SendOutsideWasm, SyncOutsideWasm,
};
use matrix_sdk_ui::{
notification_client::{
NotificationClient as MatrixNotificationClient,
@@ -1,6 +1,5 @@
use std::{fs, num::NonZeroUsize, path::Path, sync::Arc, time::Duration};
use async_compat::get_runtime_handle;
use futures_util::StreamExt;
use matrix_sdk::{
authentication::oauth::qrcode::{self, DeviceCodeErrorResponseType, LoginFailureReason},
@@ -19,7 +18,7 @@ use matrix_sdk::{
Client as MatrixClient, ClientBuildError as MatrixClientBuildError, HttpError, IdParseError,
RumaApiError, SqliteStoreConfig,
};
use matrix_sdk_common::{SendOutsideWasm, SyncOutsideWasm};
use matrix_sdk_common::{runtime::get_runtime_handle, SendOutsideWasm, SyncOutsideWasm};
use ruma::api::error::{DeserializationError, FromHttpResponseError};
use tracing::{debug, error};
use zeroize::Zeroizing;
+1 -2
View File
@@ -1,12 +1,11 @@
use std::sync::Arc;
use async_compat::get_runtime_handle;
use futures_util::StreamExt;
use matrix_sdk::{
encryption,
encryption::{backups, recovery},
};
use matrix_sdk_common::{SendOutsideWasm, SyncOutsideWasm};
use matrix_sdk_common::{runtime::get_runtime_handle, SendOutsideWasm, SyncOutsideWasm};
use thiserror::Error;
use tracing::{error, info};
use zeroize::Zeroize;
+1 -2
View File
@@ -1,7 +1,6 @@
use std::{collections::HashMap, pin::pin, sync::Arc};
use anyhow::{Context, Result};
use async_compat::get_runtime_handle;
use futures_util::{pin_mut, StreamExt};
use matrix_sdk::{
crypto::LocalTrust,
@@ -13,7 +12,7 @@ use matrix_sdk::{
PredecessorRoom as SdkPredecessorRoom, RoomHero as SdkRoomHero, RoomMemberships, RoomState,
SuccessorRoom as SdkSuccessorRoom,
};
use matrix_sdk_common::{SendOutsideWasm, SyncOutsideWasm};
use matrix_sdk_common::{runtime::get_runtime_handle, SendOutsideWasm, SyncOutsideWasm};
use matrix_sdk_ui::{
timeline::{default_event_filter, RoomExt, TimelineBuilder},
unable_to_decrypt_hook::UtdHookManager,
@@ -15,11 +15,10 @@
use std::{fmt::Debug, sync::Arc};
use async_compat::get_runtime_handle;
use eyeball_im::VectorDiff;
use futures_util::StreamExt;
use matrix_sdk::room_directory_search::RoomDirectorySearch as SdkRoomDirectorySearch;
use matrix_sdk_common::{SendOutsideWasm, SyncOutsideWasm};
use matrix_sdk_common::{runtime::get_runtime_handle, SendOutsideWasm, SyncOutsideWasm};
use ruma::ServerName;
use tokio::sync::RwLock;
+1 -2
View File
@@ -2,7 +2,6 @@
use std::{fmt::Debug, mem::MaybeUninit, ptr::addr_of_mut, sync::Arc, time::Duration};
use async_compat::get_runtime_handle;
use eyeball_im::VectorDiff;
use futures_util::{pin_mut, StreamExt};
use matrix_sdk::{
@@ -12,7 +11,7 @@ use matrix_sdk::{
},
Room as SdkRoom,
};
use matrix_sdk_common::{SendOutsideWasm, SyncOutsideWasm};
use matrix_sdk_common::{runtime::get_runtime_handle, SendOutsideWasm, SyncOutsideWasm};
use matrix_sdk_ui::{
room_list_service::filters::{
new_filter_all, new_filter_any, new_filter_category, new_filter_deduplicate_versions,
@@ -1,6 +1,5 @@
use std::sync::{Arc, RwLock};
use async_compat::get_runtime_handle;
use futures_util::StreamExt;
use matrix_sdk::{
encryption::{
@@ -11,7 +10,7 @@ use matrix_sdk::{
ruma::events::key::verification::VerificationMethod,
Account,
};
use matrix_sdk_common::{SendOutsideWasm, SyncOutsideWasm};
use matrix_sdk_common::{runtime::get_runtime_handle, SendOutsideWasm, SyncOutsideWasm};
use ruma::UserId;
use tracing::{error, warn};
+1 -2
View File
@@ -14,10 +14,9 @@
use std::{fmt::Debug, sync::Arc};
use async_compat::get_runtime_handle;
use futures_util::pin_mut;
use matrix_sdk::Client;
use matrix_sdk_common::{SendOutsideWasm, SyncOutsideWasm};
use matrix_sdk_common::{runtime::get_runtime_handle, SendOutsideWasm, SyncOutsideWasm};
use matrix_sdk_ui::{
sync_service::{
State as MatrixSyncServiceState, SyncService as MatrixSyncService,
+1 -1
View File
@@ -16,7 +16,6 @@ use std::{collections::HashMap, fmt::Write as _, fs, panic, sync::Arc};
use anyhow::{Context, Result};
use as_variant::as_variant;
use async_compat::get_runtime_handle;
use eyeball_im::VectorDiff;
use futures_util::{pin_mut, StreamExt as _};
use matrix_sdk::{
@@ -31,6 +30,7 @@ use matrix_sdk::{
reply::{EnforceThread, Reply},
},
};
use matrix_sdk_common::runtime::get_runtime_handle;
use matrix_sdk_ui::timeline::{
self, AttachmentSource, EventItemOrigin, Profile, TimelineDetails,
TimelineUniqueId as SdkTimelineUniqueId,
+1 -1
View File
@@ -14,7 +14,7 @@
use std::{mem::ManuallyDrop, ops::Deref};
use async_compat::get_runtime_handle;
use matrix_sdk_common::runtime::get_runtime_handle;
use ruma::{MilliSecondsSinceUnixEpoch, UInt};
use tracing::warn;
+1 -2
View File
@@ -1,12 +1,11 @@
use std::sync::{Arc, Mutex};
use async_compat::get_runtime_handle;
use language_tags::LanguageTag;
use matrix_sdk::{
async_trait,
widget::{MessageLikeEventFilter, StateEventFilter, ToDeviceEventFilter},
};
use matrix_sdk_common::{SendOutsideWasm, SyncOutsideWasm};
use matrix_sdk_common::{runtime::get_runtime_handle, SendOutsideWasm, SyncOutsideWasm};
use ruma::events::MessageLikeEventType;
use tracing::error;
+3 -1
View File
@@ -25,6 +25,7 @@ uniffi = ["dep:uniffi"]
test-send-sync = []
[dependencies]
async-compat.workspace = true
eyeball-im.workspace = true
futures-core.workspace = true
futures-util.workspace = true
@@ -41,9 +42,10 @@ uniffi = { workspace = true, optional = true }
tokio = { workspace = true, features = ["rt", "time", "macros"] }
[target.'cfg(target_family = "wasm")'.dependencies]
futures-executor.workspace = true
futures-util = { workspace = true, features = ["channel"] }
gloo-timers = { workspace = true, features = ["futures"] }
tokio = { workspace = true, features = ["macros"] }
tokio = { workspace = true, features = ["sync", "macros", "time"] }
tracing-subscriber = { workspace = true, features = ["fmt", "ansi"] }
wasm-bindgen.workspace = true
wasm-bindgen-futures = { version = "0.4.33", optional = true }
+1
View File
@@ -28,6 +28,7 @@ pub mod failures_cache;
pub mod linked_chunk;
pub mod locks;
pub mod ring_buffer;
pub mod runtime;
pub mod serde_helpers;
pub mod sleep;
pub mod store_locks;
+110
View File
@@ -0,0 +1,110 @@
// Copyright 2025 The Matrix.org Foundation C.I.C.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Runtime abstractions for cross-platform async execution. This provides
//! a stand-in for tokio's `get_runtime_handle` method that will work on
//! both Wasm and non-Wasm platforms. It also provides corresponding types
//! that can be used in place of tokio's `Handle` and `Runtime` types.
#[cfg(not(target_family = "wasm"))]
mod sys {
pub use tokio::runtime::{Handle, Runtime};
/// Get a runtime handle appropriate for the current target platform.
///
/// This function returns a unified `Handle` type that works across both
/// Wasm and non-Wasm platforms, allowing code to be written that is
/// agnostic to the platform-specific runtime implementation.
///
/// Returns:
/// - A `tokio::runtime::Handle` on non-Wasm platforms
/// - A `WasmRuntimeHandle` on Wasm platforms
pub fn get_runtime_handle() -> Handle {
async_compat::get_runtime_handle()
}
}
#[cfg(target_family = "wasm")]
mod sys {
use std::future::Future;
use crate::executor::{spawn, JoinHandle};
/// A dummy guard that does nothing when dropped.
/// This is used for the Wasm implementation to match
/// tokio::runtime::EnterGuard.
#[derive(Debug)]
pub struct RuntimeGuard;
/// A runtime handle implementation for WebAssembly targets.
///
/// This implements a minimal subset of the tokio::runtime::Handle API
/// that is needed for the matrix-rust-sdk to function on Wasm.
#[derive(Default, Debug)]
pub struct Handle;
pub type Runtime = Handle;
impl Handle {
/// Spawns a future in the wasm32 bindgen runtime.
#[track_caller]
pub fn spawn<F>(&self, future: F) -> JoinHandle<F::Output>
where
F: Future + 'static,
F::Output: 'static,
{
spawn(future)
}
/// Runs the provided function on an executor dedicated to blocking
/// operations.
#[track_caller]
pub fn spawn_blocking<F, R>(&self, func: F) -> JoinHandle<R>
where
F: FnOnce() -> R + 'static,
R: 'static,
{
spawn(async move { func() })
}
/// Runs a future to completion on the current thread.
pub fn block_on<F, T>(&self, future: F) -> T
where
F: Future<Output = T>,
{
futures_executor::block_on(future)
}
/// Enters the runtime context.
///
/// For WebAssembly, this is a no-op that returns a dummy guard.
pub fn enter(&self) -> RuntimeGuard {
RuntimeGuard
}
}
/// Get a runtime handle appropriate for the current target platform.
///
/// This function returns a unified `Handle` type that works across both
/// Wasm and non-Wasm platforms, allowing code to be written that is
/// agnostic to the platform-specific runtime implementation.
///
/// Returns:
/// - A `tokio::runtime::Handle` on non-Wasm platforms
/// - A `WasmRuntimeHandle` on Wasm platforms
pub fn get_runtime_handle() -> Handle {
Handle
}
}
pub use sys::*;