Surf 依赖导致先前使用 matrix_sdk 和异步特征编译程序时出现 "cannot be shared between threads safely" 错误
Surf dependency causes "cannot be shared between threads safely" error in previously compiling program with matrix_sdk and async-trait
我正在尝试编写一个支持矩阵协议的聊天机器人,我 运行 遇到了这个我无法解决的问题。代码本身编译没有问题,但是将“surf”作为依赖项添加到 Cargo.toml 会导致“dyn log::kv::source::Source` 无法在线程之间安全共享”错误。
这是发生这种情况的最少代码:
main.rs:
use std::convert::TryFrom;
use matrix_sdk::{
Client, Result,
ruma::{UserId},
};
use async_trait::async_trait;
async fn new_matrix_connector() -> Option<()> {
let username = "NAME";
let password = "PASSWORD";
let alice = match UserId::try_from(username) {
Ok(user) => user,
Err(_) => {return None;}
};
let client = match Client::new_from_user_id(alice.clone()).await {
Ok(client) => client,
Err(_) => {return None;}
};
match client.login(alice.localpart(), password, None, None).await {
Ok(_) => {},
Err(_) => {return None;}
}
Some(())
}
#[async_trait]
trait Loader {
async fn load(&self) -> Option<()>;
}
struct TestLoader {}
#[async_trait]
impl Loader for TestLoader {
async fn load(&self) -> Option<()> {
new_matrix_connector().await
}
}
#[tokio::main]
async fn main() -> Result<()> {
let loader = TestLoader{};
let _res = loader.load();
Ok(())
}
Cargo.toml:
[package]
name = "matrixtest"
version = "0.1.0"
edition = "2018"
[dependencies]
matrix-sdk = "0.4.1"
tokio = { version = "1", features = ["full"] }
async-trait = "0.1.52"
surf = "2.3.2"
这些是导致的全部错误:
error[E0277]: `dyn log::kv::source::Source` cannot be shared between threads safely
--> src/main.rs:38:40
|
38 | async fn load(&self) -> Option<()> {
| ________________________________________^
39 | | new_matrix_connector().await
40 | | }
| |_____^ `dyn log::kv::source::Source` cannot be shared between threads safely
|
= help: the trait `Sync` is not implemented for `dyn log::kv::source::Source`
= note: required because of the requirements on the impl of `Send` for `&dyn log::kv::source::Source`
= note: required because it appears within the type `log::KeyValues<'_>`
= note: required because it appears within the type `log::Record<'_>`
= note: required because it appears within the type `log::RecordBuilder<'_>`
= note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7, 't8, 't9, 't10, 't11, 't12, 't13, 't14, 't15, 't16, 't17, 't18, 't19, 't20, 't21, 't22, 't23, 't24, 't25> {ResumeTy, log::Level, log::Metadata<'r>, &'s (dyn log::Log + 't0), &'t1 mut log::RecordBuilder<'t2>, log::RecordBuilder<'t3>, &'t4 str, std::option::Option<&'t5 str>, u32, std::option::Option<u32>, [&'t6 str; 2], &'t7 [&'t8 str], &'t9 [&'t10 str; 2], &'t11 matrix_sdk::Client, impl for<'t12> std::future::Future, (), tracing_core::subscriber::Interest, &'t13 tracing_core::metadata::Metadata<'t14>, tracing_core::field::Iter, &'t15 tracing_core::field::FieldSet, &'t16 mut tracing_core::field::Iter, std::option::Option<tracing_core::field::Field>, tracing_core::field::Field, &'t17 tracing_core::field::Field, LoginInfo<'t18>, matrix_sdk::ruma::api::ruma_client_api::r0::session::login::Request<'t19>, std::option::Option<RequestConfig>, impl for<'t20, 't21> std::future::Future, matrix_sdk::ruma::api::ruma_client_api::r0::session::login::Response, matrix_sdk::Client, &'t22 matrix_sdk_base::client::BaseClient, matrix_sdk_base::client::BaseClient, &'t23 matrix_sdk::ruma::api::ruma_client_api::r0::session::login::Response, impl for<'t24, 't25> std::future::Future}`
= note: required because it appears within the type `[static generator@matrix_sdk::Client::login::{closure#0}::{closure#0}]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@matrix_sdk::Client::login::{closure#0}::{closure#0}]>`
= note: required because it appears within the type `impl std::future::Future`
= note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7, 't8, 't9, 't10> {ResumeTy, &'r matrix_sdk::Client, &'s str, std::option::Option<&'t0 str>, tracing::span::Span, impl for<'t1, 't2, 't3, 't4, 't5> std::future::Future, tracing::instrument::Instrumented<impl for<'t6, 't7, 't8, 't9, 't10> std::future::Future>, ()}`
= note: required because it appears within the type `[static generator@matrix_sdk::Client::login::{closure#0}]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@matrix_sdk::Client::login::{closure#0}]>`
= note: required because it appears within the type `impl std::future::Future`
= note: required because it appears within the type `impl std::future::Future`
= note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6> {ResumeTy, &'r str, matrix_sdk::ruma::UserId, &'s matrix_sdk::ruma::UserId, impl std::future::Future, (), matrix_sdk::Client, &'t0 matrix_sdk::Client, std::option::Option<&'t1 str>, impl for<'t2, 't3, 't4, 't5, 't6> std::future::Future}`
= note: required because it appears within the type `[static generator@src/main.rs:8:47: 27:2]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@src/main.rs:8:47: 27:2]>`
= note: required because it appears within the type `impl std::future::Future`
= note: required because it appears within the type `impl std::future::Future`
= note: required because it appears within the type `for<'r> {ResumeTy, &'r TestLoader, impl std::future::Future, ()}`
= note: required because it appears within the type `[static generator@src/main.rs:38:40: 40:6]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@src/main.rs:38:40: 40:6]>`
= note: required because it appears within the type `impl std::future::Future`
= note: required for the cast to the object type `dyn std::future::Future<Output = std::option::Option<()>> + Send`
error[E0277]: `core::fmt::Opaque` cannot be shared between threads safely
--> src/main.rs:38:40
|
38 | async fn load(&self) -> Option<()> {
| ________________________________________^
39 | | new_matrix_connector().await
40 | | }
| |_____^ `core::fmt::Opaque` cannot be shared between threads safely
|
= help: within `[ArgumentV1<'_>]`, the trait `Sync` is not implemented for `core::fmt::Opaque`
= note: required because it appears within the type `&core::fmt::Opaque`
= note: required because it appears within the type `ArgumentV1<'_>`
= note: required because it appears within the type `[ArgumentV1<'_>]`
= note: required because of the requirements on the impl of `Send` for `&[ArgumentV1<'_>]`
= note: required because it appears within the type `Arguments<'_>`
= note: required because it appears within the type `log::Record<'_>`
= note: required because it appears within the type `log::RecordBuilder<'_>`
= note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7, 't8, 't9, 't10, 't11, 't12, 't13, 't14, 't15, 't16, 't17, 't18, 't19, 't20, 't21, 't22, 't23, 't24, 't25> {ResumeTy, log::Level, log::Metadata<'r>, &'s (dyn log::Log + 't0), &'t1 mut log::RecordBuilder<'t2>, log::RecordBuilder<'t3>, &'t4 str, std::option::Option<&'t5 str>, u32, std::option::Option<u32>, [&'t6 str; 2], &'t7 [&'t8 str], &'t9 [&'t10 str; 2], &'t11 matrix_sdk::Client, impl for<'t12> std::future::Future, (), tracing_core::subscriber::Interest, &'t13 tracing_core::metadata::Metadata<'t14>, tracing_core::field::Iter, &'t15 tracing_core::field::FieldSet, &'t16 mut tracing_core::field::Iter, std::option::Option<tracing_core::field::Field>, tracing_core::field::Field, &'t17 tracing_core::field::Field, LoginInfo<'t18>, matrix_sdk::ruma::api::ruma_client_api::r0::session::login::Request<'t19>, std::option::Option<RequestConfig>, impl for<'t20, 't21> std::future::Future, matrix_sdk::ruma::api::ruma_client_api::r0::session::login::Response, matrix_sdk::Client, &'t22 matrix_sdk_base::client::BaseClient, matrix_sdk_base::client::BaseClient, &'t23 matrix_sdk::ruma::api::ruma_client_api::r0::session::login::Response, impl for<'t24, 't25> std::future::Future}`
= note: required because it appears within the type `[static generator@matrix_sdk::Client::login::{closure#0}::{closure#0}]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@matrix_sdk::Client::login::{closure#0}::{closure#0}]>`
= note: required because it appears within the type `impl std::future::Future`
= note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7, 't8, 't9, 't10> {ResumeTy, &'r matrix_sdk::Client, &'s str, std::option::Option<&'t0 str>, tracing::span::Span, impl for<'t1, 't2, 't3, 't4, 't5> std::future::Future, tracing::instrument::Instrumented<impl for<'t6, 't7, 't8, 't9, 't10> std::future::Future>, ()}`
= note: required because it appears within the type `[static generator@matrix_sdk::Client::login::{closure#0}]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@matrix_sdk::Client::login::{closure#0}]>`
= note: required because it appears within the type `impl std::future::Future`
= note: required because it appears within the type `impl std::future::Future`
= note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6> {ResumeTy, &'r str, matrix_sdk::ruma::UserId, &'s matrix_sdk::ruma::UserId, impl std::future::Future, (), matrix_sdk::Client, &'t0 matrix_sdk::Client, std::option::Option<&'t1 str>, impl for<'t2, 't3, 't4, 't5, 't6> std::future::Future}`
= note: required because it appears within the type `[static generator@src/main.rs:8:47: 27:2]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@src/main.rs:8:47: 27:2]>`
= note: required because it appears within the type `impl std::future::Future`
= note: required because it appears within the type `impl std::future::Future`
= note: required because it appears within the type `for<'r> {ResumeTy, &'r TestLoader, impl std::future::Future, ()}`
= note: required because it appears within the type `[static generator@src/main.rs:38:40: 40:6]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@src/main.rs:38:40: 40:6]>`
= note: required because it appears within the type `impl std::future::Future`
= note: required for the cast to the object type `dyn std::future::Future<Output = std::option::Option<()>> + Send`
For more information about this error, try `rustc --explain E0277`.
error: could not compile `matrix` due to 2 previous errors
在没有 surf 依赖的情况下,编译没有问题。如果直接为 TestLoader 结构实现 load() 函数,也不会发生这种情况。
我的一个朋友发现了问题所在:
问题不直接是 surf,而是带有 log 的 tracing crate功能已启用,surf 间接依赖于该功能。上面已经有一个issue on github,但是还没有解决
问题由 matrix-sdk 触发,因为它也使用 tracing,但通常没有 日志 功能。触发它的行是这样的:
info!("Registering to {}", self.homeserver().await);
改成
let homeserver = self.homeserver().await;
info!("Registering to {}", homeserver);
问题已解决。 matrix-sdk 的一个分支中存在对此的修复(在 this 提交中修复),但据我所知它尚未合并然而。从那以后也没有发布(最新版本是 0.4.1),所以也许它会在下一个版本中得到修复。
暂时我解决这个问题的方法是不依赖于 surf.
我正在尝试编写一个支持矩阵协议的聊天机器人,我 运行 遇到了这个我无法解决的问题。代码本身编译没有问题,但是将“surf”作为依赖项添加到 Cargo.toml 会导致“dyn log::kv::source::Source` 无法在线程之间安全共享”错误。
这是发生这种情况的最少代码:
main.rs:
use std::convert::TryFrom;
use matrix_sdk::{
Client, Result,
ruma::{UserId},
};
use async_trait::async_trait;
async fn new_matrix_connector() -> Option<()> {
let username = "NAME";
let password = "PASSWORD";
let alice = match UserId::try_from(username) {
Ok(user) => user,
Err(_) => {return None;}
};
let client = match Client::new_from_user_id(alice.clone()).await {
Ok(client) => client,
Err(_) => {return None;}
};
match client.login(alice.localpart(), password, None, None).await {
Ok(_) => {},
Err(_) => {return None;}
}
Some(())
}
#[async_trait]
trait Loader {
async fn load(&self) -> Option<()>;
}
struct TestLoader {}
#[async_trait]
impl Loader for TestLoader {
async fn load(&self) -> Option<()> {
new_matrix_connector().await
}
}
#[tokio::main]
async fn main() -> Result<()> {
let loader = TestLoader{};
let _res = loader.load();
Ok(())
}
Cargo.toml:
[package]
name = "matrixtest"
version = "0.1.0"
edition = "2018"
[dependencies]
matrix-sdk = "0.4.1"
tokio = { version = "1", features = ["full"] }
async-trait = "0.1.52"
surf = "2.3.2"
这些是导致的全部错误:
error[E0277]: `dyn log::kv::source::Source` cannot be shared between threads safely
--> src/main.rs:38:40
|
38 | async fn load(&self) -> Option<()> {
| ________________________________________^
39 | | new_matrix_connector().await
40 | | }
| |_____^ `dyn log::kv::source::Source` cannot be shared between threads safely
|
= help: the trait `Sync` is not implemented for `dyn log::kv::source::Source`
= note: required because of the requirements on the impl of `Send` for `&dyn log::kv::source::Source`
= note: required because it appears within the type `log::KeyValues<'_>`
= note: required because it appears within the type `log::Record<'_>`
= note: required because it appears within the type `log::RecordBuilder<'_>`
= note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7, 't8, 't9, 't10, 't11, 't12, 't13, 't14, 't15, 't16, 't17, 't18, 't19, 't20, 't21, 't22, 't23, 't24, 't25> {ResumeTy, log::Level, log::Metadata<'r>, &'s (dyn log::Log + 't0), &'t1 mut log::RecordBuilder<'t2>, log::RecordBuilder<'t3>, &'t4 str, std::option::Option<&'t5 str>, u32, std::option::Option<u32>, [&'t6 str; 2], &'t7 [&'t8 str], &'t9 [&'t10 str; 2], &'t11 matrix_sdk::Client, impl for<'t12> std::future::Future, (), tracing_core::subscriber::Interest, &'t13 tracing_core::metadata::Metadata<'t14>, tracing_core::field::Iter, &'t15 tracing_core::field::FieldSet, &'t16 mut tracing_core::field::Iter, std::option::Option<tracing_core::field::Field>, tracing_core::field::Field, &'t17 tracing_core::field::Field, LoginInfo<'t18>, matrix_sdk::ruma::api::ruma_client_api::r0::session::login::Request<'t19>, std::option::Option<RequestConfig>, impl for<'t20, 't21> std::future::Future, matrix_sdk::ruma::api::ruma_client_api::r0::session::login::Response, matrix_sdk::Client, &'t22 matrix_sdk_base::client::BaseClient, matrix_sdk_base::client::BaseClient, &'t23 matrix_sdk::ruma::api::ruma_client_api::r0::session::login::Response, impl for<'t24, 't25> std::future::Future}`
= note: required because it appears within the type `[static generator@matrix_sdk::Client::login::{closure#0}::{closure#0}]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@matrix_sdk::Client::login::{closure#0}::{closure#0}]>`
= note: required because it appears within the type `impl std::future::Future`
= note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7, 't8, 't9, 't10> {ResumeTy, &'r matrix_sdk::Client, &'s str, std::option::Option<&'t0 str>, tracing::span::Span, impl for<'t1, 't2, 't3, 't4, 't5> std::future::Future, tracing::instrument::Instrumented<impl for<'t6, 't7, 't8, 't9, 't10> std::future::Future>, ()}`
= note: required because it appears within the type `[static generator@matrix_sdk::Client::login::{closure#0}]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@matrix_sdk::Client::login::{closure#0}]>`
= note: required because it appears within the type `impl std::future::Future`
= note: required because it appears within the type `impl std::future::Future`
= note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6> {ResumeTy, &'r str, matrix_sdk::ruma::UserId, &'s matrix_sdk::ruma::UserId, impl std::future::Future, (), matrix_sdk::Client, &'t0 matrix_sdk::Client, std::option::Option<&'t1 str>, impl for<'t2, 't3, 't4, 't5, 't6> std::future::Future}`
= note: required because it appears within the type `[static generator@src/main.rs:8:47: 27:2]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@src/main.rs:8:47: 27:2]>`
= note: required because it appears within the type `impl std::future::Future`
= note: required because it appears within the type `impl std::future::Future`
= note: required because it appears within the type `for<'r> {ResumeTy, &'r TestLoader, impl std::future::Future, ()}`
= note: required because it appears within the type `[static generator@src/main.rs:38:40: 40:6]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@src/main.rs:38:40: 40:6]>`
= note: required because it appears within the type `impl std::future::Future`
= note: required for the cast to the object type `dyn std::future::Future<Output = std::option::Option<()>> + Send`
error[E0277]: `core::fmt::Opaque` cannot be shared between threads safely
--> src/main.rs:38:40
|
38 | async fn load(&self) -> Option<()> {
| ________________________________________^
39 | | new_matrix_connector().await
40 | | }
| |_____^ `core::fmt::Opaque` cannot be shared between threads safely
|
= help: within `[ArgumentV1<'_>]`, the trait `Sync` is not implemented for `core::fmt::Opaque`
= note: required because it appears within the type `&core::fmt::Opaque`
= note: required because it appears within the type `ArgumentV1<'_>`
= note: required because it appears within the type `[ArgumentV1<'_>]`
= note: required because of the requirements on the impl of `Send` for `&[ArgumentV1<'_>]`
= note: required because it appears within the type `Arguments<'_>`
= note: required because it appears within the type `log::Record<'_>`
= note: required because it appears within the type `log::RecordBuilder<'_>`
= note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7, 't8, 't9, 't10, 't11, 't12, 't13, 't14, 't15, 't16, 't17, 't18, 't19, 't20, 't21, 't22, 't23, 't24, 't25> {ResumeTy, log::Level, log::Metadata<'r>, &'s (dyn log::Log + 't0), &'t1 mut log::RecordBuilder<'t2>, log::RecordBuilder<'t3>, &'t4 str, std::option::Option<&'t5 str>, u32, std::option::Option<u32>, [&'t6 str; 2], &'t7 [&'t8 str], &'t9 [&'t10 str; 2], &'t11 matrix_sdk::Client, impl for<'t12> std::future::Future, (), tracing_core::subscriber::Interest, &'t13 tracing_core::metadata::Metadata<'t14>, tracing_core::field::Iter, &'t15 tracing_core::field::FieldSet, &'t16 mut tracing_core::field::Iter, std::option::Option<tracing_core::field::Field>, tracing_core::field::Field, &'t17 tracing_core::field::Field, LoginInfo<'t18>, matrix_sdk::ruma::api::ruma_client_api::r0::session::login::Request<'t19>, std::option::Option<RequestConfig>, impl for<'t20, 't21> std::future::Future, matrix_sdk::ruma::api::ruma_client_api::r0::session::login::Response, matrix_sdk::Client, &'t22 matrix_sdk_base::client::BaseClient, matrix_sdk_base::client::BaseClient, &'t23 matrix_sdk::ruma::api::ruma_client_api::r0::session::login::Response, impl for<'t24, 't25> std::future::Future}`
= note: required because it appears within the type `[static generator@matrix_sdk::Client::login::{closure#0}::{closure#0}]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@matrix_sdk::Client::login::{closure#0}::{closure#0}]>`
= note: required because it appears within the type `impl std::future::Future`
= note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6, 't7, 't8, 't9, 't10> {ResumeTy, &'r matrix_sdk::Client, &'s str, std::option::Option<&'t0 str>, tracing::span::Span, impl for<'t1, 't2, 't3, 't4, 't5> std::future::Future, tracing::instrument::Instrumented<impl for<'t6, 't7, 't8, 't9, 't10> std::future::Future>, ()}`
= note: required because it appears within the type `[static generator@matrix_sdk::Client::login::{closure#0}]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@matrix_sdk::Client::login::{closure#0}]>`
= note: required because it appears within the type `impl std::future::Future`
= note: required because it appears within the type `impl std::future::Future`
= note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3, 't4, 't5, 't6> {ResumeTy, &'r str, matrix_sdk::ruma::UserId, &'s matrix_sdk::ruma::UserId, impl std::future::Future, (), matrix_sdk::Client, &'t0 matrix_sdk::Client, std::option::Option<&'t1 str>, impl for<'t2, 't3, 't4, 't5, 't6> std::future::Future}`
= note: required because it appears within the type `[static generator@src/main.rs:8:47: 27:2]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@src/main.rs:8:47: 27:2]>`
= note: required because it appears within the type `impl std::future::Future`
= note: required because it appears within the type `impl std::future::Future`
= note: required because it appears within the type `for<'r> {ResumeTy, &'r TestLoader, impl std::future::Future, ()}`
= note: required because it appears within the type `[static generator@src/main.rs:38:40: 40:6]`
= note: required because it appears within the type `from_generator::GenFuture<[static generator@src/main.rs:38:40: 40:6]>`
= note: required because it appears within the type `impl std::future::Future`
= note: required for the cast to the object type `dyn std::future::Future<Output = std::option::Option<()>> + Send`
For more information about this error, try `rustc --explain E0277`.
error: could not compile `matrix` due to 2 previous errors
在没有 surf 依赖的情况下,编译没有问题。如果直接为 TestLoader 结构实现 load() 函数,也不会发生这种情况。
我的一个朋友发现了问题所在:
问题不直接是 surf,而是带有 log 的 tracing crate功能已启用,surf 间接依赖于该功能。上面已经有一个issue on github,但是还没有解决
问题由 matrix-sdk 触发,因为它也使用 tracing,但通常没有 日志 功能。触发它的行是这样的:
info!("Registering to {}", self.homeserver().await);
改成
let homeserver = self.homeserver().await;
info!("Registering to {}", homeserver);
问题已解决。 matrix-sdk 的一个分支中存在对此的修复(在 this 提交中修复),但据我所知它尚未合并然而。从那以后也没有发布(最新版本是 0.4.1),所以也许它会在下一个版本中得到修复。
暂时我解决这个问题的方法是不依赖于 surf.