diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2e5eb93ff2..dadd632cc4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ on: env: RUSTFLAGS: -Dwarnings - + jobs: fmt: @@ -83,13 +83,13 @@ jobs: rust: 1.61.0 python: false # Python bindings compilation on Windows is not supported. - # Minimum Supported Rust Version = 1.56.0 + # Minimum Supported Rust Version = 1.56.1 # # Minimum Supported Python Version = 3.7 # This is the minimum version for which manylinux Python wheels are # built. - os: ubuntu-latest - rust: 1.56.0 + rust: 1.56.1 python: 3.7 runs-on: ${{ matrix.os }} steps: diff --git a/CHANGELOG.md b/CHANGELOG.md index 8df2015164..d19dcc340d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ - node: remove `split2` dependency #3418 - node: add git installation info to readme #3418 - limit the rate of webxdc update sending #3417 +- switch from `async-std` to `tokio` as the async runtime #3449 ### Fixes - set a default error if NDN does not provide an error diff --git a/Cargo.lock b/Cargo.lock index ed11e3764b..df00a19033 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -29,15 +29,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" -[[package]] -name = "aead" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331" -dependencies = [ - "generic-array", -] - [[package]] name = "aes" version = "0.6.0" @@ -49,20 +40,6 @@ dependencies = [ "cipher", ] -[[package]] -name = "aes-gcm" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5278b5fabbb9bd46e24aa69b2fdea62c99088e0a950a9be40e3e0101298f88da" -dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "ghash", - "subtle", -] - [[package]] name = "aes-soft" version = "0.6.4" @@ -89,7 +66,7 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ - "getrandom 0.2.6", + "getrandom 0.2.7", "once_cell", "version_check 0.9.4", ] @@ -103,6 +80,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "aliasable" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" + [[package]] name = "ansi_term" version = "0.12.1" @@ -114,15 +97,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" - -[[package]] -name = "arrayvec" -version = "0.5.2" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" +checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704" [[package]] name = "ascii_utils" @@ -130,16 +107,6 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71938f30533e4d95a6d17aa530939da3842c2ab6f4f84b9dae68447e4129f74a" -[[package]] -name = "async-attributes" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" -dependencies = [ - "quote", - "syn", -] - [[package]] name = "async-channel" version = "1.6.1" @@ -152,247 +119,106 @@ dependencies = [ ] [[package]] -name = "async-dup" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7427a12b8dc09291528cfb1da2447059adb4a257388c2acd6497a79d55cf6f7c" -dependencies = [ - "futures-io", - "simple-mutex", -] - -[[package]] -name = "async-executor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "once_cell", - "slab", -] - -[[package]] -name = "async-global-executor" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c290043c9a95b05d45e952fb6383c67bcb61471f60cfa21e890dba6654234f43" -dependencies = [ - "async-channel", - "async-executor", - "async-io", - "async-mutex", - "blocking", - "futures-lite", - "num_cpus", - "once_cell", -] - -[[package]] -name = "async-h1" -version = "2.3.3" +name = "async-compression" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8101020758a4fc3a7c326cb42aa99e9fa77cbfb76987c128ad956406fe1f70a7" +checksum = "345fd392ab01f746c717b1357165b76f0b67a60192007b234058c9045fdcf695" dependencies = [ - "async-channel", - "async-dup", - "async-std", + "flate2", "futures-core", - "http-types", - "httparse", - "log", - "pin-project", + "memchr", + "pin-project-lite", + "tokio", ] [[package]] name = "async-imap" -version = "0.5.0" -source = "git+https://github.com/async-email/async-imap#d07ea4019f2ca724244f7a4503a8ac4946a722b3" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31dd46675b8c5a2ecadd4ef690c84966eacf21b1e2327373a0d167494d1a1d28" dependencies = [ + "async-channel", "async-native-tls", - "async-std", "base64 0.13.0", "byte-pool", "chrono", "futures", "imap-proto", "log", - "nom 6.1.2", + "nom 7.1.1", "once_cell", "ouroboros", "pin-utils", "stop-token", "thiserror", -] - -[[package]] -name = "async-io" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5e18f61464ae81cde0a23e713ae8fd299580c54d697a35820cfd0625b8b0e07" -dependencies = [ - "concurrent-queue", - "futures-lite", - "libc", - "log", - "once_cell", - "parking", - "polling", - "slab", - "socket2", - "waker-fn", - "winapi", -] - -[[package]] -name = "async-lock" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e97a171d191782fba31bb902b14ad94e24a68145032b7eedf871ab0bc0d077b6" -dependencies = [ - "event-listener", -] - -[[package]] -name = "async-mutex" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e" -dependencies = [ - "event-listener", + "tokio", ] [[package]] name = "async-native-tls" -version = "0.3.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e9e7a929bd34c68a82d58a4de7f86fffdaf97fb2af850162a7bb19dd7269b33" +checksum = "d57d4cec3c647232e1094dc013546c0b33ce785d8aeb251e1f20dfaf8a9a13fe" dependencies = [ - "async-std", "native-tls", "thiserror", + "tokio", "url", ] -[[package]] -name = "async-process" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf2c06e30a24e8c78a3987d07f0930edf76ef35e027e7bdb063fccafdad1f60c" -dependencies = [ - "async-io", - "blocking", - "cfg-if 1.0.0", - "event-listener", - "futures-lite", - "libc", - "once_cell", - "signal-hook", - "winapi", -] - [[package]] name = "async-smtp" -version = "0.4.0" -source = "git+https://github.com/async-email/async-smtp?branch=master#d6b947cf2a104183fb1634dd885fc0abc2cc1f59" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6da21e1dd19fbad3e095ad519fb1558ab77fd82e5c4778dca8f9be0464589e1e" dependencies = [ "async-native-tls", - "async-std", "async-trait", "base64 0.13.0", "bufstream", "fast-socks5", + "futures", "hostname", "log", - "nom 5.1.2", + "nom 7.1.1", "pin-project", "pin-utils", "thiserror", + "tokio", ] [[package]] -name = "async-std" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52580991739c5cdb36cde8b2a516371c0a3b70dda36d916cc08b82372916808c" -dependencies = [ - "async-attributes", - "async-channel", - "async-global-executor", - "async-io", - "async-lock", - "async-process", - "crossbeam-utils", - "futures-channel", - "futures-core", - "futures-io", - "futures-lite", - "gloo-timers", - "kv-log-macro", - "log", - "memchr", - "num_cpus", - "once_cell", - "pin-project-lite", - "pin-utils", - "slab", - "wasm-bindgen-futures", -] - -[[package]] -name = "async-std-resolver" -version = "0.21.2" +name = "async-trait" +version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f2f8a4a203be3325981310ab243a28e6e4ea55b6519bffce05d41ab60e09ad8" +checksum = "96cf8829f67d2eab0b2dfa42c5d0ef737e0724e4a82b01b3e292456202b19716" dependencies = [ - "async-std", - "async-trait", - "futures-io", - "futures-util", - "pin-utils", - "socket2", - "trust-dns-resolver", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "async-tar" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c49359998a76e32ef6e870dbc079ebad8f1e53e8441c5dd39d27b44493fe331" +name = "async_io_utilities" +version = "0.1.3" +source = "git+https://github.com/Majored/rs-async-io-utilities#1aa191aa5ff651526e0ac08691b1932724350229" dependencies = [ - "async-std", - "filetime", - "libc", - "pin-project", - "redox_syscall", + "tokio", ] [[package]] -name = "async-task" -version = "4.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30696a84d817107fc028e049980e09d5e140e8da8f1caeb17e8e950658a3cea9" - -[[package]] -name = "async-trait" -version = "0.1.53" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed6aa3524a2dfcf9fe180c51eae2b58738348d819517ceadf95789c51fff7600" +name = "async_zip" +version = "0.0.7" +source = "git+https://github.com/dignifiedquire/rs-async-zip?branch=main#2d657a5f3c0906ee6e95a7fbb9a854fba57268e6" dependencies = [ - "proc-macro2", - "quote", - "syn", + "async-compression", + "async_io_utilities", + "chrono", + "crc32fast", + "thiserror", + "tokio", ] -[[package]] -name = "atomic-waker" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" - [[package]] name = "atty" version = "0.2.14" @@ -434,12 +260,6 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "base-x" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc19a4937b4fbd3fe3379793130e42060d10627a360f2127802b10b87e7baf74" - [[package]] name = "base64" version = "0.11.0" @@ -470,18 +290,6 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[package]] -name = "bitvec" -version = "0.19.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55f93d0ef3363c364d5976646a38f04cf67cfe1d4c8d160cdea02cab2c116b33" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - [[package]] name = "block-buffer" version = "0.9.0" @@ -526,20 +334,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" -[[package]] -name = "blocking" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6ccb65d468978a086b69884437ded69a90faab3bbe6e67f242173ea728acccc" -dependencies = [ - "async-channel", - "async-task", - "atomic-waker", - "fastrand", - "futures-lite", - "once_cell", -] - [[package]] name = "blowfish" version = "0.7.0" @@ -607,6 +401,12 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + [[package]] name = "cache-padded" version = "1.2.0" @@ -619,7 +419,7 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a" dependencies = [ - "rustc_version 0.4.0", + "rustc_version", ] [[package]] @@ -679,7 +479,7 @@ dependencies = [ "libc", "num-integer", "num-traits", - "time 0.1.44", + "time", "winapi", ] @@ -744,40 +544,6 @@ dependencies = [ "cache-padded", ] -[[package]] -name = "config" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b076e143e1d9538dde65da30f8481c2a6c44040edb8e02b9bf1351edb92ce3" -dependencies = [ - "lazy_static", - "nom 5.1.2", - "serde", -] - -[[package]] -name = "const_fn" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbdcdcb6d86f71c5e97409ad45898af11cbc995b4ee8112d59095a28d376c935" - -[[package]] -name = "cookie" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951" -dependencies = [ - "aes-gcm", - "base64 0.13.0", - "hkdf", - "hmac", - "percent-encoding", - "rand 0.8.5", - "sha2 0.9.9", - "time 0.2.27", - "version_check 0.9.4", -] - [[package]] name = "core-foundation" version = "0.9.3" @@ -803,12 +569,6 @@ dependencies = [ "libc", ] -[[package]] -name = "cpuid-bool" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" - [[package]] name = "crc24" version = "0.1.6" @@ -830,7 +590,6 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10" dependencies = [ - "async-std", "atty", "cast", "clap", @@ -849,6 +608,7 @@ dependencies = [ "serde_derive", "serde_json", "tinytemplate", + "tokio", "walkdir", ] @@ -864,9 +624,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" +checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c" dependencies = [ "cfg-if 1.0.0", "crossbeam-utils", @@ -885,15 +645,15 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" +checksum = "07db9d94cbd326813772c968ccd25999e5f8ae22f4f8d1b11effa37ef6ce281d" dependencies = [ "autocfg 1.1.0", "cfg-if 1.0.0", "crossbeam-utils", - "lazy_static", "memoffset", + "once_cell", "scopeguard", ] @@ -909,12 +669,12 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83" dependencies = [ "cfg-if 1.0.0", - "lazy_static", + "once_cell", ] [[package]] @@ -927,16 +687,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "crypto-mac" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff07008ec701e8028e2ceb8f83f0e4274ee62bd2dbdc4fefff2e9a91824081a" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "csv" version = "1.1.6" @@ -959,25 +709,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "ctor" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c" -dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "ctr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f" -dependencies = [ - "cipher", -] - [[package]] name = "curve25519-dalek" version = "3.2.1" @@ -1027,35 +758,11 @@ dependencies = [ ] [[package]] -name = "dashmap" -version = "4.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" -dependencies = [ - "cfg-if 1.0.0", - "num_cpus", -] - -[[package]] -name = "data-encoding" -version = "2.3.2" +name = "data-encoding" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57" -[[package]] -name = "deadpool" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d126179d86aee4556e54f5f3c6bf6d9884e7cc52cef82f77ee6f90a7747616d" -dependencies = [ - "async-trait", - "config", - "crossbeam-queue", - "num_cpus", - "serde", - "tokio", -] - [[package]] name = "deflate" version = "1.0.0" @@ -1071,12 +778,11 @@ version = "1.87.0" dependencies = [ "ansi_term", "anyhow", + "async-channel", "async-imap", "async-native-tls", "async-smtp", - "async-std", - "async-std-resolver", - "async-tar", + "async_zip", "backtrace", "base64 0.13.0", "bitflags", @@ -1085,7 +791,7 @@ dependencies = [ "deltachat_derive", "dirs", "email", - "encoded-words", + "encoded-words 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "escaper", "fast-socks5", "futures", @@ -1113,6 +819,7 @@ dependencies = [ "r2d2_sqlite", "rand 0.7.3", "regex", + "reqwest", "rusqlite", "rust-hsluv", "rustyline", @@ -1124,15 +831,17 @@ dependencies = [ "smallvec", "strum", "strum_macros", - "surf", "tagger", "tempfile", "textwrap 0.15.0", "thiserror", + "tokio", + "tokio-stream", + "tokio-tar", "toml", + "trust-dns-resolver", "url", - "uuid 1.1.1", - "zip", + "uuid 1.1.2", ] [[package]] @@ -1148,14 +857,15 @@ name = "deltachat_ffi" version = "1.87.0" dependencies = [ "anyhow", - "async-std", "deltachat", "human-panic", "libc", "num-traits", + "once_cell", "rand 0.7.3", "serde_json", "thiserror", + "tokio", ] [[package]] @@ -1254,12 +964,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "discard" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" - [[package]] name = "ed25519" version = "1.5.2" @@ -1296,18 +1000,33 @@ source = "git+https://github.com/deltachat/rust-email?branch=master#25702df99254 dependencies = [ "base64 0.11.0", "chrono", - "encoded-words", + "encoded-words 0.2.0 (git+https://github.com/async-email/encoded-words?branch=master)", "encoding", "lazy_static", "rand 0.7.3", - "time 0.1.44", + "time", "version_check 0.9.4", ] [[package]] name = "encoded-words" -version = "0.1.0" -source = "git+https://github.com/async-email/encoded-words?branch=master#e878b6929ef6aee2909c4c096a0e143a38b8ff8d" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c1693107e6084e2b9444d34a985697f56c8832d314924d5cfb1fb7793154bef" +dependencies = [ + "base64 0.12.3", + "charset", + "encoding_rs", + "hex", + "lazy_static", + "regex", + "thiserror", +] + +[[package]] +name = "encoded-words" +version = "0.2.0" +source = "git+https://github.com/async-email/encoded-words?branch=master#d55366b36f96e383f39c432aedce42ee8b43f796" dependencies = [ "base64 0.12.3", "charset", @@ -1488,15 +1207,15 @@ checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" [[package]] name = "fast-socks5" -version = "0.4.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba337793c1ee49731350a8d971d791651ed51d6e814ab4ddabd79c12b5366140" +checksum = "25bef00d863e757b64a737857143b5425061271a4149ff5d81201fb4c9bfc01c" dependencies = [ "anyhow", - "async-std", - "futures", "log", "thiserror", + "tokio", + "tokio-stream", ] [[package]] @@ -1519,13 +1238,13 @@ dependencies = [ [[package]] name = "fd-lock" -version = "3.0.5" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46e245f4c8ec30c6415c56cb132c07e69e74f1942f6b4a4061da748b49f486ca" +checksum = "e11dcc7e4d79a8c89b9ab4c6f5c30b1fc4a83c420792da3542fd31179ed5f517" dependencies = [ "cfg-if 1.0.0", "rustix", - "windows-sys 0.30.0", + "windows-sys", ] [[package]] @@ -1581,12 +1300,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "funty" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" - [[package]] name = "futures" version = "0.3.21" @@ -1714,30 +1427,20 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" dependencies = [ "cfg-if 1.0.0", "libc", - "wasi 0.10.0+wasi-snapshot-preview1", -] - -[[package]] -name = "ghash" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97304e4cd182c3846f7575ced3890c53012ce534ad9114046b0a9e00bb30a375" -dependencies = [ - "opaque-debug", - "polyval", + "wasi 0.11.0+wasi-snapshot-preview1", ] [[package]] name = "gif" -version = "0.11.3" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3a7187e78088aead22ceedeee99779455b23fc231fe13ec443f99bb71694e5b" +checksum = "3edd93c6756b4dfaf2709eafcc345ba2636565295c198a9cfbf75fa5e3e00b06" dependencies = [ "color_quant", "weezl", @@ -1750,15 +1453,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" [[package]] -name = "gloo-timers" -version = "0.2.4" +name = "h2" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fb7d06c1c8cc2a29bee7ec961009a0b2caa0793ee4900c2ffb348734ba1c8f9" +checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" dependencies = [ - "futures-channel", + "bytes", + "fnv", "futures-core", - "js-sys", - "wasm-bindgen", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", ] [[package]] @@ -1776,13 +1486,19 @@ dependencies = [ "ahash", ] +[[package]] +name = "hashbrown" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db0d4cf898abf0081f964436dc980e96670a0f36863e4b83aaacdb65c9d7ccc3" + [[package]] name = "hashlink" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf" dependencies = [ - "hashbrown", + "hashbrown 0.11.2", ] [[package]] @@ -1806,26 +1522,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hkdf" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51ab2f639c231793c5f6114bdb9bbe50a7dbbfcd7c7c6bd8475dec2d991e964f" -dependencies = [ - "digest 0.9.0", - "hmac", -] - -[[package]] -name = "hmac" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" -dependencies = [ - "crypto-mac", - "digest 0.9.0", -] - [[package]] name = "hostname" version = "0.3.1" @@ -1838,43 +1534,25 @@ dependencies = [ ] [[package]] -name = "http-client" -version = "6.5.2" +name = "http" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e023af341b797ce2c039f7c6e1d347b68d0f7fd0bc7ac234fe69cfadcca1f89a" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" dependencies = [ - "async-h1", - "async-native-tls", - "async-std", - "async-trait", - "cfg-if 1.0.0", - "dashmap", - "deadpool", - "futures", - "http-types", - "log", + "bytes", + "fnv", + "itoa 1.0.2", ] [[package]] -name = "http-types" -version = "2.12.0" +name = "http-body" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e9b187a72d63adbfba487f48095306ac823049cb504ee195541e91c7775f5ad" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ - "anyhow", - "async-channel", - "async-std", - "base64 0.13.0", - "cookie", - "futures-lite", - "infer", + "bytes", + "http", "pin-project-lite", - "rand 0.7.3", - "serde", - "serde_json", - "serde_qs", - "serde_urlencoded", - "url", ] [[package]] @@ -1883,6 +1561,12 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + [[package]] name = "human-panic" version = "1.0.3" @@ -1913,6 +1597,43 @@ dependencies = [ "quick-error 1.2.3", ] +[[package]] +name = "hyper" +version = "0.14.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42dc3c131584288d375f2d07f822b0cb012d8c6fb899a5b9fdb3cb7eb9b6004f" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa 1.0.2", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -1949,18 +1670,22 @@ dependencies = [ [[package]] name = "imap-proto" -version = "0.14.3" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ad9b46a79efb6078e578ae04e51463d7c3e8767864687f7e63095b3cbefafbb" +checksum = "f256a8086d5a408348cddb97d8a07e7d10f861067c497e850e67c9aeda014fda" dependencies = [ - "nom 6.1.2", + "nom 7.1.1", ] [[package]] -name = "infer" -version = "0.2.3" +name = "indexmap" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +dependencies = [ + "autocfg 1.1.0", + "hashbrown 0.12.1", +] [[package]] name = "instant" @@ -1973,9 +1698,9 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "0.6.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9448015e586b611e5d322f6703812bbca2f1e709d5773ecd38ddb4e3bb649504" +checksum = "24c3f4eff5495aee4c0399d7b6a0dc2b6e81be84242ffbfcf253ebacccc1d0cb" [[package]] name = "ipconfig" @@ -1986,7 +1711,7 @@ dependencies = [ "socket2", "widestring", "winapi", - "winreg", + "winreg 0.7.0", ] [[package]] @@ -2024,9 +1749,9 @@ checksum = "9478aa10f73e7528198d75109c8be5cd7d15fb530238040148d5f9a22d4c5b3b" [[package]] name = "js-sys" -version = "0.3.57" +version = "0.3.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" +checksum = "c3fac17f7123a73ca62df411b1bf727ccc805daa070338fda671c86dac1bdc27" dependencies = [ "wasm-bindgen", ] @@ -2046,15 +1771,6 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9b7d56ba4a8344d6be9729995e6b06f928af29998cdf79fe390cbf6b1fee838" -[[package]] -name = "kv-log-macro" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" -dependencies = [ - "log", -] - [[package]] name = "lazy_static" version = "1.4.0" @@ -2084,23 +1800,10 @@ dependencies = [ "lettre", "mime", "regex", - "time 0.1.44", + "time", "uuid 0.8.2", ] -[[package]] -name = "lexical-core" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" -dependencies = [ - "arrayvec", - "bitflags", - "cfg-if 1.0.0", - "ryu", - "static_assertions", -] - [[package]] name = "libc" version = "0.2.126" @@ -2127,9 +1830,9 @@ dependencies = [ [[package]] name = "linked-hash-map" -version = "0.5.4" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" @@ -2154,7 +1857,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if 1.0.0", - "value-bag", ] [[package]] @@ -2222,14 +1924,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" [[package]] -name = "mime_guess" -version = "2.0.4" +name = "minimal-lexical" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" -dependencies = [ - "mime", - "unicase", -] +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" @@ -2240,6 +1938,18 @@ dependencies = [ "adler", ] +[[package]] +name = "mio" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" +dependencies = [ + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys", +] + [[package]] name = "mutate_once" version = "0.1.1" @@ -2298,26 +2008,12 @@ dependencies = [ [[package]] name = "nom" -version = "5.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" -dependencies = [ - "lexical-core", - "memchr", - "version_check 0.9.4", -] - -[[package]] -name = "nom" -version = "6.1.2" +version = "7.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2" +checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" dependencies = [ - "bitvec", - "funty", - "lexical-core", "memchr", - "version_check 0.9.4", + "minimal-lexical", ] [[package]] @@ -2384,9 +2080,9 @@ dependencies = [ [[package]] name = "num-rational" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" dependencies = [ "autocfg 1.1.0", "num-integer", @@ -2473,18 +2169,18 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-src" -version = "111.20.0+1.1.1o" +version = "111.21.0+1.1.1p" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92892c4f87d56e376e469ace79f1128fdaded07646ddf73aa0be4706ff712dec" +checksum = "6d0a8313729211913936f1b95ca47a5fc7f2e04cd658c115388287f8a8361008" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.73" +version = "0.9.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5fd19fb3e0a8191c1e34935718976a3e70c112ab9a24af6d7cadccd9d90bc0" +checksum = "835363342df5fba8354c5b453325b110ffd54044e588c539cf2f20a8014e4cb1" dependencies = [ "autocfg 1.1.0", "cc", @@ -2505,19 +2201,20 @@ dependencies = [ [[package]] name = "ouroboros" -version = "0.9.5" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeff60e3e37407a80ead3e9458145b456e978c4068cddbfea6afb48572962ca" +checksum = "9f31a3b678685b150cba82b702dcdc5e155893f63610cf388d30cd988d4ca2bf" dependencies = [ + "aliasable", "ouroboros_macro", "stable_deref_trait", ] [[package]] name = "ouroboros_macro" -version = "0.9.5" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03f2cb802b5bdfdf52f1ffa0b54ce105e4d346e91990dd571f86c91321ad49e2" +checksum = "084fd65d5dd8b3772edccb5ffd1e4b7eba43897ecd0f9401e330e8c542959408" dependencies = [ "Inflector", "proc-macro-error", @@ -2541,17 +2238,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.5", -] - [[package]] name = "parking_lot" version = "0.12.1" @@ -2559,21 +2245,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.3", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" -dependencies = [ - "cfg-if 1.0.0", - "instant", - "libc", - "redox_syscall", - "smallvec", - "winapi", + "parking_lot_core", ] [[package]] @@ -2586,7 +2258,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-sys 0.36.1", + "windows-sys", ] [[package]] @@ -2734,30 +2406,6 @@ dependencies = [ "miniz_oxide", ] -[[package]] -name = "polling" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685404d509889fade3e86fe3a5803bca2ec09b0c0778d5ada6ec8bf7a8de5259" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "log", - "wepoll-ffi", - "winapi", -] - -[[package]] -name = "polyval" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eebcc4aa140b9abd2bc40d9c3f7ccec842679cd79045ac3a7ac698c1a064b7cd" -dependencies = [ - "cpuid-bool", - "opaque-debug", - "universal-hash", -] - [[package]] name = "ppv-lite86" version = "0.2.16" @@ -2798,17 +2446,11 @@ dependencies = [ "version_check 0.9.4", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" - [[package]] name = "proc-macro2" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" dependencies = [ "unicode-ident", ] @@ -2859,9 +2501,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" dependencies = [ "proc-macro2", ] @@ -2874,12 +2516,12 @@ checksum = "3fee2dce59f7a43418e3382c766554c614e06a552d53a8f07ef499ea4b332c0f" [[package]] name = "r2d2" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "545c5bc2b880973c9c10e4067418407a0ccaa3091781d1671d46eb35107cb26f" +checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" dependencies = [ "log", - "parking_lot 0.11.2", + "parking_lot", "scheduled-thread-pool", ] @@ -2893,12 +2535,6 @@ dependencies = [ "rusqlite", ] -[[package]] -name = "radium" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" - [[package]] name = "radix_trie" version = "0.2.1" @@ -2969,7 +2605,7 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ - "getrandom 0.2.6", + "getrandom 0.2.7", ] [[package]] @@ -3029,7 +2665,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom 0.2.6", + "getrandom 0.2.7", "redox_syscall", "thiserror", ] @@ -3066,6 +2702,43 @@ dependencies = [ "winapi", ] +[[package]] +name = "reqwest" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b75aa69a3f06bbcc66ede33af2af253c6f7a86b1ca0033f60c580a27074fbf92" +dependencies = [ + "base64 0.13.0", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "lazy_static", + "log", + "mime", + "native-tls", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg 0.10.1", +] + [[package]] name = "resolv-conf" version = "0.7.0" @@ -3138,41 +2811,32 @@ checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" [[package]] name = "rustc_version" -version = "0.2.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 0.9.0", -] - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver 1.0.9", + "semver", ] [[package]] name = "rustix" -version = "0.34.8" +version = "0.35.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2079c267b8394eb529872c3cf92e181c378b41fea36e68130357b52493701d2e" +checksum = "ef258c11e17f5c01979a10543a30a4e12faef6aab217a74266e747eefa3aed88" dependencies = [ "bitflags", "errno", "io-lifetimes", "libc", "linux-raw-sys", - "winapi", + "windows-sys", ] [[package]] name = "rustversion" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" +checksum = "a0a5f7c728f5d284929a1cccb5bc19884422bfe6ef4d6c409da2c41838983fcf" [[package]] name = "rustyline" @@ -3236,7 +2900,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" dependencies = [ "lazy_static", - "windows-sys 0.36.1", + "windows-sys", ] [[package]] @@ -3245,7 +2909,7 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "977a7519bff143a44f842fd07e80ad1329295bd71686457f18e496736f4bf9bf" dependencies = [ - "parking_lot 0.12.1", + "parking_lot", ] [[package]] @@ -3279,24 +2943,9 @@ dependencies = [ [[package]] name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd" - -[[package]] -name = "semver-parser" -version = "0.7.0" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +checksum = "a41d061efea015927ac527063765e73601444cdc344ba855bc7bd44578b25e1c" [[package]] name = "serde" @@ -3339,17 +2988,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_qs" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7715380eec75f029a4ef7de39a9200e0a63823176b759d055b613f5a87df6a6" -dependencies = [ - "percent-encoding", - "serde", - "thiserror", -] - [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -3386,21 +3024,6 @@ dependencies = [ "digest 0.10.3", ] -[[package]] -name = "sha1" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" -dependencies = [ - "sha1_smol", -] - -[[package]] -name = "sha1_smol" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" - [[package]] name = "sha2" version = "0.9.9" @@ -3437,40 +3060,12 @@ dependencies = [ "opaque-debug", ] -[[package]] -name = "signal-hook" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d" -dependencies = [ - "libc", - "signal-hook-registry", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" -dependencies = [ - "libc", -] - [[package]] name = "signature" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f054c6c1a6e95179d6f23ed974060dcefb2d9388bb7256900badad682c499de4" -[[package]] -name = "simple-mutex" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38aabbeafa6f6dead8cebf246fe9fae1f9215c8d29b3a69f93bd62a9e4a3dcd6" -dependencies = [ - "event-listener", -] - [[package]] name = "simple_asn1" version = "0.4.1" @@ -3490,9 +3085,9 @@ checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" [[package]] name = "smallvec" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" +checksum = "cc88c725d61fc6c3132893370cac4a0200e3fedf5da8331c570664b1987f5ca2" [[package]] name = "smawk" @@ -3522,70 +3117,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" -[[package]] -name = "standback" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" -dependencies = [ - "version_check 0.9.4", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "stdweb" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" -dependencies = [ - "discard", - "rustc_version 0.2.3", - "stdweb-derive", - "stdweb-internal-macros", - "stdweb-internal-runtime", - "wasm-bindgen", -] - -[[package]] -name = "stdweb-derive" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "serde_derive", - "syn", -] - -[[package]] -name = "stdweb-internal-macros" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" -dependencies = [ - "base-x", - "proc-macro2", - "quote", - "serde", - "serde_derive", - "serde_json", - "sha1", - "syn", -] - -[[package]] -name = "stdweb-internal-runtime" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" - [[package]] name = "stop-token" version = "0.7.0" @@ -3612,15 +3143,15 @@ checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" [[package]] name = "strum" -version = "0.24.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96acfc1b70604b8b2f1ffa4c57e59176c7dbb05d556c71ecd2f5498a1dee7f8" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" [[package]] name = "strum_macros" -version = "0.24.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6878079b17446e4d3eba6192bb0a2950d5b14f0ed8424b852310e5a94345d0ef" +checksum = "4faebde00e8ff94316c01800f9054fd2ba77d30d9e922541913051d1d978918b" dependencies = [ "heck", "proc-macro2", @@ -3635,33 +3166,11 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" -[[package]] -name = "surf" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718b1ae6b50351982dedff021db0def601677f2120938b070eadb10ba4038dd7" -dependencies = [ - "async-native-tls", - "async-std", - "async-trait", - "cfg-if 1.0.0", - "futures-util", - "getrandom 0.2.6", - "http-client", - "http-types", - "log", - "mime_guess", - "once_cell", - "pin-project-lite", - "serde", - "serde_json", -] - [[package]] name = "syn" -version = "1.0.95" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" dependencies = [ "proc-macro2", "quote", @@ -3686,12 +3195,6 @@ version = "4.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77dd78fc7dd20ba3a13620ec231cef9e73ea5c7ba162f6c4e05b1d521e04b221" -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - [[package]] name = "tempfile" version = "3.3.0" @@ -3767,75 +3270,107 @@ dependencies = [ ] [[package]] -name = "time" -version = "0.2.27" +name = "tinytemplate" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" dependencies = [ - "const_fn", - "libc", - "standback", - "stdweb", - "time-macros", - "version_check 0.9.4", - "winapi", + "serde", + "serde_json", ] [[package]] -name = "time-macros" -version = "0.1.1" +name = "tinyvec" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ - "proc-macro-hack", - "time-macros-impl", + "tinyvec_macros", ] [[package]] -name = "time-macros-impl" -version = "0.1.2" +name = "tinyvec_macros" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "tokio" +version = "1.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c51a52ed6686dd62c320f9b89299e9dfb46f730c7a48e635c19f21d116cb1439" +dependencies = [ + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "once_cell", + "pin-project-lite", + "socket2", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" dependencies = [ - "proc-macro-hack", "proc-macro2", "quote", - "standback", "syn", ] [[package]] -name = "tinytemplate" -version = "1.2.1" +name = "tokio-native-tls" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" dependencies = [ - "serde", - "serde_json", + "native-tls", + "tokio", ] [[package]] -name = "tinyvec" -version = "1.6.0" +name = "tokio-stream" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "df54d54117d6fdc4e4fea40fe1e4e566b3505700e148a6827e59b34b0d2600d9" dependencies = [ - "tinyvec_macros", + "futures-core", + "pin-project-lite", + "tokio", ] [[package]] -name = "tinyvec_macros" -version = "0.1.0" +name = "tokio-tar" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +checksum = "a50188549787c32c1c3d9c8c71ad7e003ccf2f102489c5a96e385c84760477f4" +dependencies = [ + "filetime", + "futures-core", + "libc", + "redox_syscall", + "tokio", + "tokio-stream", + "xattr", +] [[package]] -name = "tokio" -version = "1.18.2" +name = "tokio-util" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4903bf0427cf68dddd5aa6a93220756f8be0c34fcfa9f5e6191e103e15a31395" +checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45" dependencies = [ + "bytes", + "futures-core", + "futures-sink", "pin-project-lite", + "tokio", + "tracing", ] [[package]] @@ -3847,6 +3382,32 @@ dependencies = [ "serde", ] +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" +dependencies = [ + "cfg-if 1.0.0", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" +dependencies = [ + "once_cell", +] + [[package]] name = "trust-dns-proto" version = "0.21.2" @@ -3868,6 +3429,7 @@ dependencies = [ "smallvec", "thiserror", "tinyvec", + "tokio", "url", ] @@ -3883,13 +3445,20 @@ dependencies = [ "lazy_static", "log", "lru-cache", - "parking_lot 0.12.1", + "parking_lot", "resolv-conf", "smallvec", "thiserror", + "tokio", "trust-dns-proto", ] +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + [[package]] name = "try_from" version = "0.3.2" @@ -3916,15 +3485,6 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" -[[package]] -name = "unicase" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" -dependencies = [ - "version_check 0.9.4", -] - [[package]] name = "unicode-bidi" version = "0.3.8" @@ -3933,9 +3493,9 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" [[package]] name = "unicode-ident" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" [[package]] name = "unicode-linebreak" @@ -3948,9 +3508,9 @@ dependencies = [ [[package]] name = "unicode-normalization" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +checksum = "81dee68f85cab8cf68dec42158baf3a79a1cdc065a8b103025965d6ccb7f6cbd" dependencies = [ "tinyvec", ] @@ -3973,16 +3533,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" -[[package]] -name = "universal-hash" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "url" version = "2.2.2" @@ -3993,7 +3543,6 @@ dependencies = [ "idna", "matches", "percent-encoding", - "serde", ] [[package]] @@ -4008,29 +3557,19 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" dependencies = [ - "getrandom 0.2.6", + "getrandom 0.2.7", ] [[package]] name = "uuid" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6d5d669b51467dcf7b2f1a796ce0f955f05f01cafda6c19d6e95f730df29238" +checksum = "dd6469f4314d5f1ffec476e05f17cc9a78bc7a27a6a857842170bdf8d6f98d2f" dependencies = [ - "getrandom 0.2.6", + "getrandom 0.2.7", "serde", ] -[[package]] -name = "value-bag" -version = "1.0.0-alpha.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2209b78d1249f7e6f3293657c9779fe31ced465df091bbd433a1cf88e916ec55" -dependencies = [ - "ctor", - "version_check 0.9.4", -] - [[package]] name = "vcpkg" version = "0.2.15" @@ -4066,6 +3605,16 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" @@ -4078,11 +3627,17 @@ version = "0.10.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + [[package]] name = "wasm-bindgen" -version = "0.2.80" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" +checksum = "7c53b543413a17a202f4be280a7e5c62a1c69345f5de525ee64f8cfdbc954994" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -4090,9 +3645,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.80" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" +checksum = "5491a68ab4500fa6b4d726bd67408630c3dbe9c4fe7bda16d5c82a1fd8c7340a" dependencies = [ "bumpalo", "lazy_static", @@ -4105,9 +3660,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.30" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f741de44b75e14c35df886aff5f1eb73aa114fa5d4d00dcd37b5e01259bf3b2" +checksum = "de9a9cec1733468a8c657e57fa2413d2ae2c0129b95e87c5b72b8ace4d13f31f" dependencies = [ "cfg-if 1.0.0", "js-sys", @@ -4117,9 +3672,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.80" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" +checksum = "c441e177922bc58f1e12c022624b6216378e5febc2f0533e41ba443d505b80aa" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4127,9 +3682,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.80" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" +checksum = "7d94ac45fcf608c1f45ef53e748d35660f168490c10b23704c7779ab8f5c3048" dependencies = [ "proc-macro2", "quote", @@ -4140,15 +3695,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.80" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" +checksum = "6a89911bd99e5f3659ec4acf9c4d93b0a90fe4a2a11f15328472058edc5261be" [[package]] name = "web-sys" -version = "0.3.57" +version = "0.3.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283" +checksum = "2fed94beee57daf8dd7d51f2b15dc2bcde92d7a72304cdf662a4371008b71b90" dependencies = [ "js-sys", "wasm-bindgen", @@ -4160,15 +3715,6 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c97e489d8f836838d497091de568cf16b117486d529ec5579233521065bd5e4" -[[package]] -name = "wepoll-ffi" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" -dependencies = [ - "cc", -] - [[package]] name = "widestring" version = "0.5.1" @@ -4206,86 +3752,43 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-sys" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "030b7ff91626e57a05ca64a07c481973cbb2db774e4852c9c7ca342408c6a99a" -dependencies = [ - "windows_aarch64_msvc 0.30.0", - "windows_i686_gnu 0.30.0", - "windows_i686_msvc 0.30.0", - "windows_x86_64_gnu 0.30.0", - "windows_x86_64_msvc 0.30.0", -] - [[package]] name = "windows-sys" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" dependencies = [ - "windows_aarch64_msvc 0.36.1", - "windows_i686_gnu 0.36.1", - "windows_i686_msvc 0.36.1", - "windows_x86_64_gnu 0.36.1", - "windows_x86_64_msvc 0.36.1", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_msvc" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29277a4435d642f775f63c7d1faeb927adba532886ce0287bd985bffb16b6bca" - [[package]] name = "windows_aarch64_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" -[[package]] -name = "windows_i686_gnu" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1145e1989da93956c68d1864f32fb97c8f561a8f89a5125f6a2b7ea75524e4b8" - [[package]] name = "windows_i686_gnu" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" -[[package]] -name = "windows_i686_msvc" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a09e3a0d4753b73019db171c1339cd4362c8c44baf1bcea336235e955954a6" - [[package]] name = "windows_i686_msvc" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" -[[package]] -name = "windows_x86_64_gnu" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca64fcb0220d58db4c119e050e7af03c69e6f4f415ef69ec1773d9aab422d5a" - [[package]] name = "windows_x86_64_gnu" version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" -[[package]] -name = "windows_x86_64_msvc" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08cabc9f0066848fef4bc6a1c1668e6efce38b661d2aeec75d18d8617eebb5f1" - [[package]] name = "windows_x86_64_msvc" version = "0.36.1" @@ -4302,10 +3805,13 @@ dependencies = [ ] [[package]] -name = "wyz" -version = "0.2.0" +name = "winreg" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] [[package]] name = "x25519-dalek" @@ -4318,6 +3824,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "xattr" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" +dependencies = [ + "libc", +] + [[package]] name = "zeroize" version = "1.3.0" @@ -4338,15 +3853,3 @@ dependencies = [ "syn", "synstructure", ] - -[[package]] -name = "zip" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf225bcf73bb52cbb496e70475c7bd7a3f769df699c0020f6c7bd9a96dcf0b8d" -dependencies = [ - "byteorder", - "crc32fast", - "crossbeam-utils", - "flate2", -] diff --git a/Cargo.toml b/Cargo.toml index c178f76f12..139735bc35 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ rust-version = "1.56" [profile.dev] debug = 0 panic = 'abort' +opt-level = 1 [profile.release] lto = true @@ -19,19 +20,19 @@ deltachat_derive = { path = "./deltachat_derive" } ansi_term = { version = "0.12.1", optional = true } anyhow = "1" -async-imap = { git = "https://github.com/async-email/async-imap" } -async-native-tls = { version = "0.3" } -async-smtp = { git = "https://github.com/async-email/async-smtp", branch="master", default-features=false, features = ["smtp-transport", "socks5"] } -async-std-resolver = "0.21" -async-std = { version = "1" } -async-tar = { version = "0.4", default-features=false } +async-imap = { version = "0.6", default-features = false, features = ["runtime-tokio"] } +async-native-tls = { version = "0.4", default-features = false, features = ["runtime-tokio"] } +async-smtp = { version = "0.5", default-features = false, features = ["smtp-transport", "socks5", "runtime-tokio"] } +trust-dns-resolver = "0.21" +tokio = { version = "1", features = ["fs", "rt-multi-thread", "macros"] } +tokio-tar = { version = "0.3" } # TODO: integrate tokio into async-tar backtrace = "0.3" base64 = "0.13" bitflags = "1.3" chrono = { version = "0.4", default-features=false, features = ["clock", "std"] } dirs = { version = "4", optional=true } email = { git = "https://github.com/deltachat/rust-email", branch = "master" } -encoded-words = { git = "https://github.com/async-email/encoded-words", branch="master" } +encoded-words = "0.2" escaper = "0.1" futures = "0.3" hex = "0.4.0" @@ -65,22 +66,24 @@ sha2 = "0.10" smallvec = "1" strum = "0.24" strum_macros = "0.24" -surf = { version = "2.3", default-features = false, features = ["h1-client"] } thiserror = "1" toml = "0.5" url = "2" uuid = { version = "1", features = ["serde", "v4"] } -fast-socks5 = "0.4" +fast-socks5 = "0.8" humansize = "1" qrcodegen = "1.7.0" tagger = "4.3.3" textwrap = "0.15.0" -zip = { version = "0.6.2", default-features = false, features = ["deflate"] } +async-channel = "1.6.1" +futures-lite = "1.12.0" +tokio-stream = { version = "0.1.9", features = ["fs"] } +reqwest = { version = "0.11.11", features = ["json"] } +async_zip = { git = "https://github.com/dignifiedquire/rs-async-zip", branch = "main", default-features = false, features = ["deflate"] } [dev-dependencies] ansi_term = "0.12.0" -async-std = { version = "1", features = ["unstable", "attributes"] } -criterion = { version = "0.3.4", features = ["async_std"] } +criterion = { version = "0.3.4", features = ["async_tokio"] } futures-lite = "1.12" log = "0.4" pretty_env_logger = "0.4" @@ -132,5 +135,10 @@ harness = false default = ["vendored"] internals = [] repl = ["internals", "rustyline", "log", "pretty_env_logger", "ansi_term", "dirs"] -vendored = ["async-native-tls/vendored", "async-smtp/native-tls-vendored", "rusqlite/bundled-sqlcipher-vendored-openssl"] +vendored = [ + "async-native-tls/vendored", + "async-smtp/native-tls-vendored", + "rusqlite/bundled-sqlcipher-vendored-openssl", + "reqwest/native-tls-vendored" +] nightly = ["pgp/nightly"] diff --git a/benches/contacts.rs b/benches/contacts.rs index 0c4b0a76ea..130988b8c4 100644 --- a/benches/contacts.rs +++ b/benches/contacts.rs @@ -1,4 +1,3 @@ -use async_std::task::block_on; use criterion::{black_box, criterion_group, criterion_main, Criterion}; use deltachat::contact::Contact; use deltachat::context::Context; @@ -9,9 +8,7 @@ async fn address_book_benchmark(n: u32, read_count: u32) { let dir = tempdir().unwrap(); let dbfile = dir.path().join("db.sqlite"); let id = 100; - let context = Context::new(dbfile.into(), id, Events::new()) - .await - .unwrap(); + let context = Context::new(&dbfile, id, Events::new()).await.unwrap(); let book = (0..n) .map(|i| format!("Name {}\naddr{}@example.org\n", i, i)) @@ -27,12 +24,16 @@ async fn address_book_benchmark(n: u32, read_count: u32) { } fn criterion_benchmark(c: &mut Criterion) { + let rt = tokio::runtime::Runtime::new().unwrap(); + c.bench_function("create 500 contacts", |b| { - b.iter(|| block_on(async { address_book_benchmark(black_box(500), black_box(0)).await })) + b.to_async(&rt) + .iter(|| async { address_book_benchmark(black_box(500), black_box(0)).await }) }); c.bench_function("create 100 contacts and read it 1000 times", |b| { - b.iter(|| block_on(async { address_book_benchmark(black_box(100), black_box(1000)).await })) + b.to_async(&rt) + .iter(|| async { address_book_benchmark(black_box(100), black_box(1000)).await }) }); } diff --git a/benches/create_account.rs b/benches/create_account.rs index 531d8ead8c..56f8877d60 100644 --- a/benches/create_account.rs +++ b/benches/create_account.rs @@ -1,12 +1,11 @@ -use async_std::path::PathBuf; -use async_std::task::block_on; use criterion::{black_box, criterion_group, criterion_main, Criterion}; use deltachat::accounts::Accounts; +use std::path::PathBuf; use tempfile::tempdir; async fn create_accounts(n: u32) { let dir = tempdir().unwrap(); - let p: PathBuf = dir.path().join("accounts").into(); + let p: PathBuf = dir.path().join("accounts"); let mut accounts = Accounts::new(p.clone()).await.unwrap(); @@ -18,7 +17,8 @@ async fn create_accounts(n: u32) { fn criterion_benchmark(c: &mut Criterion) { c.bench_function("create 1 account", |b| { - b.iter(|| block_on(async { create_accounts(black_box(1)).await })) + let rt = tokio::runtime::Runtime::new().unwrap(); + b.to_async(&rt).iter(|| create_accounts(black_box(1))) }); } diff --git a/benches/get_chat_msgs.rs b/benches/get_chat_msgs.rs index 252f8eab59..2c81094b44 100644 --- a/benches/get_chat_msgs.rs +++ b/benches/get_chat_msgs.rs @@ -1,6 +1,5 @@ -use async_std::path::Path; +use std::path::Path; -use criterion::async_executor::AsyncStdExecutor; use criterion::{black_box, criterion_group, criterion_main, Criterion}; use deltachat::chat::{self, ChatId}; @@ -10,9 +9,7 @@ use deltachat::Events; async fn get_chat_msgs_benchmark(dbfile: &Path, chats: &[ChatId]) { let id = 100; - let context = Context::new(dbfile.into(), id, Events::new()) - .await - .unwrap(); + let context = Context::new(dbfile, id, Events::new()).await.unwrap(); for c in chats.iter().take(10) { black_box(chat::get_chat_msgs(&context, *c, 0).await.ok()); @@ -23,8 +20,10 @@ fn criterion_benchmark(c: &mut Criterion) { // To enable this benchmark, set `DELTACHAT_BENCHMARK_DATABASE` to some large database with many // messages, such as your primary account. if let Ok(path) = std::env::var("DELTACHAT_BENCHMARK_DATABASE") { - let chats: Vec<_> = async_std::task::block_on(async { - let context = Context::new((&path).into(), 100, Events::new()) + let rt = tokio::runtime::Runtime::new().unwrap(); + + let chats: Vec<_> = rt.block_on(async { + let context = Context::new(Path::new(&path), 100, Events::new()) .await .unwrap(); let chatlist = Chatlist::try_load(&context, 0, None, None).await.unwrap(); @@ -33,7 +32,7 @@ fn criterion_benchmark(c: &mut Criterion) { }); c.bench_function("chat::get_chat_msgs (load messages from 10 chats)", |b| { - b.to_async(AsyncStdExecutor) + b.to_async(&rt) .iter(|| get_chat_msgs_benchmark(black_box(path.as_ref()), black_box(&chats))) }); } else { diff --git a/benches/get_chatlist.rs b/benches/get_chatlist.rs index 57e7579c5e..25dd09cab7 100644 --- a/benches/get_chatlist.rs +++ b/benches/get_chatlist.rs @@ -1,4 +1,5 @@ -use criterion::async_executor::AsyncStdExecutor; +use std::path::Path; + use criterion::{black_box, criterion_group, criterion_main, Criterion}; use deltachat::chatlist::Chatlist; @@ -13,11 +14,14 @@ fn criterion_benchmark(c: &mut Criterion) { // To enable this benchmark, set `DELTACHAT_BENCHMARK_DATABASE` to some large database with many // messages, such as your primary account. if let Ok(path) = std::env::var("DELTACHAT_BENCHMARK_DATABASE") { - let context = async_std::task::block_on(async { - Context::new(path.into(), 100, Events::new()).await.unwrap() + let rt = tokio::runtime::Runtime::new().unwrap(); + let context = rt.block_on(async { + Context::new(Path::new(&path), 100, Events::new()) + .await + .unwrap() }); c.bench_function("chatlist:try_load (Get Chatlist)", |b| { - b.to_async(AsyncStdExecutor) + b.to_async(&rt) .iter(|| get_chat_list_benchmark(black_box(&context))) }); } else { diff --git a/benches/receive_emails.rs b/benches/receive_emails.rs index 11bf8cf834..4fde0c80c7 100644 --- a/benches/receive_emails.rs +++ b/benches/receive_emails.rs @@ -1,8 +1,6 @@ -use async_std::{path::PathBuf, task::block_on}; -use criterion::{ - async_executor::AsyncStdExecutor, black_box, criterion_group, criterion_main, BatchSize, - Criterion, -}; +use std::path::PathBuf; + +use criterion::{black_box, criterion_group, criterion_main, Criterion}; use deltachat::{ config::Config, context::Context, @@ -43,15 +41,13 @@ async fn create_context() -> Context { let dir = tempdir().unwrap(); let dbfile = dir.path().join("db.sqlite"); let id = 100; - let context = Context::new(dbfile.into(), id, Events::new()) - .await - .unwrap(); + let context = Context::new(&dbfile, id, Events::new()).await.unwrap(); let backup: PathBuf = std::env::current_dir() .unwrap() - .join("delta-chat-backup.tar") - .into(); - if backup.exists().await { + .join("delta-chat-backup.tar"); + + if backup.exists() { println!("Importing backup"); imex(&context, ImexMode::ImportBackup, &backup, None) .await @@ -74,11 +70,15 @@ async fn create_context() -> Context { fn criterion_benchmark(c: &mut Criterion) { let mut group = c.benchmark_group("Receive messages"); group.bench_function("Receive 100 simple text msgs", |b| { - b.to_async(AsyncStdExecutor).iter_batched( - || block_on(create_context()), - |context| recv_all_emails(black_box(context)), - BatchSize::LargeInput, - ); + let rt = tokio::runtime::Runtime::new().unwrap(); + let context = rt.block_on(create_context()); + + b.to_async(&rt).iter(|| { + let ctx = context.clone(); + async move { + recv_all_emails(black_box(ctx)).await; + } + }); }); group.finish(); } diff --git a/benches/search_msgs.rs b/benches/search_msgs.rs index 45215e11b3..a912195422 100644 --- a/benches/search_msgs.rs +++ b/benches/search_msgs.rs @@ -1,13 +1,11 @@ -use async_std::task::block_on; use criterion::{black_box, criterion_group, criterion_main, Criterion}; use deltachat::context::Context; use deltachat::Events; use std::path::Path; -async fn search_benchmark(path: impl AsRef) { - let dbfile = path.as_ref(); +async fn search_benchmark(dbfile: impl AsRef) { let id = 100; - let context = Context::new(dbfile.into(), id, Events::new()) + let context = Context::new(dbfile.as_ref(), id, Events::new()) .await .unwrap(); @@ -20,8 +18,10 @@ fn criterion_benchmark(c: &mut Criterion) { // To enable this benchmark, set `DELTACHAT_BENCHMARK_DATABASE` to some large database with many // messages, such as your primary account. if let Ok(path) = std::env::var("DELTACHAT_BENCHMARK_DATABASE") { + let rt = tokio::runtime::Runtime::new().unwrap(); + c.bench_function("search hello", |b| { - b.iter(|| block_on(async { search_benchmark(black_box(&path)).await })) + b.to_async(&rt).iter(|| search_benchmark(black_box(&path))) }); } else { println!("env var not set: DELTACHAT_BENCHMARK_DATABASE"); diff --git a/deltachat-ffi/Cargo.toml b/deltachat-ffi/Cargo.toml index cad9a50881..f4d7b1cfd6 100644 --- a/deltachat-ffi/Cargo.toml +++ b/deltachat-ffi/Cargo.toml @@ -20,10 +20,11 @@ libc = "0.2" human-panic = "1" num-traits = "0.2" serde_json = "1.0" -async-std = "1" +tokio = { version = "1", features = ["rt-multi-thread"] } anyhow = "1" thiserror = "1" rand = "0.7" +once_cell = "1.12.0" [features] default = ["vendored"] diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index 5ca1877d53..c429aeed3e 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -15,17 +15,19 @@ extern crate human_panic; use std::collections::BTreeMap; use std::convert::TryFrom; use std::fmt::Write; +use std::future::Future; use std::ops::Deref; use std::ptr; use std::str::FromStr; use std::time::{Duration, SystemTime}; use anyhow::Context as _; -use async_std::sync::RwLock; -use async_std::task::{block_on, spawn}; use deltachat::qr_code_generator::get_securejoin_qr_svg; use num_traits::{FromPrimitive, ToPrimitive}; +use once_cell::sync::Lazy; use rand::Rng; +use tokio::runtime::Runtime; +use tokio::sync::RwLock; use deltachat::chat::{ChatId, ChatVisibility, MuteDuration, ProtectionStatus}; use deltachat::constants::DC_MSG_ID_LAST_SPECIAL; @@ -38,6 +40,7 @@ use deltachat::stock_str::StockMessage; use deltachat::webxdc::StatusUpdateSerial; use deltachat::*; use deltachat::{accounts::Accounts, log::LogExt}; +use tokio::task::JoinHandle; mod dc_array; mod lot; @@ -61,6 +64,23 @@ use deltachat::chatlist::Chatlist; /// Struct representing the deltachat context. pub type dc_context_t = Context; +static RT: Lazy = Lazy::new(|| Runtime::new().expect("unable to create tokio runtime")); + +fn block_on(fut: T) -> T::Output +where + T: Future, +{ + RT.block_on(fut) +} + +fn spawn(fut: T) -> JoinHandle +where + T: Future + Send + 'static, + T::Output: Send + 'static, +{ + RT.spawn(fut) +} + #[no_mangle] pub unsafe extern "C" fn dc_context_new( _os_name: *const libc::c_char, @@ -77,11 +97,7 @@ pub unsafe extern "C" fn dc_context_new( let ctx = if blobdir.is_null() || *blobdir == 0 { // generate random ID as this functionality is not yet available on the C-api. let id = rand::thread_rng().gen(); - block_on(Context::new( - as_path(dbfile).to_path_buf().into(), - id, - Events::new(), - )) + block_on(Context::new(as_path(dbfile), id, Events::new())) } else { eprintln!("blobdir can not be defined explicitly anymore"); return ptr::null_mut(); @@ -105,11 +121,7 @@ pub unsafe extern "C" fn dc_context_new_closed(dbfile: *const libc::c_char) -> * } let id = rand::thread_rng().gen(); - match block_on(Context::new_closed( - as_path(dbfile).to_path_buf().into(), - id, - Events::new(), - )) { + match block_on(Context::new_closed(as_path(dbfile), id, Events::new())) { Ok(context) => Box::into_raw(Box::new(context)), Err(err) => { eprintln!("failed to create context: {:#}", err); @@ -681,10 +693,13 @@ pub unsafe extern "C" fn dc_get_next_event(events: *mut dc_event_emitter_t) -> * } let events = &*events; - events - .recv_sync() - .map(|ev| Box::into_raw(Box::new(ev))) - .unwrap_or_else(ptr::null_mut) + block_on(async move { + events + .recv() + .await + .map(|ev| Box::into_raw(Box::new(ev))) + .unwrap_or_else(ptr::null_mut) + }) } #[no_mangle] @@ -2393,7 +2408,7 @@ pub unsafe extern "C" fn dc_get_last_error(context: *mut dc_context_t) -> *mut l return "".strdup(); } let ctx = &*context; - block_on(ctx.get_last_error()).strdup() + ctx.get_last_error().strdup() } // dc_array_t @@ -4126,7 +4141,7 @@ pub unsafe extern "C" fn dc_accounts_new( return ptr::null_mut(); } - let accs = block_on(Accounts::new(as_path(dbfile).to_path_buf().into())); + let accs = block_on(Accounts::new(as_path(dbfile).into())); match accs { Ok(accs) => Box::into_raw(Box::new(AccountsWrapper::new(accs))), @@ -4298,7 +4313,7 @@ pub unsafe extern "C" fn dc_accounts_migrate_account( block_on(async move { let mut accounts = accounts.write().await; match accounts - .migrate_account(async_std::path::PathBuf::from(dbfile)) + .migrate_account(std::path::PathBuf::from(dbfile)) .await { Ok(id) => id, @@ -4418,9 +4433,7 @@ pub unsafe extern "C" fn dc_accounts_get_next_event( return ptr::null_mut(); } let emitter = &mut *emitter; - - emitter - .recv_sync() + block_on(emitter.recv()) .map(|ev| Box::into_raw(Box::new(ev))) .unwrap_or_else(ptr::null_mut) } diff --git a/examples/repl/cmdline.rs b/examples/repl/cmdline.rs index f88a5eb48b..341e97f077 100644 --- a/examples/repl/cmdline.rs +++ b/examples/repl/cmdline.rs @@ -1,9 +1,10 @@ extern crate dirs; +use std::path::Path; use std::str::FromStr; +use std::time::{Duration, SystemTime}; use anyhow::{bail, ensure, Result}; -use async_std::path::Path; use deltachat::chat::{ self, Chat, ChatId, ChatItem, ChatVisibility, MuteDuration, ProtectionStatus, }; @@ -22,8 +23,7 @@ use deltachat::peerstate::*; use deltachat::qr::*; use deltachat::sql; use deltachat::{config, provider}; -use std::fs; -use std::time::{Duration, SystemTime}; +use tokio::fs; /// Reset database tables. /// Argument is a bitmask, executing single or multiple actions in one call. @@ -135,17 +135,13 @@ async fn poke_spec(context: &Context, spec: Option<&str>) -> bool { } else { /* import a directory */ let dir_name = std::path::Path::new(&real_spec); - let dir = std::fs::read_dir(dir_name); + let dir = fs::read_dir(dir_name).await; if dir.is_err() { error!(context, "Import: Cannot open directory \"{}\".", &real_spec,); return false; } else { - let dir = dir.unwrap(); - for entry in dir { - if entry.is_err() { - break; - } - let entry = entry.unwrap(); + let mut dir = dir.unwrap(); + while let Ok(Some(entry)) = dir.next_entry().await { let name_f = entry.file_name(); let name = name_f.to_string_lossy(); if name.ends_with(".eml") { @@ -492,7 +488,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu let setup_code = create_setup_code(&context); let file_name = blobdir.join("autocrypt-setup-message.html"); let file_content = render_setup_file(&context, &setup_code).await?; - async_std::fs::write(&file_name, file_content).await?; + fs::write(&file_name, file_content).await?; println!( "Setup message written to: {}\nSetup code: {}", file_name.display(), @@ -532,7 +528,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu .join("connectivity.html"); match context.get_connectivity_html().await { Ok(html) => { - fs::write(&file, html)?; + fs::write(&file, html).await?; println!("Report written to: {:#?}", file); } Err(err) => { @@ -892,7 +888,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu ensure!(sel_chat.is_some(), "No chat selected."); ensure!(!arg1.is_empty(), "No html-file given."); let path: &Path = arg1.as_ref(); - let html = &*fs::read(&path)?; + let html = &*fs::read(&path).await?; let html = String::from_utf8_lossy(html); let mut msg = Message::new(Viewtype::Text); @@ -1079,7 +1075,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu .unwrap_or_default() .join(format!("msg-{}.html", id.to_u32())); let html = id.get_html(&context).await?.unwrap_or_default(); - fs::write(&file, html)?; + fs::write(&file, html).await?; println!("HTML written to: {:#?}", file); } "listfresh" => { diff --git a/examples/repl/main.rs b/examples/repl/main.rs index 3df75f4eda..4c00418944 100644 --- a/examples/repl/main.rs +++ b/examples/repl/main.rs @@ -9,15 +9,16 @@ extern crate deltachat; use std::borrow::Cow::{self, Borrowed, Owned}; use std::io::{self, Write}; +use std::path::Path; use std::process::Command; use ansi_term::Color; use anyhow::{bail, Error}; -use async_std::path::Path; use deltachat::chat::ChatId; use deltachat::config; use deltachat::context::*; use deltachat::oauth2::*; +use deltachat::qr_code_generator::get_securejoin_qr_svg; use deltachat::securejoin::*; use deltachat::{EventType, Events}; use log::{error, info, warn}; @@ -30,11 +31,11 @@ use rustyline::validate::Validator; use rustyline::{ Cmd, CompletionType, Config, Context as RustyContext, EditMode, Editor, Helper, KeyEvent, }; +use tokio::fs; +use tokio::runtime::Handle; mod cmdline; use self::cmdline::*; -use deltachat::qr_code_generator::get_securejoin_qr_svg; -use std::fs; /// Event Handler fn receive_event(event: EventType) { @@ -298,10 +299,10 @@ async fn start(args: Vec) -> Result<(), Error> { println!("Error: Bad arguments, expected [db-name]."); bail!("No db-name specified"); } - let context = Context::new(Path::new(&args[1]).to_path_buf(), 0, Events::new()).await?; + let context = Context::new(Path::new(&args[1]), 0, Events::new()).await?; let events = context.get_event_emitter(); - async_std::task::spawn(async move { + tokio::task::spawn(async move { while let Some(event) = events.recv().await { receive_event(event.typ); } @@ -316,8 +317,9 @@ async fn start(args: Vec) -> Result<(), Error> { .output_stream(OutputStreamType::Stdout) .build(); let mut selected_chat = ChatId::default(); - let (reader_s, reader_r) = async_std::channel::bounded(100); - let input_loop = async_std::task::spawn_blocking(move || { + + let ctx = context.clone(); + let input_loop = tokio::task::spawn_blocking(move || { let h = DcHelper { completer: FilenameCompleter::new(), highlighter: MatchingBracketHighlighter::new(), @@ -339,16 +341,30 @@ async fn start(args: Vec) -> Result<(), Error> { Ok(line) => { // TODO: ignore "set mail_pw" rl.add_history_entry(line.as_str()); - async_std::task::block_on(reader_s.send(line)).unwrap(); + let contine = Handle::current().block_on(async { + match handle_cmd(line.trim(), ctx.clone(), &mut selected_chat).await { + Ok(ExitResult::Continue) => true, + Ok(ExitResult::Exit) => { + println!("Exiting ..."); + false + } + Err(err) => { + println!("Error: {}", err); + true + } + } + }); + + if !contine { + break; + } } Err(ReadlineError::Interrupted) | Err(ReadlineError::Eof) => { println!("Exiting..."); - drop(reader_s); break; } Err(err) => { println!("Error: {}", err); - drop(reader_s); break; } } @@ -359,15 +375,8 @@ async fn start(args: Vec) -> Result<(), Error> { Ok::<_, Error>(()) }); - while let Ok(line) = reader_r.recv().await { - match handle_cmd(line.trim(), context.clone(), &mut selected_chat).await { - Ok(ExitResult::Continue) => {} - Ok(ExitResult::Exit) => break, - Err(err) => println!("Error: {}", err), - } - } context.stop_io().await; - input_loop.await?; + input_loop.await??; Ok(()) } @@ -437,7 +446,7 @@ async fn handle_cmd( let file = dirs::home_dir().unwrap_or_default().join("qr.svg"); match get_securejoin_qr_svg(&ctx, group).await { Ok(svg) => { - fs::write(&file, svg)?; + fs::write(&file, svg).await?; println!("QR code svg written to: {:#?}", file); } Err(err) => { @@ -458,11 +467,12 @@ async fn handle_cmd( Ok(ExitResult::Continue) } -fn main() -> Result<(), Error> { +#[tokio::main] +async fn main() -> Result<(), Error> { let _ = pretty_env_logger::try_init(); let args = std::env::args().collect(); - async_std::task::block_on(async move { start(args).await })?; + start(args).await?; Ok(()) } diff --git a/examples/simple.rs b/examples/simple.rs index b552585b91..2d9ef4b0ae 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -29,21 +29,21 @@ fn cb(event: EventType) { } /// Run with `RUST_LOG=simple=info cargo run --release --example simple --features repl -- email pw`. -#[async_std::main] +#[tokio::main] async fn main() { pretty_env_logger::try_init_timed().ok(); let dir = tempdir().unwrap(); let dbfile = dir.path().join("db.sqlite"); log::info!("creating database {:?}", dbfile); - let ctx = Context::new(dbfile.into(), 0, Events::new()) + let ctx = Context::new(&dbfile, 0, Events::new()) .await .expect("Failed to create context"); let info = ctx.get_info().await; log::info!("info: {:#?}", info); let events = ctx.get_event_emitter(); - let events_spawn = async_std::task::spawn(async move { + let events_spawn = tokio::task::spawn(async move { while let Some(event) = events.recv().await { cb(event.typ); } @@ -80,7 +80,7 @@ async fn main() { } // wait for the message to be sent out - async_std::task::sleep(std::time::Duration::from_secs(1)).await; + tokio::time::sleep(std::time::Duration::from_secs(1)).await; log::info!("fetching chats.."); let chats = Chatlist::try_load(&ctx, 0, None, None).await.unwrap(); @@ -96,5 +96,5 @@ async fn main() { ctx.stop_io().await; log::info!("closing"); drop(ctx); - events_spawn.await; + events_spawn.await.unwrap(); } diff --git a/src/accounts.rs b/src/accounts.rs index c41891296a..28cdea7982 100644 --- a/src/accounts.rs +++ b/src/accounts.rs @@ -1,13 +1,12 @@ //! # Account manager module. use std::collections::BTreeMap; - -use async_std::fs; -use async_std::path::PathBuf; -use uuid::Uuid; +use std::path::{Path, PathBuf}; use anyhow::{ensure, Context as _, Result}; use serde::{Deserialize, Serialize}; +use tokio::fs; +use uuid::Uuid; use crate::context::Context; use crate::events::{Event, EventEmitter, EventType, Events}; @@ -26,7 +25,7 @@ pub struct Accounts { impl Accounts { /// Loads or creates an accounts folder at the given `dir`. pub async fn new(dir: PathBuf) -> Result { - if !dir.exists().await { + if !dir.exists() { Accounts::create(&dir).await?; } @@ -47,14 +46,10 @@ impl Accounts { /// Opens an existing accounts structure. Will error if the folder doesn't exist, /// no account exists and no config exists. pub async fn open(dir: PathBuf) -> Result { - ensure!(dir.exists().await, "directory does not exist"); + ensure!(dir.exists(), "directory does not exist"); let config_file = dir.join(CONFIG_NAME); - ensure!( - config_file.exists().await, - "{:?} does not exist", - config_file - ); + ensure!(config_file.exists(), "{:?} does not exist", config_file); let config = Config::from_file(config_file) .await @@ -106,7 +101,7 @@ impl Accounts { let account_config = self.config.new_account(&self.dir).await?; let ctx = Context::new( - account_config.dbfile().into(), + &account_config.dbfile(), account_config.id, self.events.clone(), ) @@ -121,7 +116,7 @@ impl Accounts { let account_config = self.config.new_account(&self.dir).await?; let ctx = Context::new_closed( - account_config.dbfile().into(), + &account_config.dbfile(), account_config.id, self.events.clone(), ) @@ -148,7 +143,7 @@ impl Accounts { loop { counter += 1; - if let Err(err) = fs::remove_dir_all(async_std::path::PathBuf::from(&cfg.dir)) + if let Err(err) = fs::remove_dir_all(&cfg.dir) .await .context("failed to remove account data") { @@ -157,7 +152,7 @@ impl Accounts { } // Wait 1 second and try again. - async_std::task::sleep(std::time::Duration::from_millis(1000)).await; + tokio::time::sleep(std::time::Duration::from_millis(1000)).await; } else { break; } @@ -173,16 +168,8 @@ impl Accounts { let blobdir = Context::derive_blobdir(&dbfile); let walfile = Context::derive_walfile(&dbfile); - ensure!( - dbfile.exists().await, - "no database found: {}", - dbfile.display() - ); - ensure!( - blobdir.exists().await, - "no blobdir found: {}", - blobdir.display() - ); + ensure!(dbfile.exists(), "no database found: {}", dbfile.display()); + ensure!(blobdir.exists(), "no blobdir found: {}", blobdir.display()); let old_id = self.config.get_selected_account().await; @@ -193,7 +180,7 @@ impl Accounts { .await .context("failed to create new account")?; - let new_dbfile = account_config.dbfile().into(); + let new_dbfile = account_config.dbfile(); let new_blobdir = Context::derive_blobdir(&new_dbfile); let new_walfile = Context::derive_walfile(&new_dbfile); @@ -207,7 +194,7 @@ impl Accounts { fs::rename(&blobdir, &new_blobdir) .await .context("failed to rename blobdir")?; - if walfile.exists().await { + if walfile.exists() { fs::rename(&walfile, &new_walfile) .await .context("failed to rename walfile")?; @@ -217,13 +204,13 @@ impl Accounts { match res { Ok(_) => { - let ctx = Context::new(new_dbfile, account_config.id, self.events.clone()).await?; + let ctx = Context::new(&new_dbfile, account_config.id, self.events.clone()).await?; self.accounts.insert(account_config.id, ctx); Ok(account_config.id) } Err(err) => { // remove temp account - fs::remove_dir_all(async_std::path::PathBuf::from(&account_config.dir)) + fs::remove_dir_all(std::path::PathBuf::from(&account_config.dir)) .await .context("failed to remove account data")?; @@ -321,7 +308,7 @@ struct InnerConfig { } impl Config { - pub async fn new(dir: &PathBuf) -> Result { + pub async fn new(dir: &Path) -> Result { let inner = InnerConfig { accounts: Vec::new(), selected_account: 0, @@ -355,18 +342,14 @@ impl Config { pub async fn load_accounts(&self, events: &Events) -> Result> { let mut accounts = BTreeMap::new(); for account_config in &self.inner.accounts { - let ctx = Context::new( - account_config.dbfile().into(), - account_config.id, - events.clone(), - ) - .await - .with_context(|| { - format!( - "failed to create context from file {:?}", - account_config.dbfile() - ) - })?; + let ctx = Context::new(&account_config.dbfile(), account_config.id, events.clone()) + .await + .with_context(|| { + format!( + "failed to create context from file {:?}", + account_config.dbfile() + ) + })?; accounts.insert(account_config.id, ctx); } @@ -375,7 +358,7 @@ impl Config { } /// Create a new account in the given root directory. - async fn new_account(&mut self, dir: &PathBuf) -> Result { + async fn new_account(&mut self, dir: &Path) -> Result { let id = { let id = self.inner.next_id; let uuid = Uuid::new_v4(); @@ -383,7 +366,7 @@ impl Config { self.inner.accounts.push(AccountConfig { id, - dir: target_dir.into(), + dir: target_dir, uuid, }); self.inner.next_id += 1; @@ -464,10 +447,10 @@ impl AccountConfig { mod tests { use super::*; - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_account_new_open() { let dir = tempfile::tempdir().unwrap(); - let p: PathBuf = dir.path().join("accounts1").into(); + let p: PathBuf = dir.path().join("accounts1"); let mut accounts1 = Accounts::new(p.clone()).await.unwrap(); accounts1.add_account().await.unwrap(); @@ -482,10 +465,10 @@ mod tests { assert_eq!(accounts1.accounts.len(), accounts2.accounts.len()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_account_new_add_remove() { let dir = tempfile::tempdir().unwrap(); - let p: PathBuf = dir.path().join("accounts").into(); + let p: PathBuf = dir.path().join("accounts"); let mut accounts = Accounts::new(p.clone()).await.unwrap(); assert_eq!(accounts.accounts.len(), 0); @@ -509,10 +492,10 @@ mod tests { assert_eq!(accounts.accounts.len(), 1); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_accounts_remove_last() -> Result<()> { let dir = tempfile::tempdir()?; - let p: PathBuf = dir.path().join("accounts").into(); + let p: PathBuf = dir.path().join("accounts"); let mut accounts = Accounts::new(p.clone()).await?; assert!(accounts.get_selected_account().await.is_none()); @@ -530,17 +513,17 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_migrate_account() { let dir = tempfile::tempdir().unwrap(); - let p: PathBuf = dir.path().join("accounts").into(); + let p: PathBuf = dir.path().join("accounts"); let mut accounts = Accounts::new(p.clone()).await.unwrap(); assert_eq!(accounts.accounts.len(), 0); assert_eq!(accounts.config.get_selected_account().await, 0); - let extern_dbfile: PathBuf = dir.path().join("other").into(); - let ctx = Context::new(extern_dbfile.clone(), 0, Events::new()) + let extern_dbfile: PathBuf = dir.path().join("other"); + let ctx = Context::new(&extern_dbfile, 0, Events::new()) .await .unwrap(); ctx.set_config(crate::config::Config::Addr, Some("me@mail.com")) @@ -567,10 +550,10 @@ mod tests { } /// Tests that accounts are sorted by ID. - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_accounts_sorted() { let dir = tempfile::tempdir().unwrap(); - let p: PathBuf = dir.path().join("accounts").into(); + let p: PathBuf = dir.path().join("accounts"); let mut accounts = Accounts::new(p.clone()).await.unwrap(); @@ -585,10 +568,10 @@ mod tests { } } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_accounts_ids_unique_increasing_and_persisted() -> Result<()> { let dir = tempfile::tempdir()?; - let p: PathBuf = dir.path().join("accounts").into(); + let p: PathBuf = dir.path().join("accounts"); let dummy_accounts = 10; let (id0, id1, id2) = { @@ -667,10 +650,10 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_no_accounts_event_emitter() -> Result<()> { let dir = tempfile::tempdir().unwrap(); - let p: PathBuf = dir.path().join("accounts").into(); + let p: PathBuf = dir.path().join("accounts"); let accounts = Accounts::new(p.clone()).await?; @@ -682,7 +665,7 @@ mod tests { // Test that event emitter does not return `None` immediately. let duration = std::time::Duration::from_millis(1); - assert!(async_std::future::timeout(duration, event_emitter.recv()) + assert!(tokio::time::timeout(duration, event_emitter.recv()) .await .is_err()); @@ -693,10 +676,10 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_encrypted_account() -> Result<()> { let dir = tempfile::tempdir().context("failed to create tempdir")?; - let p: PathBuf = dir.path().join("accounts").into(); + let p: PathBuf = dir.path().join("accounts"); let mut accounts = Accounts::new(p.clone()) .await diff --git a/src/blob.rs b/src/blob.rs index 48268b226c..5d1cc5bd0f 100644 --- a/src/blob.rs +++ b/src/blob.rs @@ -4,14 +4,13 @@ use core::cmp::max; use std::ffi::OsStr; use std::fmt; use std::io::Cursor; - -use async_std::path::{Path, PathBuf}; -use async_std::prelude::*; -use async_std::{fs, io}; +use std::path::{Path, PathBuf}; use anyhow::{format_err, Context as _, Error, Result}; use image::{DynamicImage, ImageFormat}; use num_traits::FromPrimitive; +use tokio::io::AsyncWriteExt; +use tokio::{fs, io}; use crate::config::Config; use crate::constants::{ @@ -89,7 +88,7 @@ impl<'a> BlobObject<'a> { Err(err) => { if attempt >= MAX_ATTEMPT { return Err(err).context("failed to create file"); - } else if attempt == 1 && !dir.exists().await { + } else if attempt == 1 && !dir.exists() { fs::create_dir_all(dir).await.ok_or_log(context); } else { name = format!("{}-{}{}", stem, rand::random::(), ext); @@ -371,108 +370,81 @@ impl<'a> BlobObject<'a> { mut img_wh: u32, max_bytes: Option, ) -> Result> { - let mut img = image::open(&blob_abs).context("image recode failure")?; - let orientation = self.get_exif_orientation(context); - let mut encoded = Vec::new(); - let mut changed_name = None; - - fn encode_img(img: &DynamicImage, encoded: &mut Vec) -> anyhow::Result<()> { - encoded.clear(); - let mut buf = Cursor::new(encoded); - img.write_to(&mut buf, image::ImageFormat::Jpeg)?; - Ok(()) - } - fn encoded_img_exceeds_bytes( - context: &Context, - img: &DynamicImage, - max_bytes: Option, - encoded: &mut Vec, - ) -> anyhow::Result { - if let Some(max_bytes) = max_bytes { - encode_img(img, encoded)?; - if encoded.len() > max_bytes { - info!( - context, - "image size {}B ({}x{}px) exceeds {}B, need to scale down", - encoded.len(), - img.width(), - img.height(), - max_bytes, - ); - return Ok(true); - } - } - Ok(false) - } - let exceeds_width = img.width() > img_wh || img.height() > img_wh; - - let do_scale = - exceeds_width || encoded_img_exceeds_bytes(context, &img, max_bytes, &mut encoded)?; - let do_rotate = matches!(orientation, Ok(90) | Ok(180) | Ok(270)); - - if do_scale || do_rotate { - if do_rotate { - img = match orientation { - Ok(90) => img.rotate90(), - Ok(180) => img.rotate180(), - Ok(270) => img.rotate270(), - _ => img, - } - } - - if do_scale { - if !exceeds_width { - // The image is already smaller than img_wh, but exceeds max_bytes - // We can directly start with trying to scale down to 2/3 of its current width - img_wh = max(img.width(), img.height()) * 2 / 3 + tokio::task::block_in_place(move || { + let mut img = image::open(&blob_abs).context("image recode failure")?; + let orientation = self.get_exif_orientation(context); + let mut encoded = Vec::new(); + let mut changed_name = None; + + let exceeds_width = img.width() > img_wh || img.height() > img_wh; + + let do_scale = + exceeds_width || encoded_img_exceeds_bytes(context, &img, max_bytes, &mut encoded)?; + let do_rotate = matches!(orientation, Ok(90) | Ok(180) | Ok(270)); + + if do_scale || do_rotate { + if do_rotate { + img = match orientation { + Ok(90) => img.rotate90(), + Ok(180) => img.rotate180(), + Ok(270) => img.rotate270(), + _ => img, + } } - loop { - let new_img = img.thumbnail(img_wh, img_wh); + if do_scale { + if !exceeds_width { + // The image is already smaller than img_wh, but exceeds max_bytes + // We can directly start with trying to scale down to 2/3 of its current width + img_wh = max(img.width(), img.height()) * 2 / 3 + } - if encoded_img_exceeds_bytes(context, &new_img, max_bytes, &mut encoded)? { - if img_wh < 20 { - return Err(format_err!( - "Failed to scale image to below {}B", - max_bytes.unwrap_or_default() - )); + loop { + let new_img = img.thumbnail(img_wh, img_wh); + + if encoded_img_exceeds_bytes(context, &new_img, max_bytes, &mut encoded)? { + if img_wh < 20 { + return Err(format_err!( + "Failed to scale image to below {}B", + max_bytes.unwrap_or_default() + )); + } + + img_wh = img_wh * 2 / 3; + } else { + if encoded.is_empty() { + encode_img(&new_img, &mut encoded)?; + } + + info!( + context, + "Final scaled-down image size: {}B ({}px)", + encoded.len(), + img_wh + ); + break; } - - img_wh = img_wh * 2 / 3; - } else { - if encoded.is_empty() { - encode_img(&new_img, &mut encoded)?; - } - - info!( - context, - "Final scaled-down image size: {}B ({}px)", - encoded.len(), - img_wh - ); - break; } } - } - // The file format is JPEG now, we may have to change the file extension - if !matches!(ImageFormat::from_path(&blob_abs), Ok(ImageFormat::Jpeg)) { - blob_abs = blob_abs.with_extension("jpg"); - let file_name = blob_abs.file_name().context("No avatar file name (???)")?; - let file_name = file_name.to_str().context("Filename is no UTF-8 (???)")?; - changed_name = Some(format!("$BLOBDIR/{}", file_name)); - } + // The file format is JPEG now, we may have to change the file extension + if !matches!(ImageFormat::from_path(&blob_abs), Ok(ImageFormat::Jpeg)) { + blob_abs = blob_abs.with_extension("jpg"); + let file_name = blob_abs.file_name().context("No avatar file name (???)")?; + let file_name = file_name.to_str().context("Filename is no UTF-8 (???)")?; + changed_name = Some(format!("$BLOBDIR/{}", file_name)); + } - if encoded.is_empty() { - encode_img(&img, &mut encoded)?; - } + if encoded.is_empty() { + encode_img(&img, &mut encoded)?; + } - fs::write(&blob_abs, &encoded) - .await - .context("failed to write recoded blob to file")?; - } + std::fs::write(&blob_abs, &encoded) + .context("failed to write recoded blob to file")?; + } - Ok(changed_name) + Ok(changed_name) + }) } pub fn get_exif_orientation(&self, context: &Context) -> Result { @@ -500,6 +472,35 @@ impl<'a> fmt::Display for BlobObject<'a> { } } +fn encode_img(img: &DynamicImage, encoded: &mut Vec) -> anyhow::Result<()> { + encoded.clear(); + let mut buf = Cursor::new(encoded); + img.write_to(&mut buf, image::ImageFormat::Jpeg)?; + Ok(()) +} +fn encoded_img_exceeds_bytes( + context: &Context, + img: &DynamicImage, + max_bytes: Option, + encoded: &mut Vec, +) -> anyhow::Result { + if let Some(max_bytes) = max_bytes { + encode_img(img, encoded)?; + if encoded.len() > max_bytes { + info!( + context, + "image size {}B ({}x{}px) exceeds {}B, need to scale down", + encoded.len(), + img.width(), + img.height(), + max_bytes, + ); + return Ok(true); + } + } + Ok(false) +} + #[cfg(test)] mod tests { use fs::File; @@ -513,7 +514,16 @@ mod tests { use super::*; - #[async_std::test] + fn check_image_size(path: impl AsRef, width: u32, height: u32) -> image::DynamicImage { + tokio::task::block_in_place(move || { + let img = image::open(path).expect("failed to open image"); + assert_eq!(img.width(), width, "invalid width"); + assert_eq!(img.height(), height, "invalid height"); + img + }) + } + + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_create() { let t = TestContext::new().await; let blob = BlobObject::create(&t, "foo", b"hello").await.unwrap(); @@ -524,28 +534,28 @@ mod tests { assert_eq!(blob.to_abs_path(), t.get_blobdir().join("foo")); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_lowercase_ext() { let t = TestContext::new().await; let blob = BlobObject::create(&t, "foo.TXT", b"hello").await.unwrap(); assert_eq!(blob.as_name(), "$BLOBDIR/foo.txt"); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_as_file_name() { let t = TestContext::new().await; let blob = BlobObject::create(&t, "foo.txt", b"hello").await.unwrap(); assert_eq!(blob.as_file_name(), "foo.txt"); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_as_rel_path() { let t = TestContext::new().await; let blob = BlobObject::create(&t, "foo.txt", b"hello").await.unwrap(); assert_eq!(blob.as_rel_path(), Path::new("foo.txt")); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_suffix() { let t = TestContext::new().await; let blob = BlobObject::create(&t, "foo.txt", b"hello").await.unwrap(); @@ -554,16 +564,16 @@ mod tests { assert_eq!(blob.suffix(), None); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_create_dup() { let t = TestContext::new().await; BlobObject::create(&t, "foo.txt", b"hello").await.unwrap(); let foo_path = t.get_blobdir().join("foo.txt"); - assert!(foo_path.exists().await); + assert!(foo_path.exists()); BlobObject::create(&t, "foo.txt", b"world").await.unwrap(); let mut dir = fs::read_dir(t.get_blobdir()).await.unwrap(); - while let Some(dirent) = dir.next().await { - let fname = dirent.unwrap().file_name(); + while let Ok(Some(dirent)) = dir.next_entry().await { + let fname = dirent.file_name(); if fname == foo_path.file_name().unwrap() { assert_eq!(fs::read(&foo_path).await.unwrap(), b"hello"); } else { @@ -574,20 +584,20 @@ mod tests { } } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_double_ext_preserved() { let t = TestContext::new().await; BlobObject::create(&t, "foo.tar.gz", b"hello") .await .unwrap(); let foo_path = t.get_blobdir().join("foo.tar.gz"); - assert!(foo_path.exists().await); + assert!(foo_path.exists()); BlobObject::create(&t, "foo.tar.gz", b"world") .await .unwrap(); let mut dir = fs::read_dir(t.get_blobdir()).await.unwrap(); - while let Some(dirent) = dir.next().await { - let fname = dirent.unwrap().file_name(); + while let Ok(Some(dirent)) = dir.next_entry().await { + let fname = dirent.file_name(); if fname == foo_path.file_name().unwrap() { assert_eq!(fs::read(&foo_path).await.unwrap(), b"hello"); } else { @@ -599,7 +609,7 @@ mod tests { } } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_create_long_names() { let t = TestContext::new().await; let s = "1".repeat(150); @@ -608,7 +618,7 @@ mod tests { assert!(blobname.len() < 128); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_create_and_copy() { let t = TestContext::new().await; let src = t.dir.path().join("src"); @@ -623,10 +633,10 @@ mod tests { .await .is_err()); let whoops = t.get_blobdir().join("whoops"); - assert!(!whoops.exists().await); + assert!(!whoops.exists()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_create_from_path() { let t = TestContext::new().await; @@ -646,7 +656,7 @@ mod tests { let data = fs::read(blob.to_abs_path()).await.unwrap(); assert_eq!(data, b"boo"); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_create_from_name_long() { let t = TestContext::new().await; let src_ext = t.dir.path().join("autocrypt-setup-message-4137848473.html"); @@ -709,7 +719,7 @@ mod tests { assert!(!stem.contains('?')); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_selfavatar_outside_blobdir() { let t = TestContext::new().await; let avatar_src = t.dir.path().join("avatar.jpg"); @@ -721,22 +731,17 @@ mod tests { .await .unwrap(); let avatar_blob = t.get_blobdir().join("avatar.jpg"); - assert!(!avatar_blob.exists().await); + assert!(!avatar_blob.exists()); t.set_config(Config::Selfavatar, Some(avatar_src.to_str().unwrap())) .await .unwrap(); - assert!(avatar_blob.exists().await); - assert!(std::fs::metadata(&avatar_blob).unwrap().len() < avatar_bytes.len() as u64); + assert!(avatar_blob.exists()); + assert!(tokio::fs::metadata(&avatar_blob).await.unwrap().len() < avatar_bytes.len() as u64); let avatar_cfg = t.get_config(Config::Selfavatar).await.unwrap(); assert_eq!(avatar_cfg, avatar_blob.to_str().map(|s| s.to_string())); - let img = image::open(avatar_src).unwrap(); - assert_eq!(img.width(), 1000); - assert_eq!(img.height(), 1000); - - let img = image::open(&avatar_blob).unwrap(); - assert_eq!(img.width(), BALANCED_AVATAR_SIZE); - assert_eq!(img.height(), BALANCED_AVATAR_SIZE); + check_image_size(avatar_src, 1000, 1000); + check_image_size(&avatar_blob, BALANCED_AVATAR_SIZE, BALANCED_AVATAR_SIZE); async fn file_size(path_buf: &PathBuf) -> u64 { let file = File::open(path_buf).await.unwrap(); @@ -750,12 +755,14 @@ mod tests { .unwrap(); assert!(file_size(&avatar_blob).await <= 3000); assert!(file_size(&avatar_blob).await > 2000); - let img = image::open(&avatar_blob).unwrap(); - assert!(img.width() > 130); - assert_eq!(img.width(), img.height()); + tokio::task::block_in_place(move || { + let img = image::open(&avatar_blob).unwrap(); + assert!(img.width() > 130); + assert_eq!(img.width(), img.height()); + }); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_selfavatar_in_blobdir() { let t = TestContext::new().await; let avatar_src = t.get_blobdir().join("avatar.png"); @@ -766,9 +773,7 @@ mod tests { .await .unwrap(); - let img = image::open(&avatar_src).unwrap(); - assert_eq!(img.width(), 900); - assert_eq!(img.height(), 900); + check_image_size(&avatar_src, 900, 900); t.set_config(Config::Selfavatar, Some(avatar_src.to_str().unwrap())) .await @@ -779,12 +784,10 @@ mod tests { avatar_src.with_extension("jpg").to_str().unwrap() ); - let img = image::open(avatar_cfg).unwrap(); - assert_eq!(img.width(), BALANCED_AVATAR_SIZE); - assert_eq!(img.height(), BALANCED_AVATAR_SIZE); + check_image_size(avatar_cfg, BALANCED_AVATAR_SIZE, BALANCED_AVATAR_SIZE); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_selfavatar_copy_without_recode() { let t = TestContext::new().await; let avatar_src = t.dir.path().join("avatar.png"); @@ -796,20 +799,20 @@ mod tests { .await .unwrap(); let avatar_blob = t.get_blobdir().join("avatar.png"); - assert!(!avatar_blob.exists().await); + assert!(!avatar_blob.exists()); t.set_config(Config::Selfavatar, Some(avatar_src.to_str().unwrap())) .await .unwrap(); - assert!(avatar_blob.exists().await); + assert!(avatar_blob.exists()); assert_eq!( - std::fs::metadata(&avatar_blob).unwrap().len(), + tokio::fs::metadata(&avatar_blob).await.unwrap().len(), avatar_bytes.len() as u64 ); let avatar_cfg = t.get_config(Config::Selfavatar).await.unwrap(); assert_eq!(avatar_cfg, avatar_blob.to_str().map(|s| s.to_string())); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_recode_image_1() { let bytes = include_bytes!("../test-data/image/avatar1000x1000.jpg"); // BALANCED_IMAGE_SIZE > 1000, the original image size, so the image is not scaled down: @@ -829,7 +832,7 @@ mod tests { .unwrap(); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_recode_image_2() { // The "-rotated" files are rotated by 270 degrees using the Exif metadata let bytes = include_bytes!("../test-data/image/rectangle2000x1800-rotated.jpg"); @@ -855,7 +858,7 @@ mod tests { // Do this in parallel to speed up the test a bit // (it still takes very long though) let bytes2 = bytes.clone(); - let join_handle = async_std::task::spawn(async move { + let join_handle = tokio::task::spawn(async move { let img_rotated = send_image_check_mediaquality( Some("0"), &bytes2, @@ -883,10 +886,10 @@ mod tests { .unwrap(); assert_correct_rotation(&img_rotated); - join_handle.await; + join_handle.await.unwrap(); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_recode_image_3() { let bytes = include_bytes!("../test-data/image/rectangle200x180-rotated.jpg"); let img_rotated = send_image_check_mediaquality(Some("0"), bytes, 200, 180, 270, 180, 200) @@ -934,10 +937,10 @@ mod tests { .await?; let file = alice.get_blobdir().join("file.jpg"); - File::create(&file).await?.write_all(bytes).await?; - let img = image::open(&file)?; - assert_eq!(img.width(), original_width); - assert_eq!(img.height(), original_height); + fs::write(&file, &bytes) + .await + .context("failed to write file")?; + check_image_size(&file, original_width, original_height); let blob = BlobObject::new_from_path(&alice, &file).await?; assert_eq!(blob.get_exif_orientation(&alice).unwrap_or(0), orientation); @@ -949,9 +952,11 @@ mod tests { let alice_msg = alice.get_last_msg().await; assert_eq!(alice_msg.get_width() as u32, compressed_width); assert_eq!(alice_msg.get_height() as u32, compressed_height); - let img = image::open(alice_msg.get_file(&alice).unwrap())?; - assert_eq!(img.width() as u32, compressed_width); - assert_eq!(img.height() as u32, compressed_height); + check_image_size( + alice_msg.get_file(&alice).unwrap(), + compressed_width, + compressed_height, + ); let bob_msg = bob.recv_msg(&sent).await; assert_eq!(bob_msg.get_width() as u32, compressed_width); @@ -961,13 +966,11 @@ mod tests { let blob = BlobObject::new_from_path(&bob, &file).await?; assert_eq!(blob.get_exif_orientation(&bob).unwrap_or(0), 0); - let img = image::open(file)?; - assert_eq!(img.width() as u32, compressed_width); - assert_eq!(img.height() as u32, compressed_height); + let img = check_image_size(file, compressed_width, compressed_height); Ok(img) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_increation_in_blobdir() -> Result<()> { let t = TestContext::new_alice().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "abc").await?; @@ -986,7 +989,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_increation_not_blobdir() -> Result<()> { let t = TestContext::new_alice().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "abc").await?; diff --git a/src/chat.rs b/src/chat.rs index b3c82aca87..52d8d871a8 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -2,11 +2,11 @@ use std::collections::HashMap; use std::convert::{TryFrom, TryInto}; +use std::path::{Path, PathBuf}; use std::str::FromStr; use std::time::{Duration, SystemTime}; use anyhow::{bail, ensure, Context as _, Result}; -use async_std::path::{Path, PathBuf}; use deltachat_derive::{FromSql, ToSql}; use serde::{Deserialize, Serialize}; @@ -3464,10 +3464,10 @@ mod tests { use crate::contact::Contact; use crate::dc_receive_imf::dc_receive_imf; use crate::test_utils::TestContext; - use async_std::fs::File; - use async_std::prelude::*; + use tokio::fs::File; + use tokio::io::AsyncWriteExt; - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_chat_info() { let t = TestContext::new().await; let chat = t.create_chat_with_contact("bob", "bob@example.com").await; @@ -3498,7 +3498,7 @@ mod tests { assert_eq!(info, loaded); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_draft_no_draft() { let t = TestContext::new().await; let chat = t.get_self_chat().await; @@ -3506,14 +3506,14 @@ mod tests { assert!(draft.is_none()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_draft_special_chat_id() { let t = TestContext::new().await; let draft = DC_CHAT_ID_LAST_SPECIAL.get_draft(&t).await.unwrap(); assert!(draft.is_none()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_draft_no_chat() { // This is a weird case, maybe this should be an error but we // do not get this info from the database currently. @@ -3522,7 +3522,7 @@ mod tests { assert!(draft.is_none()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_draft() { let t = TestContext::new().await; let chat_id = &t.get_self_chat().await.id; @@ -3536,7 +3536,7 @@ mod tests { assert_eq!(msg_text, draft_text); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_delete_draft() -> Result<()> { let t = TestContext::new_alice().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "abc").await?; @@ -3557,7 +3557,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_forwarding_draft_failing() -> Result<()> { let t = TestContext::new_alice().await; let chat_id = &t.get_self_chat().await.id; @@ -3571,7 +3571,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_draft_stable_ids() -> Result<()> { let t = TestContext::new_alice().await; let chat_id = &t.get_self_chat().await.id; @@ -3616,7 +3616,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_change_quotes_on_reused_message_object() -> Result<()> { let t = TestContext::new_alice().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "chat").await?; @@ -3668,7 +3668,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_add_contact_to_chat_ex_add_self() { // Adding self to a contact should succeed, even though it's pointless. let t = TestContext::new_alice().await; @@ -3681,7 +3681,7 @@ mod tests { assert_eq!(added, false); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_modify_chat_multi_device() -> Result<()> { let a1 = TestContext::new_alice().await; let a2 = TestContext::new_alice().await; @@ -3756,7 +3756,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_modify_chat_disordered() -> Result<()> { // Alice creates a group with Bob, Claire and Daisy and then removes Claire and Daisy // (sleep() is needed as otherwise smeared time from Alice looks to Bob like messages from the future which are all set to "now" then) @@ -3770,47 +3770,47 @@ mod tests { send_text_msg(&alice, alice_chat_id, "populate".to_string()).await?; add_contact_to_chat(&alice, alice_chat_id, bob_id).await?; - async_std::task::sleep(std::time::Duration::from_millis(1100)).await; + tokio::time::sleep(std::time::Duration::from_millis(1100)).await; let add1 = alice.pop_sent_msg().await; add_contact_to_chat(&alice, alice_chat_id, claire_id).await?; let add2 = alice.pop_sent_msg().await; - async_std::task::sleep(std::time::Duration::from_millis(1100)).await; + tokio::time::sleep(std::time::Duration::from_millis(1100)).await; add_contact_to_chat(&alice, alice_chat_id, daisy_id).await?; let add3 = alice.pop_sent_msg().await; - async_std::task::sleep(std::time::Duration::from_millis(1100)).await; + tokio::time::sleep(std::time::Duration::from_millis(1100)).await; assert_eq!(get_chat_contacts(&alice, alice_chat_id).await?.len(), 4); remove_contact_from_chat(&alice, alice_chat_id, claire_id).await?; let remove1 = alice.pop_sent_msg().await; - async_std::task::sleep(std::time::Duration::from_millis(1100)).await; + tokio::time::sleep(std::time::Duration::from_millis(1100)).await; remove_contact_from_chat(&alice, alice_chat_id, daisy_id).await?; let remove2 = alice.pop_sent_msg().await; - async_std::task::sleep(std::time::Duration::from_millis(1100)).await; + tokio::time::sleep(std::time::Duration::from_millis(1100)).await; assert_eq!(get_chat_contacts(&alice, alice_chat_id).await?.len(), 2); // Bob receives the add and deletion messages out of order let bob = TestContext::new_bob().await; bob.recv_msg(&add1).await; - async_std::task::sleep(std::time::Duration::from_millis(1100)).await; + tokio::time::sleep(std::time::Duration::from_millis(1100)).await; bob.recv_msg(&add3).await; - async_std::task::sleep(std::time::Duration::from_millis(1100)).await; + tokio::time::sleep(std::time::Duration::from_millis(1100)).await; let bob_chat_id = bob.recv_msg(&add2).await.chat_id; - async_std::task::sleep(std::time::Duration::from_millis(1100)).await; + tokio::time::sleep(std::time::Duration::from_millis(1100)).await; assert_eq!(get_chat_contacts(&bob, bob_chat_id).await?.len(), 4); bob.recv_msg(&remove2).await; - async_std::task::sleep(std::time::Duration::from_millis(1100)).await; + tokio::time::sleep(std::time::Duration::from_millis(1100)).await; bob.recv_msg(&remove1).await; - async_std::task::sleep(std::time::Duration::from_millis(1100)).await; + tokio::time::sleep(std::time::Duration::from_millis(1100)).await; assert_eq!(get_chat_contacts(&bob, bob_chat_id).await?.len(), 2); @@ -3818,7 +3818,7 @@ mod tests { } /// Test that group updates are robust to lost messages and eventual out of order arrival. - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_modify_chat_lost() -> Result<()> { let alice = TestContext::new_alice().await; @@ -3833,11 +3833,11 @@ mod tests { send_text_msg(&alice, alice_chat_id, "populate".to_string()).await?; let add = alice.pop_sent_msg().await; - async_std::task::sleep(std::time::Duration::from_millis(1100)).await; + tokio::time::sleep(std::time::Duration::from_millis(1100)).await; remove_contact_from_chat(&alice, alice_chat_id, claire_id).await?; let remove1 = alice.pop_sent_msg().await; - async_std::task::sleep(std::time::Duration::from_millis(1100)).await; + tokio::time::sleep(std::time::Duration::from_millis(1100)).await; remove_contact_from_chat(&alice, alice_chat_id, daisy_id).await?; let remove2 = alice.pop_sent_msg().await; @@ -3860,7 +3860,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_leave_group() -> Result<()> { let alice = TestContext::new_alice().await; let bob = TestContext::new_bob().await; @@ -3889,7 +3889,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_add_remove_contact_for_single() { let ctx = TestContext::new_alice().await; let bob = Contact::create(&ctx, "", "bob@f.br").await.unwrap(); @@ -3913,7 +3913,7 @@ mod tests { assert_eq!(get_chat_contacts(&ctx, chat.id).await.unwrap().len(), 1); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_self_talk() -> Result<()> { let t = TestContext::new_alice().await; let chat = &t.get_self_chat().await; @@ -3944,7 +3944,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_add_device_msg_unlabelled() { let t = TestContext::new().await; @@ -3979,7 +3979,7 @@ mod tests { assert_eq!(msg2.chat_id.get_msg_cnt(&t).await.unwrap(), 2); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_add_device_msg_labelled() -> Result<()> { let t = TestContext::new().await; @@ -4029,7 +4029,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_add_device_msg_label_only() { let t = TestContext::new().await; let res = add_device_msg(&t, Some(""), None).await; @@ -4049,7 +4049,7 @@ mod tests { assert!(!msg_id.as_ref().unwrap().is_unset()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_was_device_msg_ever_added() { let t = TestContext::new().await; add_device_msg(&t, Some("some-label"), None).await.ok(); @@ -4069,7 +4069,7 @@ mod tests { assert!(was_device_msg_ever_added(&t, "").await.is_err()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_delete_device_chat() { let t = TestContext::new().await; @@ -4089,7 +4089,7 @@ mod tests { assert_eq!(chatlist_len(&t, 0).await, 0) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_device_chat_cannot_sent() { let t = TestContext::new().await; t.update_device_chats().await.unwrap(); @@ -4106,7 +4106,7 @@ mod tests { assert!(forward_msgs(&t, &[msg_id], device_chat_id).await.is_err()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_delete_and_reset_all_device_msgs() { let t = TestContext::new().await; let mut msg = Message::new(Viewtype::Text); @@ -4138,7 +4138,7 @@ mod tests { .len() } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_archive() { // create two chats let t = TestContext::new().await; @@ -4241,7 +4241,7 @@ mod tests { assert_eq!(chatlist_len(&t, DC_GCL_ARCHIVED_ONLY).await, 1); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_unarchive_if_muted() -> Result<()> { let t = TestContext::new_alice().await; @@ -4335,7 +4335,7 @@ mod tests { result } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_pinned() { let t = TestContext::new().await; @@ -4347,9 +4347,9 @@ mod tests { .await .unwrap() .chat_id; - async_std::task::sleep(std::time::Duration::from_millis(1000)).await; + tokio::time::sleep(std::time::Duration::from_millis(1000)).await; let chat_id2 = t.get_self_chat().await.id; - async_std::task::sleep(std::time::Duration::from_millis(1000)).await; + tokio::time::sleep(std::time::Duration::from_millis(1000)).await; let chat_id3 = create_group_chat(&t, ProtectionStatus::Unprotected, "foo") .await .unwrap(); @@ -4392,7 +4392,7 @@ mod tests { assert_eq!(chatlist, vec![chat_id3, chat_id2, chat_id1]); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_set_chat_name() { let t = TestContext::new().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo") @@ -4410,7 +4410,7 @@ mod tests { ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_create_same_chat_twice() { let context = TestContext::new().await; let contact1 = Contact::create(&context.ctx, "bob", "bob@mail.de") @@ -4433,7 +4433,7 @@ mod tests { assert_eq!(chat2.name, chat.name); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_shall_attach_selfavatar() -> Result<()> { let t = TestContext::new().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?; @@ -4451,7 +4451,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_set_mute_duration() { let t = TestContext::new().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo") @@ -4502,7 +4502,7 @@ mod tests { ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_add_info_msg() -> Result<()> { let t = TestContext::new().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?; @@ -4519,7 +4519,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_add_info_msg_with_cmd() -> Result<()> { let t = TestContext::new().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?; @@ -4549,7 +4549,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_set_protection() { let t = TestContext::new_alice().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo") @@ -4617,7 +4617,7 @@ mod tests { assert_eq!(msg.get_state(), MessageState::OutDelivered); // as bcc-self is disabled and there is nobody else in the chat } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_lookup_by_contact_id() { let ctx = TestContext::new_alice().await; @@ -4660,7 +4660,7 @@ mod tests { assert!(found.is_none()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_lookup_self_by_contact_id() { let ctx = TestContext::new_alice().await; @@ -4679,7 +4679,7 @@ mod tests { assert_eq!(chat.blocked, Blocked::Not); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_group_with_removed_message_id() -> Result<()> { // Alice creates a group with Bob, sends a message to bob let alice = TestContext::new_alice().await; @@ -4733,7 +4733,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_marknoticed_chat() -> Result<()> { let t = TestContext::new_alice().await; let chat = t.create_chat_with_contact("bob", "bob@example.org").await; @@ -4778,7 +4778,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_contact_request_fresh_messages() -> Result<()> { let t = TestContext::new_alice().await; @@ -4828,7 +4828,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_contact_request_archive() -> Result<()> { let t = TestContext::new_alice().await; @@ -4868,7 +4868,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_classic_email_chat() -> Result<()> { let alice = TestContext::new_alice().await; @@ -4913,7 +4913,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_chat_get_color() -> Result<()> { let t = TestContext::new().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "a chat").await?; @@ -4956,7 +4956,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_sticker_png() -> Result<()> { test_sticker( "sticker.png", @@ -4967,7 +4967,7 @@ mod tests { .await } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_sticker_jpeg() -> Result<()> { test_sticker( "sticker.jpg", @@ -4978,7 +4978,7 @@ mod tests { .await } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_sticker_gif() -> Result<()> { test_sticker( "sticker.gif", @@ -4989,7 +4989,7 @@ mod tests { .await } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_sticker_forward() -> Result<()> { // create chats let alice = TestContext::new_alice().await; @@ -5020,7 +5020,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_forward() -> Result<()> { let alice = TestContext::new_alice().await; let bob = TestContext::new_bob().await; @@ -5041,7 +5041,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_forward_info_msg() -> Result<()> { let t = TestContext::new_alice().await; @@ -5067,7 +5067,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_forward_quote() -> Result<()> { let alice = TestContext::new_alice().await; let bob = TestContext::new_bob().await; @@ -5102,7 +5102,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_forward_group() -> Result<()> { let alice = TestContext::new_alice().await; let bob = TestContext::new_bob().await; @@ -5152,7 +5152,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_only_minimal_data_are_forwarded() -> Result<()> { // send a message from Alice to a group with Bob let alice = TestContext::new_alice().await; @@ -5194,7 +5194,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_resend_own_message() -> Result<()> { // Alice creates group with Bob and sends an initial message let alice = TestContext::new_alice().await; @@ -5247,7 +5247,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_resend_foreign_message_fails() -> Result<()> { let alice = TestContext::new_alice().await; let alice_grp = create_group_chat(&alice, ProtectionStatus::Unprotected, "grp").await?; @@ -5266,7 +5266,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_resend_opportunistically_encryption() -> Result<()> { // Alice creates group with Bob and sends an initial message let alice = TestContext::new_alice().await; @@ -5303,7 +5303,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_resend_info_message_fails() -> Result<()> { let alice = TestContext::new_alice().await; let alice_grp = create_group_chat(&alice, ProtectionStatus::Unprotected, "grp").await?; @@ -5327,7 +5327,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_can_send_group() -> Result<()> { let alice = TestContext::new_alice().await; let bob = Contact::create(&alice, "", "bob@f.br").await?; @@ -5353,7 +5353,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_broadcast() -> Result<()> { // create two context, send two messages so both know the other let alice = TestContext::new_alice().await; @@ -5396,7 +5396,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_create_for_contact_with_blocked() -> Result<()> { let t = TestContext::new().await; let (contact_id, _) = @@ -5430,7 +5430,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_chat_get_encryption_info() -> Result<()> { let alice = TestContext::new_alice().await; let bob = TestContext::new_bob().await; diff --git a/src/chatlist.rs b/src/chatlist.rs index ca70c7839c..ed3e650bc5 100644 --- a/src/chatlist.rs +++ b/src/chatlist.rs @@ -376,7 +376,7 @@ mod tests { use crate::stock_str::StockMessage; use crate::test_utils::TestContext; - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_try_load() { let t = TestContext::new().await; let chat_id1 = create_group_chat(&t, ProtectionStatus::Unprotected, "a chat") @@ -432,7 +432,7 @@ mod tests { assert_eq!(chats.len(), 1); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_sort_self_talk_up_on_forward() { let t = TestContext::new().await; t.update_device_chats().await.unwrap(); @@ -457,7 +457,7 @@ mod tests { .is_self_talk()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_search_special_chat_names() { let t = TestContext::new().await; t.update_device_chats().await.unwrap(); @@ -488,7 +488,7 @@ mod tests { assert_eq!(chats.len(), 1); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_search_single_chat() -> anyhow::Result<()> { let t = TestContext::new_alice().await; @@ -548,7 +548,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_search_single_chat_without_authname() -> anyhow::Result<()> { let t = TestContext::new_alice().await; @@ -610,7 +610,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_summary_unwrap() { let t = TestContext::new().await; let chat_id1 = create_group_chat(&t, ProtectionStatus::Unprotected, "a chat") diff --git a/src/config.rs b/src/config.rs index 44cb7e3663..231069b6ad 100644 --- a/src/config.rs +++ b/src/config.rs @@ -454,7 +454,7 @@ mod tests { ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_media_quality_config_option() { let t = TestContext::new().await; let media_quality = t.get_config_int(Config::MediaQuality).await.unwrap(); @@ -471,7 +471,7 @@ mod tests { assert_eq!(media_quality, constants::MediaQuality::Worse); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_ui_config() -> Result<()> { let t = TestContext::new().await; @@ -493,7 +493,7 @@ mod tests { } /// Regression test for https://github.com/deltachat/deltachat-core-rust/issues/3012 - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_set_config_bool() -> Result<()> { let t = TestContext::new().await; @@ -505,7 +505,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_self_addrs() -> Result<()> { let alice = TestContext::new_alice().await; @@ -558,7 +558,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_change_primary_self_addr() -> Result<()> { let mut tcm = TestContextManager::new().await; let alice = tcm.alice().await; diff --git a/src/configure.rs b/src/configure.rs index ec3456ef83..a81122509d 100644 --- a/src/configure.rs +++ b/src/configure.rs @@ -6,9 +6,10 @@ mod read_url; mod server_params; use anyhow::{bail, ensure, Context as _, Result}; -use async_std::prelude::*; -use async_std::task; +use futures::FutureExt; +use futures_lite::FutureExt as _; use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC}; +use tokio::task; use crate::config::Config; use crate::context::Context; @@ -55,8 +56,6 @@ impl Context { /// Configures this account with the currently set parameters. pub async fn configure(&self) -> Result<()> { - use futures::future::FutureExt; - ensure!( self.scheduler.read().await.is_none(), "cannot configure, already running" @@ -404,7 +403,7 @@ async fn configure(ctx: &Context, param: &mut LoginParam) -> Result<()> { progress!(ctx, 850); // Wait for SMTP configuration - match smtp_config_task.await { + match smtp_config_task.await.unwrap() { Ok(smtp_param) => { param.smtp = smtp_param; } @@ -447,7 +446,7 @@ async fn configure(ctx: &Context, param: &mut LoginParam) -> Result<()> { ctx.interrupt_inbox(InterruptInfo::new(false)).await; progress!(ctx, 940); - update_device_chats_handle.await?; + update_device_chats_handle.await??; ctx.sql.set_raw_config_bool("configured", true).await?; @@ -549,7 +548,7 @@ async fn try_imap_one_param( ); info!(context, "Trying: {}", inf); - let (_s, r) = async_std::channel::bounded(1); + let (_s, r) = async_channel::bounded(1); let mut imap = match Imap::new(param, socks5_config.clone(), addr, provider_strict_tls, r).await { @@ -634,10 +633,13 @@ async fn nicer_configuration_error(context: &Context, errors: Vec anyhow::Result { match read_url_inner(context, url).await { @@ -16,24 +15,27 @@ pub async fn read_url(context: &Context, url: &str) -> anyhow::Result { } } -pub async fn read_url_inner(context: &Context, mut url: &str) -> anyhow::Result { - let mut _temp; // For the borrow checker +pub async fn read_url_inner(context: &Context, url: &str) -> anyhow::Result { + let client = reqwest::Client::new(); + let mut url = url.to_string(); // Follow up to 10 http-redirects for _i in 0..10 { - let mut response = surf::get(url).send().await.map_err(|e| e.into_inner())?; + let response = client.get(&url).send().await?; if response.status().is_redirection() { - _temp = response - .header("location") - .context("Redirection doesn't have a target location")? + let headers = response.headers(); + let header = headers + .get_all("location") + .iter() .last() - .to_string(); - info!(context, "Following redirect to {}", _temp); - url = &_temp; + .ok_or_else(|| anyhow!("Redirection doesn't have a target location"))? + .to_str()?; + info!(context, "Following redirect to {}", header); + url = header.to_string(); continue; } - return response.body_string().await.map_err(|e| e.into_inner()); + return response.text().await.map_err(Into::into); } Err(format_err!("Followed 10 redirections")) diff --git a/src/contact.rs b/src/contact.rs index 8153c50d72..eaa0d803a7 100644 --- a/src/contact.rs +++ b/src/contact.rs @@ -2,9 +2,9 @@ use std::convert::{TryFrom, TryInto}; use std::fmt; +use std::path::PathBuf; use anyhow::{bail, ensure, Context as _, Result}; -use async_std::path::PathBuf; use deltachat_derive::{FromSql, ToSql}; use once_cell::sync::Lazy; use regex::Regex; @@ -1438,8 +1438,8 @@ fn split_address_book(book: &str) -> Vec<(&str, &str)> { #[cfg(test)] mod tests { - use async_std::fs::File; - use async_std::io::WriteExt; + use tokio::fs::File; + use tokio::io::AsyncWriteExt; use super::*; @@ -1508,7 +1508,7 @@ mod tests { ) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_contacts() -> Result<()> { let context = TestContext::new().await; @@ -1572,7 +1572,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_is_self_addr() -> Result<()> { let t = TestContext::new().await; assert_eq!(t.is_self_addr("me@me.org").await?, false); @@ -1584,7 +1584,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_add_or_lookup() { // add some contacts, this also tests add_address_book() let t = TestContext::new().await; @@ -1685,7 +1685,7 @@ mod tests { assert!(!contact.is_blocked()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_contact_name_changes() -> Result<()> { let t = TestContext::new_alice().await; @@ -1797,7 +1797,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_delete() -> Result<()> { let alice = TestContext::new_alice().await; @@ -1825,7 +1825,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_remote_authnames() { let t = TestContext::new().await; @@ -1876,7 +1876,7 @@ mod tests { assert_eq!(contact.get_display_name(), "bob3"); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_remote_authnames_create_empty() { let t = TestContext::new().await; @@ -1925,7 +1925,7 @@ mod tests { /// /// In the past, "Not Bob" name was stuck until "Bob" changed the name to "Not Bob" and back in /// the "From:" field or user set the name to empty string manually. - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_remote_authnames_update_to() -> Result<()> { let t = TestContext::new().await; @@ -1958,7 +1958,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_remote_authnames_edit_empty() { let t = TestContext::new().await; @@ -1995,7 +1995,7 @@ mod tests { assert!(addr_cmp(" mailto:AA@AA.ORG", "Aa@Aa.orG")); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_name_in_address() { let t = TestContext::new().await; @@ -2034,7 +2034,7 @@ mod tests { .is_err()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_lookup_id_by_addr() { let t = TestContext::new().await; @@ -2059,7 +2059,7 @@ mod tests { assert_eq!(id, Some(ContactId::SELF)); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_contact_get_color() -> Result<()> { let t = TestContext::new().await; let contact_id = Contact::create(&t, "name", "name@example.net").await?; @@ -2078,7 +2078,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_contact_get_encrinfo() -> Result<()> { let alice = TestContext::new_alice().await; @@ -2123,7 +2123,7 @@ CCCB 5AA9 F6E1 141C 9431 /// Tests that status is synchronized when sending encrypted BCC-self messages and not /// synchronized when the message is not encrypted. - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_synchronize_status() -> Result<()> { // Alice has two devices. let alice1 = TestContext::new_alice().await; @@ -2188,7 +2188,7 @@ CCCB 5AA9 F6E1 141C 9431 } /// Tests that DC_EVENT_SELFAVATAR_CHANGED is emitted on avatar changes. - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_selfavatar_changed_event() -> Result<()> { // Alice has two devices. let alice1 = TestContext::new_alice().await; @@ -2247,7 +2247,7 @@ CCCB 5AA9 F6E1 141C 9431 Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_last_seen() -> Result<()> { let alice = TestContext::new_alice().await; diff --git a/src/context.rs b/src/context.rs index 787a522b04..55d2e61508 100644 --- a/src/context.rs +++ b/src/context.rs @@ -3,14 +3,13 @@ use std::collections::{BTreeMap, HashMap}; use std::ffi::OsString; use std::ops::Deref; +use std::path::{Path, PathBuf}; +use std::sync::Arc; use std::time::{Duration, Instant, SystemTime}; use anyhow::{ensure, Result}; -use async_std::{ - channel::{self, Receiver, Sender}, - path::{Path, PathBuf}, - sync::{Arc, Mutex, RwLock}, -}; +use async_channel::{self as channel, Receiver, Sender}; +use tokio::sync::{Mutex, RwLock}; use crate::chat::{get_chat_cnt, ChatId}; use crate::config::Config; @@ -75,7 +74,7 @@ pub struct InnerContext { /// The text of the last error logged and emitted as an event. /// If the ui wants to display an error after a failure, /// `last_error` should be used to avoid races with the event thread. - pub(crate) last_error: RwLock, + pub(crate) last_error: std::sync::RwLock, } /// The state of ongoing process. @@ -115,7 +114,7 @@ pub fn get_info() -> BTreeMap<&'static str, String> { impl Context { /// Creates new context and opens the database. - pub async fn new(dbfile: PathBuf, id: u32, events: Events) -> Result { + pub async fn new(dbfile: &Path, id: u32, events: Events) -> Result { let context = Self::new_closed(dbfile, id, events).await?; // Open the database if is not encrypted. @@ -126,15 +125,15 @@ impl Context { } /// Creates new context without opening the database. - pub async fn new_closed(dbfile: PathBuf, id: u32, events: Events) -> Result { + pub async fn new_closed(dbfile: &Path, id: u32, events: Events) -> Result { let mut blob_fname = OsString::new(); blob_fname.push(dbfile.file_name().unwrap_or_default()); blob_fname.push("-blobs"); let blobdir = dbfile.with_file_name(blob_fname); - if !blobdir.exists().await { - async_std::fs::create_dir_all(&blobdir).await?; + if !blobdir.exists() { + tokio::fs::create_dir_all(&blobdir).await?; } - let context = Context::with_blobdir(dbfile, blobdir, id, events).await?; + let context = Context::with_blobdir(dbfile.into(), blobdir, id, events).await?; Ok(context) } @@ -172,7 +171,7 @@ impl Context { events: Events, ) -> Result { ensure!( - blobdir.is_dir().await, + blobdir.is_dir(), "Blobdir does not exist: {}", blobdir.display() ); @@ -193,7 +192,7 @@ impl Context { quota: RwLock::new(None), creation_time: std::time::SystemTime::now(), last_full_folder_scan: Mutex::new(None), - last_error: RwLock::new("".to_string()), + last_error: std::sync::RwLock::new("".to_string()), }; let ctx = Context { @@ -643,14 +642,14 @@ impl Context { Ok(mvbox.as_deref() == Some(folder_name)) } - pub(crate) fn derive_blobdir(dbfile: &PathBuf) -> PathBuf { + pub(crate) fn derive_blobdir(dbfile: &Path) -> PathBuf { let mut blob_fname = OsString::new(); blob_fname.push(dbfile.file_name().unwrap_or_default()); blob_fname.push("-blobs"); dbfile.with_file_name(blob_fname) } - pub(crate) fn derive_walfile(dbfile: &PathBuf) -> PathBuf { + pub(crate) fn derive_walfile(dbfile: &Path) -> PathBuf { let mut wal_fname = OsString::new(); wal_fname.push(dbfile.file_name().unwrap_or_default()); wal_fname.push("-wal"); @@ -679,19 +678,19 @@ mod tests { use strum::IntoEnumIterator; use tempfile::tempdir; - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_wrong_db() -> Result<()> { let tmp = tempfile::tempdir()?; let dbfile = tmp.path().join("db.sqlite"); - std::fs::write(&dbfile, b"123")?; - let res = Context::new(dbfile.into(), 1, Events::new()).await?; + tokio::fs::write(&dbfile, b"123").await?; + let res = Context::new(&dbfile, 1, Events::new()).await?; // Broken database is indistinguishable from encrypted one. assert_eq!(res.is_open().await, false); Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_fresh_msgs() { let t = TestContext::new().await; let fresh = t.get_fresh_msgs().await.unwrap(); @@ -718,7 +717,7 @@ mod tests { dc_receive_imf(t, msg.as_bytes(), false).await.unwrap(); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_fresh_msgs_and_muted_chats() { // receive various mails in 3 chats let t = TestContext::new_alice().await; @@ -768,7 +767,7 @@ mod tests { assert_eq!(t.get_fresh_msgs().await.unwrap().len(), 9); // claire is counted again } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_fresh_msgs_and_muted_until() { let t = TestContext::new_alice().await; let bob = t.create_chat_with_contact("", "bob@g.it").await; @@ -826,61 +825,61 @@ mod tests { assert_eq!(t.get_fresh_msgs().await.unwrap().len(), 1); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_blobdir_exists() { let tmp = tempfile::tempdir().unwrap(); let dbfile = tmp.path().join("db.sqlite"); - Context::new(dbfile.into(), 1, Events::new()).await.unwrap(); + Context::new(&dbfile, 1, Events::new()).await.unwrap(); let blobdir = tmp.path().join("db.sqlite-blobs"); assert!(blobdir.is_dir()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_wrong_blogdir() { let tmp = tempfile::tempdir().unwrap(); let dbfile = tmp.path().join("db.sqlite"); let blobdir = tmp.path().join("db.sqlite-blobs"); - std::fs::write(&blobdir, b"123").unwrap(); - let res = Context::new(dbfile.into(), 1, Events::new()).await; + tokio::fs::write(&blobdir, b"123").await.unwrap(); + let res = Context::new(&dbfile, 1, Events::new()).await; assert!(res.is_err()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_sqlite_parent_not_exists() { let tmp = tempfile::tempdir().unwrap(); let subdir = tmp.path().join("subdir"); let dbfile = subdir.join("db.sqlite"); let dbfile2 = dbfile.clone(); - Context::new(dbfile.into(), 1, Events::new()).await.unwrap(); + Context::new(&dbfile, 1, Events::new()).await.unwrap(); assert!(subdir.is_dir()); assert!(dbfile2.is_file()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_with_empty_blobdir() { let tmp = tempfile::tempdir().unwrap(); let dbfile = tmp.path().join("db.sqlite"); let blobdir = PathBuf::new(); - let res = Context::with_blobdir(dbfile.into(), blobdir, 1, Events::new()).await; + let res = Context::with_blobdir(dbfile, blobdir, 1, Events::new()).await; assert!(res.is_err()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_with_blobdir_not_exists() { let tmp = tempfile::tempdir().unwrap(); let dbfile = tmp.path().join("db.sqlite"); let blobdir = tmp.path().join("blobs"); - let res = Context::with_blobdir(dbfile.into(), blobdir.into(), 1, Events::new()).await; + let res = Context::with_blobdir(dbfile, blobdir, 1, Events::new()).await; assert!(res.is_err()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn no_crashes_on_context_deref() { let t = TestContext::new().await; std::mem::drop(t); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_info() { let t = TestContext::new().await; @@ -896,7 +895,7 @@ mod tests { assert_eq!(info.get("level").unwrap(), "awesome"); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_info_completeness() { // For easier debugging, // get_info() shall return all important information configurable by the Config-values. @@ -944,7 +943,7 @@ mod tests { } } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_search_msgs() -> Result<()> { let alice = TestContext::new_alice().await; let self_talk = ChatId::create_for_contact(&alice, ContactId::SELF).await?; @@ -1000,7 +999,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_limit_search_msgs() -> Result<()> { let alice = TestContext::new_alice().await; let chat = alice @@ -1033,13 +1032,13 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_check_passphrase() -> Result<()> { let dir = tempdir()?; let dbfile = dir.path().join("db.sqlite"); let id = 1; - let context = Context::new_closed(dbfile.clone().into(), id, Events::new()) + let context = Context::new_closed(&dbfile, id, Events::new()) .await .context("failed to create context")?; assert_eq!(context.open("foo".to_string()).await?, true); @@ -1047,7 +1046,7 @@ mod tests { drop(context); let id = 2; - let context = Context::new(dbfile.into(), id, Events::new()) + let context = Context::new(&dbfile, id, Events::new()) .await .context("failed to create context")?; assert_eq!(context.is_open().await, false); @@ -1058,7 +1057,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_ongoing() -> Result<()> { let context = TestContext::new().await; diff --git a/src/dc_receive_imf.rs b/src/dc_receive_imf.rs index 7d9a62310f..15a85ed270 100644 --- a/src/dc_receive_imf.rs +++ b/src/dc_receive_imf.rs @@ -2203,8 +2203,8 @@ async fn add_or_lookup_contact_by_addr( #[cfg(test)] mod tests { - use async_std::fs::{self, File}; - use async_std::io::WriteExt; + use tokio::fs::{self, File}; + use tokio::io::AsyncWriteExt; use super::*; @@ -2216,7 +2216,7 @@ mod tests { use crate::message::Message; use crate::test_utils::{get_chat_msg, TestContext, TestContextManager}; - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_grpid_simple() { let context = TestContext::new().await; let raw = b"Received: (Postfix, from userid 1000); Mon, 4 Dec 2006 14:51:39 +0100 (CET)\n\ @@ -2234,7 +2234,7 @@ mod tests { assert_eq!(extract_grpid(&mimeparser, HeaderDef::References), grpid); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_grpid_from_multiple() { let context = TestContext::new().await; let raw = b"Received: (Postfix, from userid 1000); Mon, 4 Dec 2006 14:51:39 +0100 (CET)\n\ @@ -2283,7 +2283,7 @@ mod tests { \n\ hello\n"; - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_adhoc_group_show_chats_only() { let t = TestContext::new_alice().await; assert_eq!(t.get_config_int(Config::ShowEmails).await.unwrap(), 0); @@ -2306,7 +2306,7 @@ mod tests { assert_eq!(chats.len(), 1); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_adhoc_group_show_accepted_contact_unknown() { let t = TestContext::new_alice().await; t.set_config(Config::ShowEmails, Some("1")).await.unwrap(); @@ -2317,7 +2317,7 @@ mod tests { assert_eq!(chats.len(), 0); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_adhoc_group_show_accepted_contact_known() { let t = TestContext::new_alice().await; t.set_config(Config::ShowEmails, Some("1")).await.unwrap(); @@ -2330,7 +2330,7 @@ mod tests { assert_eq!(chats.len(), 0); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_adhoc_group_show_accepted_contact_accepted() { let t = TestContext::new_alice().await; t.set_config(Config::ShowEmails, Some("1")).await.unwrap(); @@ -2368,7 +2368,7 @@ mod tests { assert_eq!(chat::get_chat_contacts(&t, chat_id).await.unwrap().len(), 3); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_adhoc_group_show_all() { let t = TestContext::new_alice().await; t.set_config(Config::ShowEmails, Some("2")).await.unwrap(); @@ -2387,7 +2387,7 @@ mod tests { assert_eq!(chat::get_chat_contacts(&t, chat_id).await.unwrap().len(), 3); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_read_receipt_and_unarchive() -> Result<()> { // create alice's account let t = TestContext::new_alice().await; @@ -2501,7 +2501,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_no_from() { // if there is no from given, from_id stays 0 which is just fine. These messages // are very rare, however, we have to add them to the database @@ -2533,7 +2533,7 @@ mod tests { assert!(chats.get_msg_id(0).is_ok()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_escaped_from() { let t = TestContext::new_alice().await; let contact_id = Contact::create(&t, "foobar", "foobar@example.com") @@ -2566,7 +2566,7 @@ mod tests { assert_eq!(msg.param.get_int(Param::WantsMdn).unwrap(), 1); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_escaped_recipients() { let t = TestContext::new_alice().await; Contact::create(&t, "foobar", "foobar@example.com") @@ -2608,7 +2608,7 @@ mod tests { assert_eq!(msg.param.get_int(Param::WantsMdn).unwrap(), 1); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_cc_to_contact() { let t = TestContext::new_alice().await; Contact::create(&t, "foobar", "foobar@example.com") @@ -2643,7 +2643,7 @@ mod tests { assert_eq!(contact.get_display_name(), "Carl"); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_parse_ndn_tiscali() { test_parse_ndn( "alice@tiscali.it", @@ -2655,7 +2655,7 @@ mod tests { .await; } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_parse_ndn_testrun() { test_parse_ndn( "alice@testrun.org", @@ -2667,7 +2667,7 @@ mod tests { .await; } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_parse_ndn_yahoo() { test_parse_ndn( "alice@yahoo.com", @@ -2679,7 +2679,7 @@ mod tests { .await; } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_parse_ndn_gmail() { test_parse_ndn( "alice@gmail.com", @@ -2691,7 +2691,7 @@ mod tests { .await; } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_parse_ndn_gmx() { test_parse_ndn( "alice@gmx.com", @@ -2703,7 +2703,7 @@ mod tests { .await; } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_parse_ndn_posteo() { test_parse_ndn( "alice@posteo.org", @@ -2715,7 +2715,7 @@ mod tests { .await; } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_parse_ndn_testrun_2() { test_parse_ndn( "alice@example.org", @@ -2781,7 +2781,7 @@ mod tests { assert_eq!(msg.error(), error_msg.map(|error| error.to_string())); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_parse_ndn_group_msg() -> Result<()> { let t = TestContext::new().await; t.configure_addr("alice@gmail.com").await; @@ -2841,7 +2841,7 @@ mod tests { Message::load_from_db(context, msg_id).await.unwrap() } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_html_only_mail() { let t = TestContext::new_alice().await; let msg = load_imf_email(&t, include_bytes!("../test-data/message/wrong-html.eml")).await; @@ -2874,7 +2874,7 @@ mod tests { \n\ hello back\n"; - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_github_mailing_list() -> Result<()> { let t = TestContext::new_alice().await; t.ctx.set_config(Config::ShowEmails, Some("2")).await?; @@ -2941,7 +2941,7 @@ mod tests { \n\ body 4\n"; - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_classic_mailing_list() -> Result<()> { let t = TestContext::new_alice().await; t.ctx @@ -2987,7 +2987,7 @@ Hello mailinglist!\r\n" Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_other_device_writes_to_mailinglist() -> Result<()> { let t = TestContext::new_alice().await; t.set_config(Config::ShowEmails, Some("2")).await?; @@ -3037,7 +3037,7 @@ Hello mailinglist!\r\n" Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_block_mailing_list() { let t = TestContext::new_alice().await; t.ctx @@ -3071,7 +3071,7 @@ Hello mailinglist!\r\n" assert_eq!(msgs.len(), 2); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_mailing_list_decide_block_then_unblock() { let t = TestContext::new_alice().await; t.set_config(Config::ShowEmails, Some("2")).await.unwrap(); @@ -3104,7 +3104,7 @@ Hello mailinglist!\r\n" assert_eq!(msgs.len(), 2); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_mailing_list_decide_not_now() { let t = TestContext::new_alice().await; t.ctx @@ -3137,7 +3137,7 @@ Hello mailinglist!\r\n" assert!(chat.is_contact_request()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_mailing_list_decide_accept() { let t = TestContext::new_alice().await; t.ctx @@ -3165,7 +3165,7 @@ Hello mailinglist!\r\n" assert!(chat.can_send(&t.ctx).await.unwrap()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_majordomo_mailing_list() { let t = TestContext::new_alice().await; t.set_config(Config::ShowEmails, Some("2")).await.unwrap(); @@ -3214,7 +3214,7 @@ Hello mailinglist!\r\n" assert_eq!(chat::get_chat_msgs(&t, chat.id, 0).await.unwrap().len(), 2); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_mailchimp_mailing_list() { let t = TestContext::new_alice().await; t.set_config(Config::ShowEmails, Some("2")).await.unwrap(); @@ -3244,7 +3244,7 @@ Hello mailinglist!\r\n" assert_eq!(chat.name, "Atlas Obscura"); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_dhl_mailing_list() { let t = TestContext::new_alice().await; t.set_config(Config::ShowEmails, Some("2")).await.unwrap(); @@ -3269,7 +3269,7 @@ Hello mailinglist!\r\n" assert_eq!(chat.name, "DHL Paket"); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_dpd_mailing_list() { let t = TestContext::new_alice().await; t.set_config(Config::ShowEmails, Some("2")).await.unwrap(); @@ -3294,7 +3294,7 @@ Hello mailinglist!\r\n" assert_eq!(chat.name, "DPD"); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_xt_local_mailing_list() -> Result<()> { let t = TestContext::new_alice().await; t.set_config(Config::ShowEmails, Some("2")).await?; @@ -3324,7 +3324,7 @@ Hello mailinglist!\r\n" Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_xing_mailing_list() -> Result<()> { let t = TestContext::new_alice().await; t.set_config(Config::ShowEmails, Some("2")).await?; @@ -3345,7 +3345,7 @@ Hello mailinglist!\r\n" Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_ttline_mailing_list() -> Result<()> { let t = TestContext::new_alice().await; t.set_config(Config::ShowEmails, Some("2")).await?; @@ -3366,7 +3366,7 @@ Hello mailinglist!\r\n" Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_mailing_list_with_mimepart_footer() { let t = TestContext::new_alice().await; t.set_config(Config::ShowEmails, Some("2")).await.unwrap(); @@ -3397,7 +3397,7 @@ Hello mailinglist!\r\n" assert_eq!(chat.name, "Intern"); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_mailing_list_with_mimepart_footer_signed() { let t = TestContext::new_alice().await; t.set_config(Config::ShowEmails, Some("2")).await.unwrap(); @@ -3422,7 +3422,7 @@ Hello mailinglist!\r\n" /// Test that the changes from apply_mailinglist_changes() are also applied /// if the message is assigned to the chat by In-Reply-To - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_apply_mailinglist_changes_assigned_by_reply() { let t = TestContext::new_alice().await; t.set_config(Config::ShowEmails, Some("2")).await.unwrap(); @@ -3464,7 +3464,7 @@ Hello mailinglist!\r\n" ) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_dont_show_tokens_in_contacts_list() { check_dont_show_in_contacts_list( "reply+OGHVYCLVBEGATYBICAXBIRQATABUOTUCERABERAHNO@reply.github.com", @@ -3472,7 +3472,7 @@ Hello mailinglist!\r\n" .await; } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_dont_show_noreply_in_contacts_list() { check_dont_show_in_contacts_list("noreply@github.com").await; } @@ -3510,7 +3510,7 @@ YEAAAAAA!. assert!(contacts.is_empty()); // The contact should not have been added to the db } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_pdf_filename_simple() { let t = TestContext::new_alice().await; let msg = load_imf_email( @@ -3523,7 +3523,7 @@ YEAAAAAA!. assert_eq!(msg.param.get(Param::File).unwrap(), "$BLOBDIR/simple.pdf"); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_pdf_filename_continuation() { // test filenames split across multiple header lines, see rfc 2231 let t = TestContext::new_alice().await; @@ -3550,7 +3550,7 @@ YEAAAAAA!. /// or mua may use multipart/related not correctly - /// so this test is in competition with parse_thunderbird_html_embedded_image() /// that wants the image to be kept in the chat. - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_many_images() { let t = TestContext::new_alice().await; t.set_config(Config::ShowEmails, Some("2")).await.unwrap(); @@ -3571,7 +3571,7 @@ YEAAAAAA!. /// Test that classical MUA messages are assigned to group chats based on the `In-Reply-To` /// header. - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_in_reply_to() { let t = TestContext::new().await; t.configure_addr("bob@example.com").await; @@ -3636,7 +3636,7 @@ YEAAAAAA!. /// Test that classical MUA messages are assigned to group chats /// based on the `In-Reply-To` header for two-member groups. - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_in_reply_to_two_member_group() { let t = TestContext::new().await; t.configure_addr("bob@example.com").await; @@ -3738,7 +3738,7 @@ YEAAAAAA!. assert_eq!(msg.get_text().unwrap(), "private reply"); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_save_mime_headers_off() -> anyhow::Result<()> { let alice = TestContext::new_alice().await; let bob = TestContext::new_bob().await; @@ -3753,7 +3753,7 @@ YEAAAAAA!. Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_save_mime_headers_on() -> anyhow::Result<()> { let alice = TestContext::new_alice().await; alice.set_config_bool(Config::SaveMimeHeaders, true).await?; @@ -3924,7 +3924,7 @@ YEAAAAAA!. ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_alias_support_answer_from_nondc() { // Bob, the other supporter, answers with a classic MUA. let bob_answer = b"To: support@example.org, claire@example.org\n\ @@ -3944,7 +3944,7 @@ YEAAAAAA!. check_alias_reply(bob_answer, false, false).await; } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_alias_answer_from_dc() { // Bob, the other supporter, answers with Delta Chat. let bob_answer = b"To: support@example.org, claire@example.org\n\ @@ -3968,7 +3968,7 @@ YEAAAAAA!. check_alias_reply(bob_answer, false, false).await; } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_dont_assign_to_trash_by_parent() { let t = TestContext::new_alice().await; t.set_config(Config::ShowEmails, Some("2")).await.unwrap(); @@ -4016,7 +4016,7 @@ YEAAAAAA!. assert_eq!(msg.text.unwrap(), "Reply"); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_dont_show_all_outgoing_msgs_in_self_chat() { // Regression test for : // Some servers add a `Bcc: ` header, which caused all outgoing messages to @@ -4043,7 +4043,7 @@ Message content", assert_ne!(msg.chat_id, t.get_self_chat().await.id); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_outgoing_classic_mail_creates_chat() { let alice = TestContext::new_alice().await; @@ -4073,7 +4073,7 @@ Message content", assert_eq!(msg.get_text().unwrap(), "Subj – Message content"); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_duplicate_message() -> Result<()> { // Test that duplicate messages are ignored based on the Message-ID let alice = TestContext::new_alice().await; @@ -4132,7 +4132,7 @@ Second signature"; Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_chat_assignment_private_classical_reply() { for outgoing_is_classical in &[true, false] { let t = TestContext::new_alice().await; @@ -4216,7 +4216,7 @@ Private reply"#, } } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_chat_assignment_private_chat_reply() { for (outgoing_is_classical, outgoing_has_multiple_recipients) in &[(true, true), (false, true), (false, false)] @@ -4312,7 +4312,7 @@ Sent with my Delta Chat Messenger: https://delta.chat } } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_chat_assignment_nonprivate_classical_reply() { for outgoing_is_classical in &[true, false] { let t = TestContext::new_alice().await; @@ -4421,7 +4421,7 @@ Reply to all"#, /// messages have the same recipient lists and only differ in the subject and message contents. /// The messages can be properly assigned to chats only using the In-Reply-To or References /// headers. - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_chat_assignment_adhoc() -> Result<()> { let alice = TestContext::new_alice().await; let bob = TestContext::new_alice().await; @@ -4501,7 +4501,7 @@ Second thread."#; } /// Test that read receipts don't create chats. - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_read_receipts_dont_create_chats() -> Result<()> { let alice = TestContext::new_alice().await; let bob = TestContext::new_bob().await; @@ -4534,7 +4534,7 @@ Second thread."#; Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_gmx_forwarded_msg() -> Result<()> { let t = TestContext::new_alice().await; t.set_config(Config::ShowEmails, Some("2")).await?; @@ -4554,7 +4554,7 @@ Second thread."#; } /// Tests that user is notified about new incoming contact requests. - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_incoming_contact_request() -> Result<()> { let t = TestContext::new_alice().await; @@ -4579,7 +4579,7 @@ Second thread."#; } } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_parent_message() -> Result<()> { let t = TestContext::new_alice().await; t.set_config(Config::ShowEmails, Some("2")).await?; @@ -4642,7 +4642,7 @@ Message with references."#; } /// Test a message with RFC 1847 encapsulation as created by Thunderbird. - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_rfc1847_encapsulation() -> Result<()> { let alice = TestContext::new_alice().await; let bob = TestContext::new_bob().await; @@ -4668,7 +4668,7 @@ Message with references."#; Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_invalid_to_address() -> Result<()> { let alice = TestContext::new_alice().await; @@ -4680,7 +4680,7 @@ Message with references."#; Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_reply_from_different_addr() -> Result<()> { let t = TestContext::new_alice().await; t.set_config(Config::ShowEmails, Some("2")).await?; @@ -4745,7 +4745,7 @@ Reply from different address Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_long_filenames() -> Result<()> { let mut tcm = TestContextManager::new().await; let alice = tcm.alice().await; @@ -4800,7 +4800,7 @@ Reply from different address } /// Tests that contact request is accepted automatically on outgoing message. - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_accept_outgoing() -> Result<()> { let mut tcm = TestContextManager::new().await; let alice1 = tcm.alice().await; @@ -4845,7 +4845,7 @@ Reply from different address Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_outgoing_private_reply_multidevice() -> Result<()> { let mut tcm = TestContextManager::new().await; let alice1 = tcm.alice().await; @@ -4922,7 +4922,7 @@ Reply from different address Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_no_private_reply_to_blocked_account() -> Result<()> { let mut tcm = TestContextManager::new().await; let alice = tcm.alice().await; diff --git a/src/dc_tools.rs b/src/dc_tools.rs index 1e7f6f7210..49287d48c9 100644 --- a/src/dc_tools.rs +++ b/src/dc_tools.rs @@ -5,20 +5,19 @@ use core::cmp::{max, min}; use std::borrow::Cow; use std::fmt; use std::io::Cursor; +use std::path::{Path, PathBuf}; use std::str::from_utf8; use std::str::FromStr; use std::time::{Duration, SystemTime}; -use async_std::path::{Path, PathBuf}; -use async_std::prelude::*; -use async_std::{fs, io}; - use anyhow::{bail, Error, Result}; use chrono::{Local, TimeZone}; +use futures::StreamExt; use mailparse::dateparse; use mailparse::headers::Headers; use mailparse::MailHeaderMap; use rand::{thread_rng, Rng}; +use tokio::{fs, io}; use crate::chat::{add_device_msg, add_device_msg_with_importance}; use crate::constants::{DC_ELLIPSIS, DC_OUTDATED_WARNING_DAYS}; @@ -278,7 +277,7 @@ pub fn dc_get_filemeta(buf: &[u8]) -> Result<(u32, u32), Error> { /// /// If `path` starts with "$BLOBDIR", replaces it with the blobdir path. /// Otherwise, returns path as is. -pub(crate) fn dc_get_abs_path>(context: &Context, path: P) -> PathBuf { +pub(crate) fn dc_get_abs_path(context: &Context, path: impl AsRef) -> PathBuf { let p: &Path = path.as_ref(); if let Ok(p) = p.strip_prefix("$BLOBDIR") { context.get_blobdir().join(p) @@ -297,10 +296,10 @@ pub(crate) async fn dc_get_filebytes(context: &Context, path: impl AsRef) pub(crate) async fn dc_delete_file(context: &Context, path: impl AsRef) -> bool { let path_abs = dc_get_abs_path(context, &path); - if !path_abs.exists().await { + if !path_abs.exists() { return false; } - if !path_abs.is_file().await { + if !path_abs.is_file() { warn!( context, "refusing to delete non-file \"{}\".", @@ -323,8 +322,9 @@ pub(crate) async fn dc_delete_file(context: &Context, path: impl AsRef) -> } pub async fn dc_delete_files_in_dir(context: &Context, path: impl AsRef) { - match async_std::fs::read_dir(path).await { - Ok(mut read_dir) => { + match tokio::fs::read_dir(path).await { + Ok(read_dir) => { + let mut read_dir = tokio_stream::wrappers::ReadDirStream::new(read_dir); while let Some(entry) = read_dir.next().await { match entry { Ok(file) => { @@ -344,7 +344,7 @@ pub(crate) async fn dc_create_folder( path: impl AsRef, ) -> Result<(), io::Error> { let path_abs = dc_get_abs_path(context, &path); - if !path_abs.exists().await { + if !path_abs.exists() { match fs::create_dir_all(path_abs).await { Ok(_) => Ok(()), Err(err) => { @@ -655,7 +655,7 @@ mod tests { assert_eq!(hop_info, expected) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_parse_receive_headers_integration() { let raw = include_bytes!("../test-data/message/mail_with_cc.txt"); let expected = r"State: Fresh @@ -873,7 +873,7 @@ Hop: From: hq5.example.org; By: hq5.example.org; Date: Mon, 27 Dec 2021 11:21:22 } } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_file_handling() { let t = TestContext::new().await; let context = &t; @@ -889,8 +889,8 @@ Hop: From: hq5.example.org; By: hq5.example.org; Date: Mon, 27 Dec 2021 11:21:22 assert!(dc_write_file(context, "$BLOBDIR/foobar", b"content") .await .is_ok()); - assert!(dc_file_exist!(context, "$BLOBDIR/foobar").await); - assert!(!dc_file_exist!(context, "$BLOBDIR/foobarx").await); + assert!(dc_file_exist!(context, "$BLOBDIR/foobar")); + assert!(!dc_file_exist!(context, "$BLOBDIR/foobarx")); assert_eq!(dc_get_filebytes(context, "$BLOBDIR/foobar").await, 7); let abs_path = context @@ -899,23 +899,23 @@ Hop: From: hq5.example.org; By: hq5.example.org; Date: Mon, 27 Dec 2021 11:21:22 .to_string_lossy() .to_string(); - assert!(dc_file_exist!(context, &abs_path).await); + assert!(dc_file_exist!(context, &abs_path)); assert!(dc_delete_file(context, "$BLOBDIR/foobar").await); assert!(dc_create_folder(context, "$BLOBDIR/foobar-folder") .await .is_ok()); - assert!(dc_file_exist!(context, "$BLOBDIR/foobar-folder").await); + assert!(dc_file_exist!(context, "$BLOBDIR/foobar-folder")); assert!(!dc_delete_file(context, "$BLOBDIR/foobar-folder").await); let fn0 = "$BLOBDIR/data.data"; assert!(dc_write_file(context, &fn0, b"content").await.is_ok()); assert!(dc_delete_file(context, &fn0).await); - assert!(!dc_file_exist!(context, &fn0).await); + assert!(!dc_file_exist!(context, &fn0)); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_create_smeared_timestamp() { let t = TestContext::new().await; assert_ne!( @@ -931,7 +931,7 @@ Hop: From: hq5.example.org; By: hq5.example.org; Date: Mon, 27 Dec 2021 11:21:22 ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_create_smeared_timestamps() { let t = TestContext::new().await; let count = MAX_SECONDS_TO_LEND_FROM_FUTURE - 1; @@ -1001,7 +1001,7 @@ Hop: From: hq5.example.org; By: hq5.example.org; Date: Mon, 27 Dec 2021 11:21:22 assert_eq!(improve_single_line_input("\r\nahte\n\r"), "ahte"); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_maybe_warn_on_bad_time() { let t = TestContext::new().await; let timestamp_now = time(); @@ -1064,7 +1064,7 @@ Hop: From: hq5.example.org; By: hq5.example.org; Date: Mon, 27 Dec 2021 11:21:22 assert_eq!(msgs.len(), 2); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_maybe_warn_on_outdated() { let t = TestContext::new().await; let timestamp_now: i64 = time(); diff --git a/src/dehtml.rs b/src/dehtml.rs index 5a804d1cb6..3d39080c65 100644 --- a/src/dehtml.rs +++ b/src/dehtml.rs @@ -382,7 +382,7 @@ mod tests { assert_eq!(txt.trim(), "two\nlines"); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_quote_div() { let input = include_str!("../test-data/message/gmx-quote-body.eml"); let dehtml = dehtml(input).unwrap(); diff --git a/src/download.rs b/src/download.rs index 7c0bed1bf0..4682bd4587 100644 --- a/src/download.rs +++ b/src/download.rs @@ -280,7 +280,7 @@ mod tests { ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_download_limit() -> Result<()> { let t = TestContext::new_alice().await; @@ -303,7 +303,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_update_download_state() -> Result<()> { let t = TestContext::new_alice().await; let chat = t.create_chat_with_contact("Bob", "bob@example.org").await; @@ -328,7 +328,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_partial_receive_imf() -> Result<()> { let t = TestContext::new_alice().await; @@ -376,7 +376,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_partial_download_and_ephemeral() -> Result<()> { let t = TestContext::new_alice().await; let chat_id = t diff --git a/src/e2ee.rs b/src/e2ee.rs index c84753a432..311f7d7b9e 100644 --- a/src/e2ee.rs +++ b/src/e2ee.rs @@ -422,7 +422,7 @@ mod tests { mod ensure_secret_key_exists { use super::*; - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_prexisting() { let t = TestContext::new_alice().await; assert_eq!( @@ -431,7 +431,7 @@ mod tests { ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_not_configured() { let t = TestContext::new().await; assert!(ensure_secret_key_exists(&t).await.is_err()); @@ -480,7 +480,7 @@ Sent with my Delta Chat Messenger: https://delta.chat"; assert_eq!(has_decrypted_pgp_armor(data), false); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_encrypted_no_autocrypt() -> anyhow::Result<()> { let alice = TestContext::new_alice().await; let bob = TestContext::new_bob().await; @@ -588,7 +588,7 @@ Sent with my Delta Chat Messenger: https://delta.chat"; vec![(Some(peerstate), addr)] } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_should_encrypt() { let t = TestContext::new_alice().await; let encrypt_helper = EncryptHelper::new(&t).await.unwrap(); @@ -615,7 +615,7 @@ Sent with my Delta Chat Messenger: https://delta.chat"; assert!(!encrypt_helper.should_encrypt(&t, false, &ps).unwrap()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_mixed_up_mime() -> Result<()> { // "Mixed Up" mail as received when sending an encrypted // message using Delta Chat Desktop via ProtonMail IMAP/SMTP diff --git a/src/ephemeral.rs b/src/ephemeral.rs index cd1ec39424..da585b4d3e 100644 --- a/src/ephemeral.rs +++ b/src/ephemeral.rs @@ -62,9 +62,9 @@ use std::str::FromStr; use std::time::{Duration, SystemTime, UNIX_EPOCH}; use anyhow::{ensure, Context as _, Result}; -use async_std::channel::Receiver; -use async_std::future::timeout; +use async_channel::Receiver; use serde::{Deserialize, Serialize}; +use tokio::time::timeout; use crate::chat::{send_msg, ChatId}; use crate::constants::{DC_CHAT_ID_LAST_SPECIAL, DC_CHAT_ID_TRASH}; @@ -581,7 +581,7 @@ mod tests { dc_tools::IsNoneOrEmpty, }; - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_stock_ephemeral_messages() { let context = TestContext::new().await; @@ -711,7 +711,7 @@ mod tests { } /// Test enabling and disabling ephemeral timer remotely. - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_ephemeral_enable_disable() -> Result<()> { let alice = TestContext::new_alice().await; let bob = TestContext::new_bob().await; @@ -743,7 +743,7 @@ mod tests { } /// Test that timer is enabled even if the message explicitly enabling the timer is lost. - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_ephemeral_enable_lost() -> Result<()> { let alice = TestContext::new_alice().await; let bob = TestContext::new_bob().await; @@ -785,7 +785,7 @@ mod tests { /// Test that Alice replying to the chat without a timer at the same time as Bob enables the /// timer does not result in disabling the timer on the Bob's side. - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_ephemeral_timer_rollback() -> Result<()> { let alice = TestContext::new_alice().await; let bob = TestContext::new_bob().await; @@ -859,7 +859,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_ephemeral_delete_msgs() -> Result<()> { let t = TestContext::new_alice().await; let self_chat = t.get_self_chat().await; @@ -985,7 +985,7 @@ mod tests { } } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_delete_expired_imap_messages() -> Result<()> { let t = TestContext::new_alice().await; const HOUR: i64 = 60 * 60; @@ -1096,7 +1096,7 @@ mod tests { } // Regression test for a bug in the timer rollback protection. - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_ephemeral_timer_references() -> Result<()> { let alice = TestContext::new_alice().await; diff --git a/src/events.rs b/src/events.rs index fd82f37a80..17d70e2949 100644 --- a/src/events.rs +++ b/src/events.rs @@ -1,7 +1,8 @@ //! # Events specification. -use async_std::channel::{self, Receiver, Sender, TrySendError}; -use async_std::path::PathBuf; +use std::path::PathBuf; + +use async_channel::{self as channel, Receiver, Sender, TrySendError}; use crate::chat::ChatId; use crate::contact::ContactId; @@ -61,23 +62,18 @@ impl Events { /// /// [`Context`]: crate::context::Context /// [`Context::get_event_emitter`]: crate::context::Context::get_event_emitter -/// [`Stream`]: async_std::stream::Stream +/// [`Stream`]: futures::stream::Stream #[derive(Debug, Clone)] pub struct EventEmitter(Receiver); impl EventEmitter { - /// Blocking recv of an event. Return `None` if the `Sender` has been droped. - pub fn recv_sync(&self) -> Option { - async_std::task::block_on(self.recv()) - } - /// Async recv of an event. Return `None` if the `Sender` has been droped. pub async fn recv(&self) -> Option { self.0.recv().await.ok() } } -impl async_std::stream::Stream for EventEmitter { +impl futures::stream::Stream for EventEmitter { type Item = Event; fn poll_next( diff --git a/src/format_flowed.rs b/src/format_flowed.rs index a58bb8ea7b..cb4c5f0459 100644 --- a/src/format_flowed.rs +++ b/src/format_flowed.rs @@ -203,7 +203,7 @@ mod tests { assert_eq!(format_flowed_quote(quote), expected); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_send_quotes() -> anyhow::Result<()> { let alice = TestContext::new_alice().await; let bob = TestContext::new_bob().await; diff --git a/src/html.rs b/src/html.rs index 43a63b2df1..dbe2b3943a 100644 --- a/src/html.rs +++ b/src/html.rs @@ -284,7 +284,7 @@ mod tests { use crate::message::{MessengerMessage, Viewtype}; use crate::test_utils::TestContext; - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_htmlparse_plain_unspecified() { let t = TestContext::new().await; let raw = include_bytes!("../test-data/message/text_plain_unspecified.eml"); @@ -300,7 +300,7 @@ This message does not have Content-Type nor Subject.
); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_htmlparse_plain_iso88591() { let t = TestContext::new().await; let raw = include_bytes!("../test-data/message/text_plain_iso88591.eml"); @@ -316,7 +316,7 @@ message with a non-UTF-8 encoding: äöüßÄÖÜ
); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_htmlparse_plain_flowed() { let t = TestContext::new().await; let raw = include_bytes!("../test-data/message/text_plain_flowed.eml"); @@ -336,7 +336,7 @@ and will be wrapped as usual.
); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_htmlparse_alt_plain() { let t = TestContext::new().await; let raw = include_bytes!("../test-data/message/text_alt_plain.eml"); @@ -355,7 +355,7 @@ test some special html-characters as < > and & but also " and &#x ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_htmlparse_html() { let t = TestContext::new().await; let raw = include_bytes!("../test-data/message/text_html.eml"); @@ -373,7 +373,7 @@ test some special html-characters as < > and & but also " and &#x ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_htmlparse_alt_html() { let t = TestContext::new().await; let raw = include_bytes!("../test-data/message/text_alt_html.eml"); @@ -388,7 +388,7 @@ test some special html-characters as < > and & but also " and &#x ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_htmlparse_alt_plain_html() { let t = TestContext::new().await; let raw = include_bytes!("../test-data/message/text_alt_plain_html.eml"); @@ -405,7 +405,7 @@ test some special html-characters as < > and & but also " and &#x ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_htmlparse_apple_cid_jpg() { // load raw mime html-data with related image-part (cid:) // and make sure, Content-Id has angle-brackets that are removed correctly. @@ -424,14 +424,14 @@ test some special html-characters as < > and & but also " and &#x assert!(!parser.html.contains("cid:")); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_html_invalid_msgid() { let t = TestContext::new().await; let msg_id = MsgId::new(100); assert!(msg_id.get_html(&t).await.is_err()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_html_forwarding() { // alice receives a non-delta html-message let alice = TestContext::new_alice().await; @@ -478,7 +478,7 @@ test some special html-characters as < > and & but also " and &#x assert!(html.contains("this is html")); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_html_forwarding_encrypted() { // Alice receives a non-delta html-message // (`ShowEmails=1` lets Alice actually receive non-delta messages for known contacts, @@ -515,7 +515,7 @@ test some special html-characters as < > and & but also " and &#x assert!(html.contains("this is html")); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_set_html() { let alice = TestContext::new_alice().await; let bob = TestContext::new_bob().await; @@ -547,7 +547,7 @@ test some special html-characters as < > and & but also " and &#x assert!(html.contains("html text")); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_cp1252_html() -> Result<()> { let t = TestContext::new_alice().await; t.set_config(Config::ShowEmails, Some("2")).await?; diff --git a/src/imap.rs b/src/imap.rs index 6d5ffee5bb..a7a60ea961 100644 --- a/src/imap.rs +++ b/src/imap.rs @@ -11,11 +11,11 @@ use std::{ }; use anyhow::{bail, format_err, Context as _, Result}; +use async_channel::Receiver; use async_imap::types::{ Fetch, Flag, Mailbox, Name, NameAttribute, Quota, QuotaRoot, UnsolicitedResponse, }; -use async_std::channel::Receiver; -use async_std::prelude::*; +use futures::StreamExt; use num_traits::FromPrimitive; use crate::chat::{self, ChatId, ChatIdBlocked}; @@ -1922,7 +1922,7 @@ fn get_folder_meaning_by_name(folder_name: &str) -> FolderMeaning { fn get_folder_meaning(folder_name: &Name) -> FolderMeaning { for attr in folder_name.attributes() { - if let NameAttribute::Custom(ref label) = attr { + if let NameAttribute::Extension(ref label) = attr { match label.as_ref() { "\\Trash" => return FolderMeaning::Other, "\\Sent" => return FolderMeaning::Sent, @@ -2388,7 +2388,7 @@ mod tests { assert_eq!(get_folder_meaning_by_name("SPAM"), FolderMeaning::Spam); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_set_uid_next_validity() { let t = TestContext::new_alice().await; assert_eq!(get_uid_next(&t.ctx, "Inbox").await.unwrap(), 0); @@ -2570,7 +2570,7 @@ mod tests { ("Spam", true, true, "DeltaChat"), ]; - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_target_folder_incoming_accepted() -> Result<()> { for (folder, mvbox_move, chat_msg, expected_destination) in COMBINATIONS_ACCEPTED_CHAT { check_target_folder_combination( @@ -2587,7 +2587,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_target_folder_incoming_request() -> Result<()> { for (folder, mvbox_move, chat_msg, expected_destination) in COMBINATIONS_REQUEST { check_target_folder_combination( @@ -2604,7 +2604,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_target_folder_outgoing() -> Result<()> { // Test outgoing emails for (folder, mvbox_move, chat_msg, expected_destination) in COMBINATIONS_ACCEPTED_CHAT { @@ -2622,7 +2622,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_target_folder_setupmsg() -> Result<()> { // Test setupmessages for (folder, mvbox_move, chat_msg, _expected_destination) in COMBINATIONS_ACCEPTED_CHAT { @@ -2640,7 +2640,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_imap_search_command() -> Result<()> { let t = TestContext::new_alice().await; assert_eq!( diff --git a/src/imap/client.rs b/src/imap/client.rs index 31c10779d0..ed6faa64c8 100644 --- a/src/imap/client.rs +++ b/src/imap/client.rs @@ -8,7 +8,7 @@ use anyhow::{Context as _, Result}; use async_imap::Client as ImapClient; use async_smtp::ServerAddress; -use async_std::net::{self, TcpStream}; +use tokio::net::{self, TcpStream}; use super::session::Session; use crate::login_param::{dc_build_tls, Socks5Config}; diff --git a/src/imap/idle.rs b/src/imap/idle.rs index dcf5ee6f4f..04e9718792 100644 --- a/src/imap/idle.rs +++ b/src/imap/idle.rs @@ -2,7 +2,7 @@ use super::Imap; use anyhow::{bail, Context as _, Result}; use async_imap::extensions::idle::IdleResponse; -use async_std::prelude::*; +use futures_lite::FutureExt; use std::time::{Duration, SystemTime}; use crate::{context::Context, scheduler::InterruptInfo}; @@ -87,9 +87,7 @@ impl Imap { } } - let session = handle - .done() - .timeout(Duration::from_secs(15)) + let session = tokio::time::timeout(Duration::from_secs(15), handle.done()) .await? .context("IMAP IDLE protocol timed out")?; self.session = Some(Session { inner: session }); @@ -121,7 +119,7 @@ impl Imap { // check every minute if there are new messages // TODO: grow sleep durations / make them more flexible - let mut interval = async_std::stream::interval(Duration::from_secs(60)); + let mut interval = tokio::time::interval(Duration::from_secs(60)); enum Event { Tick, @@ -131,7 +129,7 @@ impl Imap { let info = loop { use futures::future::FutureExt; match interval - .next() + .tick() .map(|_| Event::Tick) .race( self.idle_interrupt diff --git a/src/imap/scan_folders.rs b/src/imap/scan_folders.rs index cd4b6820ba..37699b3e4c 100644 --- a/src/imap/scan_folders.rs +++ b/src/imap/scan_folders.rs @@ -1,14 +1,13 @@ use std::{collections::BTreeMap, time::Instant}; use anyhow::{Context as _, Result}; +use futures::stream::StreamExt; use crate::config::Config; use crate::imap::Imap; use crate::log::LogExt; use crate::{context::Context, imap::FolderMeaning}; -use async_std::stream::StreamExt; - use super::{get_folder_meaning, get_folder_meaning_by_name}; impl Imap { @@ -104,7 +103,7 @@ impl Imap { let list = session .list(Some(""), Some("*")) .await? - .filter_map(|f| f.ok_or_log_msg(context, "list_folders() can't get folder")); + .filter_map(|f| async { f.ok_or_log_msg(context, "list_folders() can't get folder") }); Ok(list.collect().await) } } diff --git a/src/imap/session.rs b/src/imap/session.rs index 4b7c7c0012..50005a67ba 100644 --- a/src/imap/session.rs +++ b/src/imap/session.rs @@ -2,8 +2,8 @@ use std::ops::{Deref, DerefMut}; use async_imap::Session as ImapSession; use async_native_tls::TlsStream; -use async_std::net::TcpStream; use fast_socks5::client::Socks5Stream; +use tokio::net::TcpStream; #[derive(Debug)] pub(crate) struct Session { @@ -11,7 +11,7 @@ pub(crate) struct Session { } pub(crate) trait SessionStream: - async_std::io::Read + async_std::io::Write + Unpin + Send + Sync + std::fmt::Debug + tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + Send + Sync + std::fmt::Debug { } diff --git a/src/imex.rs b/src/imex.rs index f649f29ff7..ac2cd8303e 100644 --- a/src/imex.rs +++ b/src/imex.rs @@ -2,16 +2,15 @@ use std::any::Any; use std::ffi::OsStr; +use std::path::{Path, PathBuf}; use ::pgp::types::KeyTrait; use anyhow::{bail, ensure, format_err, Context as _, Result}; -use async_std::{ - fs::{self, File}, - path::{Path, PathBuf}, - prelude::*, -}; -use async_tar::Archive; +use futures::{StreamExt, TryStreamExt}; +use futures_lite::FutureExt; use rand::{thread_rng, Rng}; +use tokio::fs::{self, File}; +use tokio_tar::Archive; use crate::blob::BlobObject; use crate::chat::{self, delete_and_reset_all_device_msgs, ChatId}; @@ -109,24 +108,22 @@ pub async fn imex( /// Returns the filename of the backup found (otherwise an error) pub async fn has_backup(_context: &Context, dir_name: &Path) -> Result { - let mut dir_iter = async_std::fs::read_dir(dir_name).await?; + let mut dir_iter = tokio::fs::read_dir(dir_name).await?; let mut newest_backup_name = "".to_string(); let mut newest_backup_path: Option = None; - while let Some(dirent) = dir_iter.next().await { - if let Ok(dirent) = dirent { - let path = dirent.path(); - let name = dirent.file_name(); - let name: String = name.to_string_lossy().into(); - if name.starts_with("delta-chat") - && name.ends_with(".tar") - && (newest_backup_name.is_empty() || name > newest_backup_name) - { - // We just use string comparison to determine which backup is newer. - // This works fine because the filenames have the form ...delta-chat-backup-2020-07-24-00.tar - newest_backup_path = Some(path); - newest_backup_name = name; - } + while let Ok(Some(dirent)) = dir_iter.next_entry().await { + let path = dirent.path(); + let name = dirent.file_name(); + let name: String = name.to_string_lossy().into(); + if name.starts_with("delta-chat") + && name.ends_with(".tar") + && (newest_backup_name.is_empty() || name > newest_backup_name) + { + // We just use string comparison to determine which backup is newer. + // This works fine because the filenames have the form ...delta-chat-backup-2020-07-24-00.tar + newest_backup_path = Some(path); + newest_backup_name = name; } } @@ -177,7 +174,7 @@ async fn do_initiate_key_transfer(context: &Context) -> Result { let msg_id = chat::send_msg(context, chat_id, &mut msg).await?; info!(context, "Wait for setup message being sent ...",); while !context.shall_stop_ongoing().await { - async_std::task::sleep(std::time::Duration::from_secs(1)).await; + tokio::time::sleep(std::time::Duration::from_secs(1)).await; if let Ok(msg) = Message::load_from_db(context, msg_id).await { if msg.is_sent() { info!(context, "... setup message sent.",); @@ -446,7 +443,7 @@ async fn import_backup( context.sql.config_cache.write().await.clear(); - let archive = Archive::new(backup_file); + let mut archive = Archive::new(backup_file); let mut entries = archive.entries()?; let mut last_progress = 0; @@ -477,7 +474,7 @@ async fn import_backup( // async_tar will unpack to blobdir/BLOBS_BACKUP_NAME, so we move the file afterwards. f.unpack_in(context.get_blobdir()).await?; let from_path = context.get_blobdir().join(f.path()?); - if from_path.is_file().await { + if from_path.is_file() { if let Some(name) = from_path.file_name() { fs::rename(&from_path, context.get_blobdir().join(name)).await?; } else { @@ -499,10 +496,7 @@ async fn import_backup( /// Returns Ok((temp_db_path, temp_path, dest_path)) on success. Unencrypted database can be /// written to temp_db_path. The backup can then be written to temp_path. If the backup succeeded, /// it can be renamed to dest_path. This guarantees that the backup is complete. -async fn get_next_backup_path( - folder: &Path, - backup_time: i64, -) -> Result<(PathBuf, PathBuf, PathBuf)> { +fn get_next_backup_path(folder: &Path, backup_time: i64) -> Result<(PathBuf, PathBuf, PathBuf)> { let folder = PathBuf::from(folder); let stem = chrono::NaiveDateTime::from_timestamp(backup_time, 0) // Don't change this file name format, in has_backup() we use string comparison to determine which backup is newer: @@ -520,7 +514,7 @@ async fn get_next_backup_path( let mut destfile = folder.clone(); destfile.push(format!("{}-{:02}.tar", stem, i)); - if !tempdbfile.exists().await && !tempfile.exists().await && !destfile.exists().await { + if !tempdbfile.exists() && !tempfile.exists() && !destfile.exists() { return Ok((tempdbfile, tempfile, destfile)); } } @@ -530,7 +524,7 @@ async fn get_next_backup_path( async fn export_backup(context: &Context, dir: &Path, passphrase: String) -> Result<()> { // get a fine backup file name (the name includes the date so that multiple backup instances are possible) let now = time(); - let (temp_db_path, temp_path, dest_path) = get_next_backup_path(dir, now).await?; + let (temp_db_path, temp_path, dest_path) = get_next_backup_path(dir, now)?; let _d1 = DeleteOnDrop(temp_db_path.clone()); let _d2 = DeleteOnDrop(temp_path.clone()); @@ -584,7 +578,8 @@ impl Drop for DeleteOnDrop { fn drop(&mut self) { let file = self.0.clone(); // Not using dc_delete_file() here because it would send a DeletedBlobFile event - async_std::task::block_on(fs::remove_file(file)).ok(); + // Hack to avoid panic in nested runtime calls of tokio + std::fs::remove_file(file).ok(); } } @@ -595,19 +590,21 @@ async fn export_backup_inner( ) -> Result<()> { let file = File::create(temp_path).await?; - let mut builder = async_tar::Builder::new(file); + let mut builder = tokio_tar::Builder::new(file); builder .append_path_with_name(temp_db_path, DBFILE_BACKUP_NAME) .await?; - let read_dir: Vec<_> = fs::read_dir(context.get_blobdir()).await?.collect().await; + let read_dir: Vec<_> = + tokio_stream::wrappers::ReadDirStream::new(fs::read_dir(context.get_blobdir()).await?) + .try_collect() + .await?; let count = read_dir.len(); let mut written_files = 0; let mut last_progress = 0; for entry in read_dir.into_iter() { - let entry = entry?; let name = entry.file_name(); if !entry.file_type().await?.is_file() { warn!( @@ -648,9 +645,9 @@ async fn import_self_keys(context: &Context, dir: &Path) -> Result<()> { let mut imported_cnt = 0; let dir_name = dir.to_string_lossy(); - let mut dir_handle = async_std::fs::read_dir(&dir).await?; - while let Some(entry) = dir_handle.next().await { - let entry_fn = entry?.file_name(); + let mut dir_handle = tokio::fs::read_dir(&dir).await?; + while let Ok(Some(entry)) = dir_handle.next_entry().await { + let entry_fn = entry.file_name(); let name_f = entry_fn.to_string_lossy(); let path_plus_name = dir.join(&entry_fn); match dc_get_filesuffix_lc(&name_f) { @@ -800,7 +797,7 @@ mod tests { use ::pgp::armor::BlockType; - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_render_setup_file() { let t = TestContext::new_alice().await; let msg = render_setup_file(&t, "hello").await.unwrap(); @@ -817,7 +814,7 @@ mod tests { assert!(msg.contains("-----END PGP MESSAGE-----\n")); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_render_setup_file_newline_replace() { let t = TestContext::new_alice().await; t.set_stock_translation(StockMessage::AcSetupMsgBody, "hello\r\nthere".to_string()) @@ -828,7 +825,7 @@ mod tests { assert!(msg.contains("

hello
there

")); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_create_setup_code() { let t = TestContext::new().await; let setupcode = create_setup_code(&t); @@ -843,7 +840,7 @@ mod tests { assert_eq!(setupcode.chars().nth(39).unwrap(), '-'); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_export_public_key_to_asc_file() { let context = TestContext::new().await; let key = alice_keypair().public; @@ -853,12 +850,12 @@ mod tests { .is_ok()); let blobdir = context.ctx.get_blobdir().to_str().unwrap(); let filename = format!("{}/public-key-default.asc", blobdir); - let bytes = async_std::fs::read(&filename).await.unwrap(); + let bytes = tokio::fs::read(&filename).await.unwrap(); assert_eq!(bytes, key.to_asc(None).into_bytes()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_export_private_key_to_asc_file() { let context = TestContext::new().await; let key = alice_keypair().secret; @@ -868,12 +865,12 @@ mod tests { .is_ok()); let blobdir = context.ctx.get_blobdir().to_str().unwrap(); let filename = format!("{}/private-key-default.asc", blobdir); - let bytes = async_std::fs::read(&filename).await.unwrap(); + let bytes = tokio::fs::read(&filename).await.unwrap(); assert_eq!(bytes, key.to_asc(None).into_bytes()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_export_and_import_key() { let context = TestContext::new_alice().await; let blobdir = context.ctx.get_blobdir(); @@ -887,7 +884,7 @@ mod tests { } } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_export_and_import_backup() -> Result<()> { let backup_dir = tempfile::tempdir().unwrap(); @@ -896,26 +893,21 @@ mod tests { let context2 = TestContext::new().await; assert!(!context2.is_configured().await?); - assert!(has_backup(&context2, backup_dir.path().as_ref()) - .await - .is_err()); + assert!(has_backup(&context2, backup_dir.path()).await.is_err()); // export from context1 - assert!(imex( - &context1, - ImexMode::ExportBackup, - backup_dir.path().as_ref(), - None, - ) - .await - .is_ok()); + assert!( + imex(&context1, ImexMode::ExportBackup, backup_dir.path(), None) + .await + .is_ok() + ); let _event = context1 .evtracker .get_matching(|evt| matches!(evt, EventType::ImexProgress(1000))) .await; // import to context2 - let backup = has_backup(&context2, backup_dir.path().as_ref()).await?; + let backup = has_backup(&context2, backup_dir.path()).await?; // Import of unencrypted backup with incorrect "foobar" backup passphrase fails. assert!(imex( @@ -961,7 +953,7 @@ mod tests { const S_EM_SETUPCODE: &str = "1742-0185-6197-1303-7016-8412-3581-4441-0597"; const S_EM_SETUPFILE: &str = include_str!("../test-data/message/stress.txt"); - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_split_and_decrypt() { let buf_1 = S_EM_SETUPFILE.as_bytes().to_vec(); let (typ, headers, base64) = split_armored_data(&buf_1).unwrap(); @@ -984,20 +976,20 @@ mod tests { assert!(headers.get(HEADER_SETUPCODE).is_none()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_key_transfer() -> Result<()> { let alice = TestContext::new_alice().await; let alice_clone = alice.clone(); - let key_transfer_task = async_std::task::spawn(async move { + let key_transfer_task = tokio::task::spawn(async move { let ctx = alice_clone; initiate_key_transfer(&ctx).await }); // Wait for the message to be added to the queue. - async_std::task::sleep(std::time::Duration::from_secs(1)).await; + tokio::time::sleep(std::time::Duration::from_secs(1)).await; let sent = alice.pop_sent_msg().await; - let setup_code = key_transfer_task.await?; + let setup_code = key_transfer_task.await??; // Alice sets up a second device. let alice2 = TestContext::new().await; diff --git a/src/job.rs b/src/job.rs index 96f93ef39c..14072d6033 100644 --- a/src/job.rs +++ b/src/job.rs @@ -448,7 +448,7 @@ mod tests { .unwrap(); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_load_next_job_two() -> Result<()> { // We want to ensure that loading jobs skips over jobs which // fails to load from the database instead of failing to load @@ -464,7 +464,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_load_next_job_one() -> Result<()> { let t = TestContext::new().await; diff --git a/src/key.rs b/src/key.rs index d98f149919..545e0c10c4 100644 --- a/src/key.rs +++ b/src/key.rs @@ -11,6 +11,7 @@ use num_traits::FromPrimitive; use pgp::composed::Deserializable; use pgp::ser::Serialize; use pgp::types::{KeyTrait, SecretKeyTrait}; +use tokio::runtime::Handle; use crate::config::Config; use crate::constants::KeyGenType; @@ -219,9 +220,10 @@ async fn generate_keypair(context: &Context) -> Result { let keytype = KeyGenType::from_i32(context.get_config_int(Config::KeyGenType).await?) .unwrap_or_default(); info!(context, "Generating keypair with type {}", keytype); - let keypair = - async_std::task::spawn_blocking(move || crate::pgp::create_keypair(addr, keytype)) - .await?; + let keypair = Handle::current() + .spawn_blocking(move || crate::pgp::create_keypair(addr, keytype)) + .await??; + store_self_keypair(context, &keypair, KeyPairUse::Default).await?; info!( context, @@ -397,8 +399,8 @@ mod tests { use super::*; use crate::test_utils::{alice_keypair, TestContext}; - use async_std::sync::Arc; use once_cell::sync::Lazy; + use std::sync::Arc; static KEYPAIR: Lazy = Lazy::new(alice_keypair); @@ -520,7 +522,7 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD assert_eq!(key, key2); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_load_self_existing() { let alice = alice_keypair(); let t = TestContext::new_alice().await; @@ -530,7 +532,7 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD assert_eq!(alice.secret, seckey); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_load_self_generate_public() { let t = TestContext::new().await; t.set_config(Config::ConfiguredAddr, Some("alice@example.org")) @@ -540,7 +542,7 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD assert!(key.is_ok()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_load_self_generate_secret() { let t = TestContext::new().await; t.set_config(Config::ConfiguredAddr, Some("alice@example.org")) @@ -550,7 +552,7 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD assert!(key.is_ok()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_load_self_generate_concurrent() { use std::thread; @@ -560,11 +562,19 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD .unwrap(); let thr0 = { let ctx = t.clone(); - thread::spawn(move || async_std::task::block_on(SignedPublicKey::load_self(&ctx))) + thread::spawn(move || { + tokio::runtime::Runtime::new() + .unwrap() + .block_on(SignedPublicKey::load_self(&ctx)) + }) }; let thr1 = { let ctx = t.clone(); - thread::spawn(move || async_std::task::block_on(SignedPublicKey::load_self(&ctx))) + thread::spawn(move || { + tokio::runtime::Runtime::new() + .unwrap() + .block_on(SignedPublicKey::load_self(&ctx)) + }) }; let res0 = thr0.join().unwrap(); let res1 = thr1.join().unwrap(); @@ -577,7 +587,7 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD assert_eq!(pubkey.primary_key, KEYPAIR.public.primary_key); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_save_self_key_twice() { // Saving the same key twice should result in only one row in // the keypairs table. diff --git a/src/keyring.rs b/src/keyring.rs index d6e07ce516..192b8de802 100644 --- a/src/keyring.rs +++ b/src/keyring.rs @@ -76,7 +76,7 @@ mod tests { assert_eq!(sec_ring.keys(), [alice.secret]); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_keyring_load_self() { // new_self() implies load_self() let t = TestContext::new_alice().await; diff --git a/src/lib.rs b/src/lib.rs index 9427323a9d..42dbac6a59 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ //! # Delta Chat Core Library. +#![recursion_limit = "256"] #![forbid(unsafe_code)] #![deny( unused, diff --git a/src/location.rs b/src/location.rs index 98fe7ba172..3db46b807f 100644 --- a/src/location.rs +++ b/src/location.rs @@ -1,12 +1,12 @@ //! Location handling. use std::convert::TryFrom; +use std::time::Duration; use anyhow::{ensure, Context as _, Result}; -use async_std::channel::Receiver; -use async_std::future::timeout; +use async_channel::Receiver; use bitflags::bitflags; use quick_xml::events::{BytesEnd, BytesStart, BytesText}; -use std::time::Duration; +use tokio::time::timeout; use crate::chat::{self, ChatId}; use crate::contact::ContactId; @@ -731,7 +731,7 @@ mod tests { use crate::dc_receive_imf::dc_receive_imf; use crate::test_utils::TestContext; - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_kml_parse() { let context = TestContext::new().await; @@ -763,7 +763,7 @@ mod tests { assert_eq!(locations_ref[1].timestamp, 1544739072); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_message_kml() { let context = TestContext::new().await; let timestamp = 1598490000; @@ -791,7 +791,7 @@ mod tests { } /// Tests that location.kml is hidden. - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn receive_location_kml() -> Result<()> { let alice = TestContext::new_alice().await; diff --git a/src/log.rs b/src/log.rs index f9acc3ecc5..4ae368514c 100644 --- a/src/log.rs +++ b/src/log.rs @@ -1,7 +1,6 @@ //! # Logging. use crate::context::Context; -use async_std::task::block_on; #[macro_export] macro_rules! info { @@ -49,15 +48,13 @@ impl Context { /// Set last error string. /// Implemented as blocking as used from macros in different, not always async blocks. pub fn set_last_error(&self, error: &str) { - block_on(async move { - let mut last_error = self.last_error.write().await; - *last_error = error.to_string(); - }); + let mut last_error = self.last_error.write().unwrap(); + *last_error = error.to_string(); } /// Get last error string. - pub async fn get_last_error(&self) -> String { - let last_error = &*self.last_error.read().await; + pub fn get_last_error(&self) -> String { + let last_error = &*self.last_error.read().unwrap(); last_error.clone() } } @@ -159,24 +156,24 @@ mod tests { use crate::test_utils::TestContext; use anyhow::Result; - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_last_error() -> Result<()> { let t = TestContext::new().await; - assert_eq!(t.get_last_error().await, ""); + assert_eq!(t.get_last_error(), ""); error!(t, "foo-error"); - assert_eq!(t.get_last_error().await, "foo-error"); + assert_eq!(t.get_last_error(), "foo-error"); warn!(t, "foo-warning"); - assert_eq!(t.get_last_error().await, "foo-error"); + assert_eq!(t.get_last_error(), "foo-error"); info!(t, "foo-info"); - assert_eq!(t.get_last_error().await, "foo-error"); + assert_eq!(t.get_last_error(), "foo-error"); error!(t, "bar-error"); error!(t, "baz-error"); - assert_eq!(t.get_last_error().await, "baz-error"); + assert_eq!(t.get_last_error(), "baz-error"); Ok(()) } diff --git a/src/login_param.rs b/src/login_param.rs index 2021a18982..9fe58b6c16 100644 --- a/src/login_param.rs +++ b/src/login_param.rs @@ -4,18 +4,16 @@ use std::borrow::Cow; use std::fmt; use std::time::Duration; -use crate::constants::{DC_LP_AUTH_FLAGS, DC_LP_AUTH_NORMAL, DC_LP_AUTH_OAUTH2}; -use crate::provider::{get_provider_by_id, Provider}; -use crate::{context::Context, provider::Socket}; use anyhow::{ensure, Result}; - -use async_std::io; -use async_std::net::TcpStream; - use async_native_tls::Certificate; pub use async_smtp::ServerAddress; use fast_socks5::client::Socks5Stream; use once_cell::sync::Lazy; +use tokio::{io, net::TcpStream}; + +use crate::constants::{DC_LP_AUTH_FLAGS, DC_LP_AUTH_NORMAL, DC_LP_AUTH_OAUTH2}; +use crate::provider::{get_provider_by_id, Provider}; +use crate::{context::Context, provider::Socket}; #[derive(Copy, Clone, Debug, Display, FromPrimitive, PartialEq, Eq)] #[repr(u32)] @@ -424,7 +422,7 @@ mod tests { ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_save_load_login_param() -> Result<()> { let t = TestContext::new().await; @@ -460,7 +458,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_build_tls() -> Result<()> { // we are using some additional root certificates. // make sure, they do not break construction of TlsConnector diff --git a/src/message.rs b/src/message.rs index 7f1b6b598a..20077bc8c3 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1,9 +1,9 @@ //! # Messages and their identifiers. use std::collections::BTreeSet; +use std::path::{Path, PathBuf}; use anyhow::{ensure, format_err, Context as _, Result}; -use async_std::path::{Path, PathBuf}; use deltachat_derive::{FromSql, ToSql}; use rusqlite::types::ValueRef; use serde::{Deserialize, Serialize}; @@ -1857,7 +1857,7 @@ mod tests { ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_prepare_message_and_send() { use crate::config::Config; @@ -1879,7 +1879,7 @@ mod tests { } /// Tests that message cannot be prepared if account has no configured address. - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_prepare_not_configured() { let d = test::TestContext::new().await; let ctx = &d.ctx; @@ -1891,7 +1891,7 @@ mod tests { assert!(chat::prepare_msg(ctx, chat.id, &mut msg).await.is_err()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_parse_webrtc_instance() { let (webrtc_type, url) = Message::parse_webrtc_instance("basicwebrtc:https://foo/bar"); assert_eq!(webrtc_type, VideochatType::BasicWebrtc); @@ -1910,7 +1910,7 @@ mod tests { assert_eq!(url, "https://j.si/foo"); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_create_webrtc_instance() { // webrtc_instance may come from an input field of the ui, be pretty tolerant on input let instance = Message::create_webrtc_instance("https://meet.jit.si/", "123"); @@ -1947,7 +1947,7 @@ mod tests { assert_eq!(instance, "basicwebrtc:https://basic.stuff/12345ab"); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_create_webrtc_instance_noroom() { // webrtc_instance may come from an input field of the ui, be pretty tolerant on input let instance = Message::create_webrtc_instance("bla.foo$NOROOM", "123"); @@ -1967,7 +1967,7 @@ mod tests { assert_eq!(instance, "https://bla.foo/?$NOROOM=123"); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_width_height() { let t = test::TestContext::new().await; @@ -1997,7 +1997,7 @@ mod tests { assert!(has_image); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_quote() { use crate::config::Config; @@ -2033,7 +2033,7 @@ mod tests { assert!(quoted_msg.get_text() == msg2.quoted_text()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_chat_id() { // Alice receives a message that pops up as a contact request let alice = TestContext::new_alice().await; @@ -2057,7 +2057,7 @@ mod tests { assert_eq!(msg.get_text().unwrap(), "hello".to_string()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_set_override_sender_name() { // send message with overridden sender name let alice = TestContext::new_alice().await; @@ -2105,7 +2105,7 @@ mod tests { assert_ne!(chat.typ, Chattype::Mailinglist); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_markseen_msgs() -> Result<()> { let alice = TestContext::new_alice().await; let bob = TestContext::new_bob().await; @@ -2178,7 +2178,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_state() -> Result<()> { let alice = TestContext::new_alice().await; let bob = TestContext::new_bob().await; @@ -2234,7 +2234,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_is_bot() -> Result<()> { let alice = TestContext::new_alice().await; diff --git a/src/mimefactory.rs b/src/mimefactory.rs index fd8cde3314..221ab0fefa 100644 --- a/src/mimefactory.rs +++ b/src/mimefactory.rs @@ -3,9 +3,9 @@ use std::convert::TryInto; use anyhow::{bail, ensure, Context as _, Result}; -use async_std::fs; use chrono::TimeZone; use lettre_email::{mime, Address, Header, MimeMultipartType, PartBuilder}; +use tokio::fs; use crate::blob::BlobObject; use crate::chat::Chat; @@ -1451,9 +1451,9 @@ fn maybe_encode_words(words: &str) -> String { #[cfg(test)] mod tests { - use async_std::fs::File; - use async_std::prelude::*; use mailparse::{addrparse_header, MailHeaderMap}; + use tokio::fs::File; + use tokio::io::AsyncWriteExt; use crate::chat::ChatId; use crate::chat::{ @@ -1556,7 +1556,7 @@ mod tests { assert_eq!(maybe_encode_words("äöü"), "=?utf-8?b?w6TDtsO8?="); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_subject_from_mua() { // 1.: Receive a mail from an MUA assert_eq!( @@ -1590,7 +1590,7 @@ mod tests { ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_subject_from_dc() { // 2. Receive a message from Delta Chat assert_eq!( @@ -1610,7 +1610,7 @@ mod tests { ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_subject_outgoing() { // 3. Send the first message to a new contact let t = TestContext::new_alice().await; @@ -1624,7 +1624,7 @@ mod tests { assert_eq!(first_subject_str(t).await, "Message from Alice"); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_subject_unicode() { // 4. Receive messages with unicode characters and make sure that we do not panic (we do not care about the result) msg_to_subject_str( @@ -1656,7 +1656,7 @@ mod tests { .await; } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_subject_mdn() { // 5. Receive an mdn (read receipt) and make sure the mdn's subject is not used let t = TestContext::new_alice().await; @@ -1706,7 +1706,7 @@ mod tests { assert_eq!("Re: Hello, Bob", mf.subject_str(&t).await.unwrap()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_subject_in_group() -> Result<()> { async fn send_msg_get_subject( t: &TestContext, @@ -1914,7 +1914,7 @@ mod tests { new_msg } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] // This test could still be extended async fn test_render_reply() { let t = TestContext::new_alice().await; @@ -2008,7 +2008,7 @@ mod tests { assert!(!headers.lines().any(|l| l.trim().is_empty())); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_selfavatar_unencrypted() -> anyhow::Result<()> { // create chat with bob, set selfavatar let t = TestContext::new_alice().await; @@ -2065,7 +2065,7 @@ mod tests { } /// Test that removed member address does not go into the `To:` field. - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_remove_member_bcc() -> Result<()> { // Alice creates a group with Bob and Claire and then removes Bob. let alice = TestContext::new_alice().await; @@ -2096,7 +2096,7 @@ mod tests { } /// Tests that standard IMF header "From:" comes before non-standard "Autocrypt:" header. - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_from_before_autocrypt() -> Result<()> { // create chat with bob let t = TestContext::new_alice().await; diff --git a/src/mimeparser.rs b/src/mimeparser.rs index e17a54759f..6761a939aa 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -2,7 +2,6 @@ use std::collections::{HashMap, HashSet}; use std::future::Future; -use std::io::Cursor; use std::pin::Pin; use anyhow::{bail, Context as _, Result}; @@ -1029,9 +1028,8 @@ impl MimeMessage { if decoded_data.is_empty() { return; } - let reader = Cursor::new(decoded_data); let msg_type = if context - .is_webxdc_file(filename, reader) + .is_webxdc_file(filename, decoded_data) .await .unwrap_or(false) { @@ -1750,7 +1748,7 @@ mod tests { } } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_mimeparser_fromheader() { let ctx = TestContext::new_alice().await; @@ -1808,7 +1806,7 @@ mod tests { assert_eq!(contact.display_name, Some("Götz C".to_string())); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_dc_mimeparser_crash() { let context = TestContext::new().await; let raw = include_bytes!("../test-data/message/issue_523.txt"); @@ -1820,7 +1818,7 @@ mod tests { assert_eq!(mimeparser.parts.len(), 1); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_rfc724_mid_exists() { let context = TestContext::new().await; let raw = include_bytes!("../test-data/message/mail_with_message_id.txt"); @@ -1834,7 +1832,7 @@ mod tests { ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_rfc724_mid_not_exists() { let context = TestContext::new().await; let raw = include_bytes!("../test-data/message/issue_523.txt"); @@ -1876,7 +1874,7 @@ mod tests { mail } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_attachment_filename() { let t = TestContext::new().await; let mail = load_mail_with_attachment( @@ -1887,7 +1885,7 @@ mod tests { assert_eq!(filename, Some("test.html".to_string())) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_attachment_filename_encoded_words() { let t = TestContext::new().await; let mail = load_mail_with_attachment( @@ -1898,7 +1896,7 @@ mod tests { assert_eq!(filename, Some("Maßnahmen Okt. 2020.html".to_string())) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_attachment_filename_encoded_words_binary() { let t = TestContext::new().await; let mail = load_mail_with_attachment( @@ -1909,7 +1907,7 @@ mod tests { assert_eq!(filename, Some(" § 165 Abs".to_string())) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_attachment_filename_encoded_words_windows1251() { let t = TestContext::new().await; let mail = load_mail_with_attachment( @@ -1920,7 +1918,7 @@ mod tests { assert_eq!(filename, Some("file Что нового 2020.pdf".to_string())) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_attachment_filename_encoded_words_cont() { // test continued encoded-words and also test apostropes work that way let t = TestContext::new().await; @@ -1932,7 +1930,7 @@ mod tests { assert_eq!(filename, Some("Maßn'ah'men Okt. 2020.html".to_string())) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_attachment_filename_encoded_words_bad_delimiter() { let t = TestContext::new().await; let mail = load_mail_with_attachment( @@ -1944,7 +1942,7 @@ mod tests { assert_eq!(filename, Some("=?utf-8?q?foo?=.bar".to_string())) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_attachment_filename_apostrophed() { let t = TestContext::new().await; let mail = load_mail_with_attachment( @@ -1955,7 +1953,7 @@ mod tests { assert_eq!(filename, Some("Maßnahmen Okt. 2021.html".to_string())) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_attachment_filename_apostrophed_cont() { let t = TestContext::new().await; let mail = load_mail_with_attachment( @@ -1966,7 +1964,7 @@ mod tests { assert_eq!(filename, Some("Maßnahmen März 2022.html".to_string())) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_attachment_filename_apostrophed_windows1251() { let t = TestContext::new().await; let mail = load_mail_with_attachment( @@ -1977,7 +1975,7 @@ mod tests { assert_eq!(filename, Some("программирование.HTM".to_string())) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_attachment_filename_apostrophed_cp1252() { let t = TestContext::new().await; let mail = load_mail_with_attachment( @@ -1988,7 +1986,7 @@ mod tests { assert_eq!(filename, Some("Auftragsbestätigung.pdf".to_string())) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_attachment_filename_apostrophed_invalid() { let t = TestContext::new().await; let mail = load_mail_with_attachment( @@ -1999,7 +1997,7 @@ mod tests { assert_eq!(filename, Some("somedäüta.html.zip".to_string())) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_attachment_filename_combined() { // test that if `filename` and `filename*0` are given, the filename is not doubled let t = TestContext::new().await; @@ -2024,7 +2022,7 @@ mod tests { ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_parse_first_addr() { let context = TestContext::new().await; let raw = b"From: hello@one.org, world@two.org\n\ @@ -2045,7 +2043,7 @@ mod tests { assert!(mimeparser.chat_disposition_notification_to.is_none()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_parent_timestamp() { let context = TestContext::new().await; let raw = b"From: foo@example.org\n\ @@ -2078,7 +2076,7 @@ mod tests { ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_mimeparser_with_context() { let context = TestContext::new().await; let raw = b"From: hello\n\ @@ -2130,7 +2128,7 @@ mod tests { .is_none()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_mimeparser_with_avatars() { let t = TestContext::new().await; @@ -2171,7 +2169,7 @@ mod tests { assert!(mimeparser.group_avatar.unwrap().is_change()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_mimeparser_with_videochat() { let t = TestContext::new().await; @@ -2193,7 +2191,7 @@ mod tests { assert_eq!(mimeparser.group_avatar, None); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_mimeparser_message_kml() { let context = TestContext::new().await; let raw = b"Chat-Version: 1.0\n\ @@ -2238,7 +2236,7 @@ Content-Disposition: attachment; filename=\"message.kml\"\n\ assert_eq!(mimeparser.parts.len(), 1); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_parse_mdn() { let context = TestContext::new().await; let raw = b"Subject: =?utf-8?q?Chat=3A_Message_opened?=\n\ @@ -2288,7 +2286,7 @@ Disposition: manual-action/MDN-sent-automatically; displayed\n\ /// /// RFC 6522 specifically allows MDNs to be nested inside /// multipart MIME messages. - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_parse_multiple_mdns() { let context = TestContext::new().await; let raw = b"Subject: =?utf-8?q?Chat=3A_Message_opened?=\n\ @@ -2364,7 +2362,7 @@ Disposition: manual-action/MDN-sent-automatically; displayed\n\ assert_eq!(message.mdn_reports.len(), 2); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_parse_mdn_with_additional_message_ids() { let context = TestContext::new().await; let raw = b"Subject: =?utf-8?q?Chat=3A_Message_opened?=\n\ @@ -2419,7 +2417,7 @@ Additional-Message-IDs: \n\ ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_parse_inline_attachment() { let context = TestContext::new().await; let raw = br#"Date: Thu, 13 Feb 2020 22:41:20 +0000 (UTC) @@ -2459,7 +2457,7 @@ MDYyMDYxNTE1RTlDOEE4Cj4+CnN0YXJ0eHJlZgo4Mjc4CiUlRU9GCg== assert_eq!(message.parts[0].msg, "Mail with inline attachment – Hello!"); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_hide_html_without_content() { let t = TestContext::new().await; let raw = br#"Date: Thu, 13 Feb 2020 22:41:20 +0000 (UTC) @@ -2503,12 +2501,12 @@ MDYyMDYxNTE1RTlDOEE4Cj4+CnN0YXJ0eHJlZgo4Mjc4CiUlRU9GCg== .await .unwrap() .unwrap(); - let f = async_std::fs::File::open(blob.to_abs_path()).await.unwrap(); + let f = tokio::fs::File::open(blob.to_abs_path()).await.unwrap(); let size = f.metadata().await.unwrap().len(); assert_eq!(size, 154); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn parse_inline_image() { let context = TestContext::new().await; let raw = br#"Message-ID: @@ -2554,7 +2552,7 @@ CWt6wx7fiLp0qS9RrX75g6Gqw7nfCs6EcBERcIPt7DTe8VStJwf3LWqVwxl4gQl46yhfoqwEO+I= assert_eq!(message.parts[0].msg, "example – Test"); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn parse_thunderbird_html_embedded_image() { let context = TestContext::new().await; let raw = br#"To: Alice @@ -2627,7 +2625,7 @@ CWt6wx7fiLp0qS9RrX75g6Gqw7nfCs6EcBERcIPt7DTe8VStJwf3LWqVwxl4gQl46yhfoqwEO+I= } // Outlook specifies filename in the "name" attribute of Content-Type - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn parse_outlook_html_embedded_image() { let context = TestContext::new().await; let raw = br##"From: Anonymous @@ -2766,7 +2764,7 @@ CWt6wx7fiLp0qS9RrX75g6Gqw7nfCs6EcBERcIPt7DTe8VStJwf3LWqVwxl4gQl46yhfoqwEO+I= assert!(test.is_empty()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn parse_format_flowed_quote() { let context = TestContext::new().await; let raw = br##"Content-Type: text/plain; charset=utf-8; format=flowed; delsp=no @@ -2802,7 +2800,7 @@ Reply assert_eq!(message.parts[0].msg, "Reply"); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn parse_quote_without_reply() { let context = TestContext::new().await; let raw = br##"Content-Type: text/plain; charset=utf-8; format=flowed; delsp=no @@ -2834,7 +2832,7 @@ From: alice assert_eq!(message.parts[0].msg, ""); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn parse_quote_top_posting() { let context = TestContext::new().await; let raw = br##"Content-Type: text/plain; charset=utf-8; format=flowed; delsp=no @@ -2865,7 +2863,7 @@ On 2020-10-25, Bob wrote: assert_eq!(message.parts[0].msg, "A reply."); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_attachment_quote() { let context = TestContext::new().await; let raw = include_bytes!("../test-data/message/quote_attach.eml"); @@ -2883,7 +2881,7 @@ On 2020-10-25, Bob wrote: assert_eq!(mimeparser.parts[0].typ, Viewtype::File); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_quote_div() { let t = TestContext::new().await; let raw = include_bytes!("../test-data/message/gmx-quote.eml"); @@ -2892,7 +2890,7 @@ On 2020-10-25, Bob wrote: assert_eq!(mimeparser.parts[0].param.get(Param::Quote).unwrap(), "Now?"); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_allinkl_blockquote() { // all-inkl.com puts quotes into `
`. let t = TestContext::new().await; @@ -2905,7 +2903,7 @@ On 2020-10-25, Bob wrote: ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_add_subj_to_multimedia_msg() { let t = TestContext::new_alice().await; t.set_config(Config::ShowEmails, Some("2")).await.unwrap(); @@ -2938,7 +2936,7 @@ On 2020-10-25, Bob wrote: assert_eq!(msg.get_filemime().unwrap(), "image/png"); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_mime_modified_plain() { let t = TestContext::new().await; let raw = include_bytes!("../test-data/message/text_plain_unspecified.eml"); @@ -2950,7 +2948,7 @@ On 2020-10-25, Bob wrote: ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_mime_modified_alt_plain_html() { let t = TestContext::new().await; let raw = include_bytes!("../test-data/message/text_alt_plain_html.eml"); @@ -2962,7 +2960,7 @@ On 2020-10-25, Bob wrote: ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_mime_modified_alt_plain() { let t = TestContext::new().await; let raw = include_bytes!("../test-data/message/text_alt_plain.eml"); @@ -2977,7 +2975,7 @@ On 2020-10-25, Bob wrote: ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_mime_modified_alt_html() { let t = TestContext::new().await; let raw = include_bytes!("../test-data/message/text_alt_html.eml"); @@ -2989,7 +2987,7 @@ On 2020-10-25, Bob wrote: ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_mime_modified_html() { let t = TestContext::new().await; let raw = include_bytes!("../test-data/message/text_html.eml"); @@ -3001,7 +2999,7 @@ On 2020-10-25, Bob wrote: ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_mime_modified_large_plain() { let t = TestContext::new().await; @@ -3022,7 +3020,7 @@ On 2020-10-25, Bob wrote: assert!(mimemsg.parts[0].msg.len() <= DC_DESIRED_TEXT_LEN + DC_ELLIPSIS.len()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_x_microsoft_original_message_id() { let t = TestContext::new().await; let message = MimeMessage::from_bytes(&t, b"Date: Wed, 17 Feb 2021 15:45:15 +0000\n\ @@ -3045,7 +3043,7 @@ On 2020-10-25, Bob wrote: ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_long_in_reply_to() -> Result<()> { let t = TestContext::new_alice().await; @@ -3088,7 +3086,7 @@ Some reply } // Test that WantsMdn parameter is not set on outgoing messages. - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_outgoing_wants_mdn() -> Result<()> { let alice = TestContext::new_alice().await; let bob = TestContext::new_bob().await; @@ -3119,7 +3117,7 @@ Message. Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_ignore_read_receipt_to_self() -> Result<()> { let alice = TestContext::new_alice().await; @@ -3189,7 +3187,7 @@ Message. /// /// It does not have required Original-Message-ID field, so it is useless, but we want to /// recognize it as MDN nevertheless to avoid displaying it in the chat as normal message. - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_ms_exchange_mdn() -> Result<()> { let t = TestContext::new_alice().await; t.set_config(Config::ShowEmails, Some("2")).await?; diff --git a/src/oauth2.rs b/src/oauth2.rs index f525f89666..8eb91bb019 100644 --- a/src/oauth2.rs +++ b/src/oauth2.rs @@ -156,21 +156,21 @@ pub async fn dc_get_oauth2_access_token( } // ... and POST - let mut req = surf::post(post_url).build(); - if let Err(err) = req.body_form(&post_param) { - warn!(context, "Error calling OAuth2 at {}: {:?}", token_url, err); - return Ok(None); - } - - let client = surf::Client::new(); - let parsed: Result = client.recv_json(req).await; - let response = match parsed { - Ok(response) => response, + let client = reqwest::Client::new(); + + let response: Response = match client.post(post_url).form(&post_param).send().await { + Ok(resp) => match resp.json().await { + Ok(response) => response, + Err(err) => { + warn!( + context, + "Failed to parse OAuth2 JSON response from {}: error: {}", token_url, err + ); + return Ok(None); + } + }, Err(err) => { - warn!( - context, - "Failed to parse OAuth2 JSON response from {}: error: {}", token_url, err - ); + warn!(context, "Error calling OAuth2 at {}: {:?}", token_url, err); return Ok(None); } }; @@ -288,8 +288,14 @@ impl Oauth2 { // "verified_email": true, // "picture": "https://lh4.googleusercontent.com/-Gj5jh_9R0BY/AAAAAAAAAAI/AAAAAAAAAAA/IAjtjfjtjNA/photo.jpg" // } - let response: Result, surf::Error> = - surf::get(userinfo_url).recv_json().await; + let response = match reqwest::get(userinfo_url).await { + Ok(response) => response, + Err(err) => { + warn!(context, "failed to get userinfo: {}", err); + return None; + } + }; + let response: Result, _> = response.json().await; let parsed = match response { Ok(parsed) => parsed, Err(err) => { @@ -360,7 +366,7 @@ mod tests { ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_oauth_from_address() { let t = TestContext::new().await; assert_eq!( @@ -382,7 +388,7 @@ mod tests { assert_eq!(Oauth2::from_address(&t, "hello@web.de", false).await, None); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_oauth_from_mx() { // youtube staff seems to use "google workspace with oauth2", figures this out by MX lookup let t = TestContext::new().await; @@ -397,7 +403,7 @@ mod tests { ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_dc_get_oauth2_addr() { let ctx = TestContext::new().await; let addr = "dignifiedquire@gmail.com"; @@ -407,7 +413,7 @@ mod tests { assert_eq!(res, None); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_dc_get_oauth2_url() { let ctx = TestContext::new().await; let addr = "dignifiedquire@gmail.com"; @@ -419,7 +425,7 @@ mod tests { assert_eq!(res, Some("https://accounts.google.com/o/oauth2/auth?client_id=959970109878%2D4mvtgf6feshskf7695nfln6002mom908%2Eapps%2Egoogleusercontent%2Ecom&redirect_uri=chat%2Edelta%3A%2Fcom%2Eb44t%2Emessenger&response_type=code&scope=https%3A%2F%2Fmail.google.com%2F%20email&access_type=offline".into())); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_dc_get_oauth2_token() { let ctx = TestContext::new().await; let addr = "dignifiedquire@gmail.com"; diff --git a/src/param.rs b/src/param.rs index 0763da40ad..d2739ec08f 100644 --- a/src/param.rs +++ b/src/param.rs @@ -1,9 +1,9 @@ use std::collections::BTreeMap; use std::fmt; +use std::path::PathBuf; use std::str; use anyhow::{bail, Error, Result}; -use async_std::path::PathBuf; use num_traits::FromPrimitive; use serde::{Deserialize, Serialize}; @@ -434,12 +434,13 @@ impl<'a> ParamsFile<'a> { mod tests { use super::*; + use std::path::Path; + use std::str::FromStr; + use anyhow::Result; - use async_std::fs; - use async_std::path::Path; + use tokio::fs; use crate::test_utils::TestContext; - use std::str::FromStr; #[test] fn test_dc_param() { @@ -485,7 +486,7 @@ mod tests { assert_eq!(params.to_string().parse::().unwrap(), params); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_params_file_fs_path() { let t = TestContext::new().await; if let ParamsFile::FsPath(p) = ParamsFile::from_param(&t, "/foo/bar/baz").unwrap() { @@ -495,7 +496,7 @@ mod tests { } } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_params_file_blob() { let t = TestContext::new().await; if let ParamsFile::Blob(b) = ParamsFile::from_param(&t, "$BLOBDIR/foo").unwrap() { @@ -506,7 +507,7 @@ mod tests { } // Tests for Params::get_file(), Params::get_path() and Params::get_blob(). - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_params_get_fileparam() { let t = TestContext::new().await; let fname = t.dir.path().join("foo"); @@ -514,10 +515,9 @@ mod tests { p.set(Param::File, fname.to_str().unwrap()); let file = p.get_file(Param::File, &t).unwrap().unwrap(); - assert_eq!(file, ParamsFile::FsPath(fname.clone().into())); + assert_eq!(file, ParamsFile::FsPath(fname.clone())); let path: PathBuf = p.get_path(Param::File, &t).unwrap().unwrap(); - let fname: PathBuf = fname.into(); assert_eq!(path, fname); // Blob does not exist yet, expect error. @@ -539,7 +539,7 @@ mod tests { assert!(p.get_blob(Param::File, &t, false).await.unwrap().is_none()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_params_unknown_key() -> Result<()> { // 'Z' is used as a key that is known to be unused; these keys should be ignored silently by definition. let p = Params::from_str("w=12\nZ=13\nh=14")?; diff --git a/src/peerstate.rs b/src/peerstate.rs index ffcdc53011..16e9deb01c 100644 --- a/src/peerstate.rs +++ b/src/peerstate.rs @@ -552,7 +552,7 @@ mod tests { use super::*; use crate::test_utils::alice_keypair; - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_peerstate_save_to_db() { let ctx = crate::test_utils::TestContext::new().await; let addr = "hello@mail.com"; @@ -596,7 +596,7 @@ mod tests { assert_eq!(peerstate, peerstate_new2); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_peerstate_double_create() { let ctx = crate::test_utils::TestContext::new().await; let addr = "hello@mail.com"; @@ -628,7 +628,7 @@ mod tests { ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_peerstate_with_empty_gossip_key_save_to_db() { let ctx = crate::test_utils::TestContext::new().await; let addr = "hello@mail.com"; @@ -665,7 +665,7 @@ mod tests { assert_eq!(Some(peerstate), peerstate_new); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_peerstate_load_db_defaults() { let ctx = crate::test_utils::TestContext::new().await; let addr = "hello@mail.com"; @@ -694,7 +694,7 @@ mod tests { assert_eq!(peerstate.verified_key_fingerprint, None); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_peerstate_degrade_reordering() { let addr = "example@example.org"; let pub_key = alice_keypair().public; diff --git a/src/pgp.rs b/src/pgp.rs index f470736c25..ba90ea7dab 100644 --- a/src/pgp.rs +++ b/src/pgp.rs @@ -15,6 +15,7 @@ use pgp::types::{ CompressionAlgorithm, KeyTrait, Mpi, PublicKeyTrait, SecretKeyTrait, StringToKey, }; use rand::{thread_rng, CryptoRng, Rng}; +use tokio::runtime::Handle; use crate::constants::KeyGenType; use crate::dc_tools::EmailAddress; @@ -224,32 +225,33 @@ pub async fn pk_encrypt( ) -> Result { let lit_msg = Message::new_literal_bytes("", plain); - async_std::task::spawn_blocking(move || { - let pkeys: Vec = public_keys_for_encryption - .keys() - .iter() - .filter_map(select_pk_for_encryption) - .collect(); - let pkeys_refs: Vec<&SignedPublicKeyOrSubkey> = pkeys.iter().collect(); - - let mut rng = thread_rng(); - - // TODO: measure time - let encrypted_msg = if let Some(ref skey) = private_key_for_signing { - lit_msg - .sign(skey, || "".into(), Default::default()) - .and_then(|msg| msg.compress(CompressionAlgorithm::ZLIB)) - .and_then(|msg| msg.encrypt_to_keys(&mut rng, Default::default(), &pkeys_refs)) - } else { - lit_msg.encrypt_to_keys(&mut rng, Default::default(), &pkeys_refs) - }; - - let msg = encrypted_msg?; - let encoded_msg = msg.to_armored_string(None)?; - - Ok(encoded_msg) - }) - .await + Handle::current() + .spawn_blocking(move || { + let pkeys: Vec = public_keys_for_encryption + .keys() + .iter() + .filter_map(select_pk_for_encryption) + .collect(); + let pkeys_refs: Vec<&SignedPublicKeyOrSubkey> = pkeys.iter().collect(); + + let mut rng = thread_rng(); + + // TODO: measure time + let encrypted_msg = if let Some(ref skey) = private_key_for_signing { + lit_msg + .sign(skey, || "".into(), Default::default()) + .and_then(|msg| msg.compress(CompressionAlgorithm::ZLIB)) + .and_then(|msg| msg.encrypt_to_keys(&mut rng, Default::default(), &pkeys_refs)) + } else { + lit_msg.encrypt_to_keys(&mut rng, Default::default(), &pkeys_refs) + }; + + let msg = encrypted_msg?; + let encoded_msg = msg.to_armored_string(None)?; + + Ok(encoded_msg) + }) + .await? } /// Decrypts the message with keys from the private key keyring. @@ -268,7 +270,7 @@ pub async fn pk_decrypt( ) -> Result<(Vec, HashSet)> { let mut ret_signature_fingerprints: HashSet = Default::default(); - let msgs = async_std::task::spawn_blocking(move || { + let msgs = tokio::task::spawn_blocking(move || { let cursor = Cursor::new(ctext); let (msg, _) = Message::from_armor_single(cursor)?; @@ -277,7 +279,7 @@ pub async fn pk_decrypt( let (decryptor, _) = msg.decrypt(|| "".into(), || "".into(), &skeys[..])?; decryptor.collect::>>() }) - .await?; + .await??; if let Some(msg) = msgs.into_iter().next() { // get_content() will decompress the message if needed, @@ -342,7 +344,7 @@ pub async fn symm_encrypt(passphrase: &str, plain: &[u8]) -> Result { let lit_msg = Message::new_literal_bytes("", plain); let passphrase = passphrase.to_string(); - async_std::task::spawn_blocking(move || { + tokio::task::spawn_blocking(move || { let mut rng = thread_rng(); let s2k = StringToKey::new_default(&mut rng); let msg = @@ -352,7 +354,7 @@ pub async fn symm_encrypt(passphrase: &str, plain: &[u8]) -> Result { Ok(encoded_msg) }) - .await + .await? } /// Symmetric decryption. @@ -363,7 +365,7 @@ pub async fn symm_decrypt( let (enc_msg, _) = Message::from_armor_single(ctext)?; let passphrase = passphrase.to_string(); - async_std::task::spawn_blocking(move || { + tokio::task::spawn_blocking(move || { let decryptor = enc_msg.decrypt_with_password(|| passphrase)?; let msgs = decryptor.collect::>>()?; @@ -376,7 +378,7 @@ pub async fn symm_decrypt( bail!("No valid messages found") } }) - .await + .await? } #[cfg(test)] @@ -487,7 +489,7 @@ mod tests { assert!(CTEXT_UNSIGNED.starts_with("-----BEGIN PGP MESSAGE-----")); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_decrypt_singed() { // Check decrypting as Alice let mut decrypt_keyring: Keyring = Keyring::new(); @@ -520,7 +522,7 @@ mod tests { assert_eq!(valid_signatures.len(), 1); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_decrypt_no_sig_check() { let mut keyring = Keyring::new(); keyring.add(KEYS.alice_secret.clone()); @@ -533,7 +535,7 @@ mod tests { assert_eq!(valid_signatures.len(), 0); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_decrypt_signed_no_key() { // The validation does not have the public key of the signer. let mut decrypt_keyring = Keyring::new(); @@ -551,7 +553,7 @@ mod tests { assert_eq!(valid_signatures.len(), 0); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_decrypt_unsigned() { let mut decrypt_keyring = Keyring::new(); decrypt_keyring.add(KEYS.bob_secret.clone()); diff --git a/src/plaintext.rs b/src/plaintext.rs index 0f1082ea5e..cdd8a2e1df 100644 --- a/src/plaintext.rs +++ b/src/plaintext.rs @@ -99,7 +99,7 @@ impl PlainText { mod tests { use super::*; - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_plain_to_html() { let html = PlainText { text: r##"line 1 @@ -127,7 +127,7 @@ line with https://link-mid-of-line.org here!"#.to_string(), @@ -146,7 +146,7 @@ line with <http://encapsulated.l ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_plain_to_html_nolink() { let html = PlainText { text: r#"line with nohttp://no.link here"#.to_string(), @@ -165,7 +165,7 @@ line with nohttp://no.link here
); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_plain_to_html_mailto() { let html = PlainText { text: r#"just an address: foo@bar.org another@one.de"#.to_string(), @@ -184,7 +184,7 @@ just an address:
foo@bar.org quote \n>still quote\n >no quote".to_string(), @@ -206,7 +206,7 @@ line still line
); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_plain_to_html_flowed_delsp() { let html = PlainText { text: "line \nstill line\n>quote \n>still quote\n >no quote".to_string(), @@ -228,7 +228,7 @@ linestill line
); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_plain_to_html_fixed() { let html = PlainText { text: "line \nstill line\n>quote \n>still quote\n >no quote".to_string(), diff --git a/src/provider.rs b/src/provider.rs index bdba76a65c..01ad90f886 100644 --- a/src/provider.rs +++ b/src/provider.rs @@ -6,8 +6,8 @@ use crate::config::Config; use crate::context::Context; use crate::provider::data::{PROVIDER_DATA, PROVIDER_IDS, PROVIDER_UPDATED}; use anyhow::Result; -use async_std_resolver::{config, resolver, resolver_from_system_conf, AsyncStdResolver}; use chrono::{NaiveDateTime, NaiveTime}; +use trust_dns_resolver::{config, AsyncResolver, TokioAsyncResolver}; #[derive(Debug, Display, Copy, Clone, PartialEq, FromPrimitive, ToPrimitive)] #[repr(u8)] @@ -85,18 +85,17 @@ pub struct Provider { /// Get resolver to query MX records. /// -/// We first try resolver_from_system_conf() which reads the system's resolver from `/etc/resolv.conf`. -/// This does not work at least on some Androids, therefore we use use ResolverConfig::default() -/// which default eg. to google's 8.8.8.8 or 8.8.4.4 as a fallback. -async fn get_resolver() -> Result { - if let Ok(resolver) = resolver_from_system_conf().await { +/// We first try to read the system's resolver from `/etc/resolv.conf`. +/// This does not work at least on some Androids, therefore we fallback +/// to the default `ResolverConfig` which uses eg. to google's `8.8.8.8` or `8.8.4.4`. +fn get_resolver() -> Result { + if let Ok(resolver) = AsyncResolver::tokio_from_system_conf() { return Ok(resolver); } - let resolver = resolver( + let resolver = AsyncResolver::tokio( config::ResolverConfig::default(), config::ResolverOpts::default(), - ) - .await?; + )?; Ok(resolver) } @@ -141,7 +140,7 @@ pub fn get_provider_by_domain(domain: &str) -> Option<&'static Provider> { /// /// For security reasons, only Gmail can be configured this way. pub async fn get_provider_by_mx(context: &Context, domain: &str) -> Option<&'static Provider> { - if let Ok(resolver) = get_resolver().await { + if let Ok(resolver) = get_resolver() { let mut fqdn: String = domain.to_string(); if !fqdn.ends_with('.') { fqdn.push('.'); @@ -242,7 +241,7 @@ mod tests { assert!(provider.id == "gmail"); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_provider_info() { let t = TestContext::new().await; assert!(get_provider_info(&t, "", false).await.is_none()); @@ -270,9 +269,9 @@ mod tests { assert!(get_provider_update_timestamp() > timestamp_past); } - #[async_std::test] - async fn test_get_resolver() -> Result<()> { - assert!(get_resolver().await.is_ok()); + #[test] + fn test_get_resolver() -> Result<()> { + assert!(get_resolver().is_ok()); Ok(()) } } diff --git a/src/qr.rs b/src/qr.rs index 6046049fa8..20edeb3b8f 100644 --- a/src/qr.rs +++ b/src/qr.rs @@ -1,6 +1,6 @@ //! # QR code module. -use anyhow::{bail, ensure, format_err, Context as _, Error, Result}; +use anyhow::{bail, ensure, Context as _, Error, Result}; use once_cell::sync::Lazy; use percent_encoding::percent_decode_str; use serde::Deserialize; @@ -355,13 +355,13 @@ struct CreateAccountResponse { async fn set_account_from_qr(context: &Context, qr: &str) -> Result<()> { let url_str = &qr[DCACCOUNT_SCHEME.len()..]; - let parsed: CreateAccountResponse = surf::post(url_str).recv_json().await.map_err(|err| { - format_err!( - "Cannot create account, request to {:?} failed: {}", - url_str, - err - ) - })?; + let parsed: CreateAccountResponse = reqwest::Client::new() + .post(url_str) + .send() + .await? + .json() + .await + .with_context(|| format!("Cannot create account, request to {:?} failed", url_str))?; context .set_config(Config::Addr, Some(&parsed.email)) @@ -565,7 +565,7 @@ mod tests { use crate::test_utils::{alice_keypair, TestContext}; use anyhow::Result; - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_decode_http() -> Result<()> { let ctx = TestContext::new().await; @@ -580,7 +580,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_decode_https() -> Result<()> { let ctx = TestContext::new().await; @@ -595,7 +595,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_decode_text() -> Result<()> { let ctx = TestContext::new().await; @@ -610,7 +610,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_decode_vcard() -> Result<()> { let ctx = TestContext::new().await; @@ -632,7 +632,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_decode_matmsg() -> Result<()> { let ctx = TestContext::new().await; @@ -652,7 +652,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_decode_mailto() -> Result<()> { let ctx = TestContext::new().await; @@ -682,7 +682,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_decode_smtp() -> Result<()> { let ctx = TestContext::new().await; @@ -698,7 +698,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_decode_openpgp_group() -> Result<()> { let ctx = TestContext::new().await; let qr = check_qr( @@ -741,7 +741,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_decode_openpgp_secure_join() -> Result<()> { let ctx = TestContext::new().await; @@ -788,7 +788,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_decode_openpgp_fingerprint() -> Result<()> { let ctx = TestContext::new().await; @@ -850,7 +850,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_decode_openpgp_without_addr() -> Result<()> { let ctx = TestContext::new().await; @@ -886,7 +886,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_withdraw_verifycontact() -> Result<()> { let alice = TestContext::new_alice().await; let qr = dc_get_securejoin_qr(&alice, None).await?; @@ -920,7 +920,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_withdraw_verifygroup() -> Result<()> { let alice = TestContext::new_alice().await; let chat_id = create_group_chat(&alice, ProtectionStatus::Unprotected, "foo").await?; @@ -953,7 +953,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_decode_account() -> Result<()> { let ctx = TestContext::new().await; @@ -985,7 +985,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_decode_webrtc_instance() -> Result<()> { let ctx = TestContext::new().await; @@ -1011,7 +1011,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_decode_account_bad_scheme() { let ctx = TestContext::new().await; let res = check_qr( @@ -1030,7 +1030,7 @@ mod tests { assert!(res.is_err()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_set_config_from_qr() -> Result<()> { let ctx = TestContext::new().await; diff --git a/src/qr_code_generator.rs b/src/qr_code_generator.rs index 502b0ba8a6..a4d90ed4e7 100644 --- a/src/qr_code_generator.rs +++ b/src/qr_code_generator.rs @@ -25,7 +25,7 @@ async fn generate_join_group_qr_code(context: &Context, chat_id: ChatId) -> Resu let avatar = match chat.get_profile_image(context).await? { Some(path) => { let avatar_blob = BlobObject::from_path(context, &path)?; - Some(std::fs::read(avatar_blob.to_abs_path())?) + Some(tokio::fs::read(avatar_blob.to_abs_path()).await?) } None => None, }; @@ -45,7 +45,7 @@ async fn generate_verification_qr(context: &Context) -> Result { let avatar = match contact.get_profile_image(context).await? { Some(path) => { let avatar_blob = BlobObject::from_path(context, &path)?; - Some(std::fs::read(avatar_blob.to_abs_path())?) + Some(tokio::fs::read(avatar_blob.to_abs_path()).await?) } None => None, }; @@ -266,7 +266,7 @@ fn inner_generate_secure_join_qr_code( mod tests { use super::*; - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_svg_escaping() { let svg = inner_generate_secure_join_qr_code( "descr123 \" < > &", diff --git a/src/quota.rs b/src/quota.rs index 1820e6e2fd..2dc5525376 100644 --- a/src/quota.rs +++ b/src/quota.rs @@ -180,7 +180,7 @@ mod tests { QUOTA_WARN_THRESHOLD_PERCENTAGE, }; - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_needs_quota_warning() -> Result<()> { assert!(!needs_quota_warning(0, 0)); assert!(!needs_quota_warning(10, 0)); @@ -199,7 +199,7 @@ mod tests { } #[allow(clippy::assertions_on_constants)] - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_quota_thresholds() -> anyhow::Result<()> { assert!(QUOTA_ALLCLEAR_PERCENTAGE > 50); assert!(QUOTA_ALLCLEAR_PERCENTAGE < QUOTA_WARN_THRESHOLD_PERCENTAGE); diff --git a/src/scheduler.rs b/src/scheduler.rs index 2febdd473e..46b98ba710 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -1,9 +1,8 @@ use anyhow::{bail, Context as _, Result}; -use async_std::prelude::*; -use async_std::{ - channel::{self, Receiver, Sender}, - future, task, -}; +use async_channel::{self as channel, Receiver, Sender}; +use futures::{join, try_join}; +use futures_lite::FutureExt; +use tokio::task; use crate::config::Config; use crate::context::Context; @@ -338,7 +337,7 @@ async fn smtp_loop(ctx: Context, started: Sender<()>, smtp_handlers: SmtpConnect "smtp got rate limited, waiting for {} until can send again", duration_to_str(duration_until_can_send) ); - async_std::future::timeout(duration_until_can_send, async { + tokio::time::timeout(duration_until_can_send, async { idle_interrupt_receiver.recv().await.unwrap_or_default() }) .await @@ -367,7 +366,7 @@ async fn smtp_loop(ctx: Context, started: Sender<()>, smtp_handlers: SmtpConnect "smtp has messages to retry, planning to retry {} seconds later", timeout ); let duration = std::time::Duration::from_secs(timeout); - async_std::future::timeout(duration, async { + tokio::time::timeout(duration, async { idle_interrupt_receiver.recv().await.unwrap_or_default() }) .await @@ -493,13 +492,12 @@ impl Scheduler { }; // wait for all loops to be started - if let Err(err) = inbox_start_recv - .recv() - .try_join(mvbox_start_recv.recv()) - .try_join(sentbox_start_recv.recv()) - .try_join(smtp_start_recv.recv()) - .await - { + if let Err(err) = try_join!( + inbox_start_recv.recv(), + mvbox_start_recv.recv(), + sentbox_start_recv.recv(), + smtp_start_recv.recv() + ) { bail!("failed to start scheduler: {}", err); } @@ -508,19 +506,21 @@ impl Scheduler { } async fn maybe_network(&self) { - self.interrupt_inbox(InterruptInfo::new(true)) - .join(self.interrupt_mvbox(InterruptInfo::new(true))) - .join(self.interrupt_sentbox(InterruptInfo::new(true))) - .join(self.interrupt_smtp(InterruptInfo::new(true))) - .await; + join!( + self.interrupt_inbox(InterruptInfo::new(true)), + self.interrupt_mvbox(InterruptInfo::new(true)), + self.interrupt_sentbox(InterruptInfo::new(true)), + self.interrupt_smtp(InterruptInfo::new(true)) + ); } async fn maybe_network_lost(&self) { - self.interrupt_inbox(InterruptInfo::new(false)) - .join(self.interrupt_mvbox(InterruptInfo::new(false))) - .join(self.interrupt_sentbox(InterruptInfo::new(false))) - .join(self.interrupt_smtp(InterruptInfo::new(false))) - .await; + join!( + self.interrupt_inbox(InterruptInfo::new(false)), + self.interrupt_mvbox(InterruptInfo::new(false)), + self.interrupt_sentbox(InterruptInfo::new(false)), + self.interrupt_smtp(InterruptInfo::new(false)) + ); } async fn interrupt_inbox(&self, info: InterruptInfo) { @@ -564,24 +564,24 @@ impl Scheduler { // Actually shutdown tasks. let timeout_duration = std::time::Duration::from_secs(30); - future::timeout(timeout_duration, self.inbox_handle) + tokio::time::timeout(timeout_duration, self.inbox_handle) .await .ok_or_log(context); if let Some(mvbox_handle) = self.mvbox_handle.take() { - future::timeout(timeout_duration, mvbox_handle) + tokio::time::timeout(timeout_duration, mvbox_handle) .await .ok_or_log(context); } if let Some(sentbox_handle) = self.sentbox_handle.take() { - future::timeout(timeout_duration, sentbox_handle) + tokio::time::timeout(timeout_duration, sentbox_handle) .await .ok_or_log(context); } - future::timeout(timeout_duration, self.smtp_handle) + tokio::time::timeout(timeout_duration, self.smtp_handle) .await .ok_or_log(context); - self.ephemeral_handle.cancel().await; - self.location_handle.cancel().await; + self.ephemeral_handle.abort(); + self.location_handle.abort(); } } diff --git a/src/scheduler/connectivity.rs b/src/scheduler/connectivity.rs index 8512c1fe8c..8564046a5a 100644 --- a/src/scheduler/connectivity.rs +++ b/src/scheduler/connectivity.rs @@ -1,7 +1,7 @@ use core::fmt; use std::{ops::Deref, sync::Arc}; -use async_std::sync::{Mutex, RwLockReadGuard}; +use tokio::sync::{Mutex, RwLockReadGuard}; use crate::dc_tools::time; use crate::events::EventType; @@ -239,7 +239,7 @@ pub(crate) async fn maybe_network_lost( impl fmt::Debug for ConnectivityStore { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(guard) = self.0.try_lock() { + if let Ok(guard) = self.0.try_lock() { write!(f, "ConnectivityStore {:?}", &*guard) } else { write!(f, "ConnectivityStore [LOCKED]") diff --git a/src/securejoin.rs b/src/securejoin.rs index 7100541d18..f6a6cbdcbb 100644 --- a/src/securejoin.rs +++ b/src/securejoin.rs @@ -696,7 +696,7 @@ mod tests { use crate::peerstate::Peerstate; use crate::test_utils::{TestContext, TestContextManager}; - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_setup_contact() { let mut tcm = TestContextManager::new().await; let alice = tcm.alice().await; @@ -903,14 +903,14 @@ mod tests { ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_setup_contact_bad_qr() { let bob = TestContext::new_bob().await; let ret = dc_join_securejoin(&bob.ctx, "not a qr code").await; assert!(ret.is_err()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_setup_contact_bob_knows_alice() -> Result<()> { let mut tcm = TestContextManager::new().await; let alice = tcm.alice().await; @@ -1035,7 +1035,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_setup_contact_concurrent_calls() -> Result<()> { let mut tcm = TestContextManager::new().await; let alice = tcm.alice().await; @@ -1066,7 +1066,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_secure_join() -> Result<()> { let mut tcm = TestContextManager::new().await; let alice = tcm.alice().await; @@ -1290,7 +1290,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_adhoc_group_no_qr() -> Result<()> { let alice = TestContext::new_alice().await; alice.set_config(Config::ShowEmails, Some("2")).await?; diff --git a/src/smtp.rs b/src/smtp.rs index 8c2bd2adf2..830e3ecf81 100644 --- a/src/smtp.rs +++ b/src/smtp.rs @@ -8,7 +8,7 @@ use anyhow::{bail, format_err, Context as _, Error, Result}; use async_smtp::smtp::client::net::ClientTlsParameters; use async_smtp::smtp::response::{Category, Code, Detail}; use async_smtp::{smtp, EmailAddress, ServerAddress}; -use async_std::task; +use tokio::task; use crate::config::Config; use crate::contact::{Contact, ContactId}; diff --git a/src/sql.rs b/src/sql.rs index f7f2a9df66..2ac4b7cf99 100644 --- a/src/sql.rs +++ b/src/sql.rs @@ -1,16 +1,14 @@ //! # SQLite wrapper. -use async_std::path::Path; -use async_std::sync::RwLock; - use std::collections::{HashMap, HashSet}; use std::convert::TryFrom; +use std::path::Path; +use std::path::PathBuf; use std::time::Duration; use anyhow::{bail, Context as _, Result}; -use async_std::path::PathBuf; -use async_std::prelude::*; use rusqlite::{config::DbConfig, Connection, OpenFlags}; +use tokio::sync::RwLock; use crate::blob::BlobObject; use crate::chat::{add_device_msg, update_device_icon, update_saved_messages_icon}; @@ -126,18 +124,21 @@ impl Sql { .to_str() .with_context(|| format!("path {:?} is not valid unicode", path))?; let conn = self.get_conn().await?; - conn.execute( - "ATTACH DATABASE ? AS backup KEY ?", - paramsv![path_str, passphrase], - ) - .context("failed to attach backup database")?; - let res = conn - .query_row("SELECT sqlcipher_export('backup')", [], |_row| Ok(())) - .context("failed to export to attached backup database"); - conn.execute("DETACH DATABASE backup", []) - .context("failed to detach backup database")?; - res?; - Ok(()) + tokio::task::block_in_place(move || { + conn.execute( + "ATTACH DATABASE ? AS backup KEY ?", + paramsv![path_str, passphrase], + ) + .context("failed to attach backup database")?; + let res = conn + .query_row("SELECT sqlcipher_export('backup')", [], |_row| Ok(())) + .context("failed to export to attached backup database"); + conn.execute("DETACH DATABASE backup", []) + .context("failed to detach backup database")?; + res?; + + Ok(()) + }) } /// Imports the database from a separate file with the given passphrase. @@ -147,40 +148,42 @@ impl Sql { .with_context(|| format!("path {:?} is not valid unicode", path))?; let conn = self.get_conn().await?; - // Check that backup passphrase is correct before resetting our database. - conn.execute( - "ATTACH DATABASE ? AS backup KEY ?", - paramsv![path_str, passphrase], - ) - .context("failed to attach backup database")?; - if let Err(err) = conn - .query_row("SELECT count(*) FROM sqlite_master", [], |_row| Ok(())) - .context("backup passphrase is not correct") - { + tokio::task::block_in_place(move || { + // Check that backup passphrase is correct before resetting our database. + conn.execute( + "ATTACH DATABASE ? AS backup KEY ?", + paramsv![path_str, passphrase], + ) + .context("failed to attach backup database")?; + if let Err(err) = conn + .query_row("SELECT count(*) FROM sqlite_master", [], |_row| Ok(())) + .context("backup passphrase is not correct") + { + conn.execute("DETACH DATABASE backup", []) + .context("failed to detach backup database")?; + return Err(err); + } + + // Reset the database without reopening it. We don't want to reopen the database because we + // don't have main database passphrase at this point. + // See for documentation. + // Without resetting import may fail due to existing tables. + conn.set_db_config(DbConfig::SQLITE_DBCONFIG_RESET_DATABASE, true) + .context("failed to set SQLITE_DBCONFIG_RESET_DATABASE")?; + conn.execute("VACUUM", []) + .context("failed to vacuum the database")?; + conn.set_db_config(DbConfig::SQLITE_DBCONFIG_RESET_DATABASE, false) + .context("failed to unset SQLITE_DBCONFIG_RESET_DATABASE")?; + let res = conn + .query_row("SELECT sqlcipher_export('main', 'backup')", [], |_row| { + Ok(()) + }) + .context("failed to import from attached backup database"); conn.execute("DETACH DATABASE backup", []) .context("failed to detach backup database")?; - return Err(err); - } - - // Reset the database without reopening it. We don't want to reopen the database because we - // don't have main database passphrase at this point. - // See for documentation. - // Without resetting import may fail due to existing tables. - conn.set_db_config(DbConfig::SQLITE_DBCONFIG_RESET_DATABASE, true) - .context("failed to set SQLITE_DBCONFIG_RESET_DATABASE")?; - conn.execute("VACUUM", []) - .context("failed to vacuum the database")?; - conn.set_db_config(DbConfig::SQLITE_DBCONFIG_RESET_DATABASE, false) - .context("failed to unset SQLITE_DBCONFIG_RESET_DATABASE")?; - let res = conn - .query_row("SELECT sqlcipher_export('main', 'backup')", [], |_row| { - Ok(()) - }) - .context("failed to import from attached backup database"); - conn.execute("DETACH DATABASE backup", []) - .context("failed to detach backup database")?; - res?; - Ok(()) + res?; + Ok(()) + }) } fn new_pool( @@ -224,20 +227,22 @@ impl Sql { { let conn = self.get_conn().await?; - - // Try to enable auto_vacuum. This will only be - // applied if the database is new or after successful - // VACUUM, which usually happens before backup export. - // When auto_vacuum is INCREMENTAL, it is possible to - // use PRAGMA incremental_vacuum to return unused - // database pages to the filesystem. - conn.pragma_update(None, "auto_vacuum", &"INCREMENTAL".to_string())?; - - // journal_mode is persisted, it is sufficient to change it only for one handle. - conn.pragma_update(None, "journal_mode", &"WAL".to_string())?; - - // Default synchronous=FULL is much slower. NORMAL is sufficient for WAL mode. - conn.pragma_update(None, "synchronous", &"NORMAL".to_string())?; + tokio::task::block_in_place(move || -> Result<()> { + // Try to enable auto_vacuum. This will only be + // applied if the database is new or after successful + // VACUUM, which usually happens before backup export. + // When auto_vacuum is INCREMENTAL, it is possible to + // use PRAGMA incremental_vacuum to return unused + // database pages to the filesystem. + conn.pragma_update(None, "auto_vacuum", &"INCREMENTAL".to_string())?; + + // journal_mode is persisted, it is sufficient to change it only for one handle. + conn.pragma_update(None, "journal_mode", &"WAL".to_string())?; + + // Default synchronous=FULL is much slower. NORMAL is sufficient for WAL mode. + conn.pragma_update(None, "synchronous", &"NORMAL".to_string())?; + Ok(()) + })?; } self.run_migrations(context).await?; @@ -343,15 +348,19 @@ impl Sql { /// Execute the given query, returning the number of affected rows. pub async fn execute(&self, query: &str, params: impl rusqlite::Params) -> Result { let conn = self.get_conn().await?; - let res = conn.execute(query, params)?; - Ok(res) + tokio::task::block_in_place(move || { + let res = conn.execute(query, params)?; + Ok(res) + }) } /// Executes the given query, returning the last inserted row ID. pub async fn insert(&self, query: &str, params: impl rusqlite::Params) -> Result { let conn = self.get_conn().await?; - conn.execute(query, params)?; - Ok(conn.last_insert_rowid()) + tokio::task::block_in_place(move || { + conn.execute(query, params)?; + Ok(conn.last_insert_rowid()) + }) } /// Prepares and executes the statement and maps a function over the resulting rows. @@ -369,9 +378,11 @@ impl Sql { G: FnMut(rusqlite::MappedRows) -> Result, { let conn = self.get_conn().await?; - let mut stmt = conn.prepare(sql)?; - let res = stmt.query_map(params, f)?; - g(res) + tokio::task::block_in_place(move || { + let mut stmt = conn.prepare(sql)?; + let res = stmt.query_map(params, f)?; + g(res) + }) } pub async fn get_conn( @@ -408,8 +419,10 @@ impl Sql { F: FnOnce(&rusqlite::Row) -> rusqlite::Result, { let conn = self.get_conn().await?; - let res = conn.query_row(query, params, f)?; - Ok(res) + tokio::task::block_in_place(move || { + let res = conn.query_row(query, params, f)?; + Ok(res) + }) } /// Execute the function inside a transaction. @@ -422,49 +435,55 @@ impl Sql { G: Send + 'static + FnOnce(&mut rusqlite::Transaction<'_>) -> anyhow::Result, { let mut conn = self.get_conn().await?; - let mut transaction = conn.transaction()?; - let ret = callback(&mut transaction); - - match ret { - Ok(ret) => { - transaction.commit()?; - Ok(ret) - } - Err(err) => { - transaction.rollback()?; - Err(err) + tokio::task::block_in_place(move || { + let mut transaction = conn.transaction()?; + let ret = callback(&mut transaction); + + match ret { + Ok(ret) => { + transaction.commit()?; + Ok(ret) + } + Err(err) => { + transaction.rollback()?; + Err(err) + } } - } + }) } /// Query the database if the requested table already exists. pub async fn table_exists(&self, name: &str) -> anyhow::Result { let conn = self.get_conn().await?; - let mut exists = false; - conn.pragma(None, "table_info", &name.to_string(), |_row| { - // will only be executed if the info was found - exists = true; - Ok(()) - })?; + tokio::task::block_in_place(move || { + let mut exists = false; + conn.pragma(None, "table_info", &name.to_string(), |_row| { + // will only be executed if the info was found + exists = true; + Ok(()) + })?; - Ok(exists) + Ok(exists) + }) } /// Check if a column exists in a given table. pub async fn col_exists(&self, table_name: &str, col_name: &str) -> anyhow::Result { let conn = self.get_conn().await?; - let mut exists = false; - // `PRAGMA table_info` returns one row per column, - // each row containing 0=cid, 1=name, 2=type, 3=notnull, 4=dflt_value - conn.pragma(None, "table_info", &table_name.to_string(), |row| { - let curr_name: String = row.get(1)?; - if col_name == curr_name { - exists = true; - } - Ok(()) - })?; + tokio::task::block_in_place(move || { + let mut exists = false; + // `PRAGMA table_info` returns one row per column, + // each row containing 0=cid, 1=name, 2=type, 3=notnull, 4=dflt_value + conn.pragma(None, "table_info", &table_name.to_string(), |row| { + let curr_name: String = row.get(1)?; + if col_name == curr_name { + exists = true; + } + Ok(()) + })?; - Ok(exists) + Ok(exists) + }) } /// Execute a query which is expected to return zero or one row. @@ -478,12 +497,15 @@ impl Sql { F: FnOnce(&rusqlite::Row) -> rusqlite::Result, { let conn = self.get_conn().await?; - let res = match conn.query_row(sql.as_ref(), params, f) { - Ok(res) => Ok(Some(res)), - Err(rusqlite::Error::QueryReturnedNoRows) => Ok(None), - Err(rusqlite::Error::InvalidColumnType(_, _, rusqlite::types::Type::Null)) => Ok(None), - Err(err) => Err(err), - }?; + let res = + tokio::task::block_in_place(move || match conn.query_row(sql.as_ref(), params, f) { + Ok(res) => Ok(Some(res)), + Err(rusqlite::Error::QueryReturnedNoRows) => Ok(None), + Err(rusqlite::Error::InvalidColumnType(_, _, rusqlite::types::Type::Null)) => { + Ok(None) + } + Err(err) => Err(err), + })?; Ok(res) } @@ -717,7 +739,7 @@ pub async fn remove_unused_files(context: &Context) -> Result<()> { info!(context, "{} files in use.", files_in_use.len(),); /* go through directory and delete unused files */ let p = context.get_blobdir(); - match async_std::fs::read_dir(p).await { + match tokio::fs::read_dir(p).await { Ok(mut dir_handle) => { /* avoid deletion of files that are just created to build a message object */ let diff = std::time::Duration::from_secs(60 * 60); @@ -725,11 +747,7 @@ pub async fn remove_unused_files(context: &Context) -> Result<()> { .checked_sub(diff) .unwrap_or(std::time::SystemTime::UNIX_EPOCH); - while let Some(entry) = dir_handle.next().await { - let entry = match entry { - Ok(entry) => entry, - Err(_) => break, - }; + while let Ok(Some(entry)) = dir_handle.next_entry().await { let name_f = entry.file_name(); let name_s = name_f.to_string_lossy(); @@ -743,7 +761,7 @@ pub async fn remove_unused_files(context: &Context) -> Result<()> { unreferenced_count += 1; - if let Ok(stats) = async_std::fs::metadata(entry.path()).await { + if let Ok(stats) = tokio::fs::metadata(entry.path()).await { let recently_created = stats.created().map_or(false, |t| t > keep_files_newer_than); let recently_modified = stats @@ -860,8 +878,9 @@ pub fn repeat_vars(count: usize) -> String { #[cfg(test)] mod tests { - use async_std::channel; - use async_std::fs::File; + use async_channel as channel; + use tokio::fs::File; + use tokio::io::AsyncWriteExt; use crate::config::Config; use crate::{test_utils::TestContext, EventType}; @@ -894,14 +913,14 @@ mod tests { assert!(is_file_in_use(&files, Some("-suffix"), "world.txt-suffix")); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_table_exists() { let t = TestContext::new().await; assert!(t.ctx.sql.table_exists("msgs").await.unwrap()); assert!(!t.ctx.sql.table_exists("foobar").await.unwrap()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_col_exists() { let t = TestContext::new().await; assert!(t.ctx.sql.col_exists("msgs", "mime_modified").await.unwrap()); @@ -910,7 +929,7 @@ mod tests { } /// Tests that auto_vacuum is enabled for new databases. - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_auto_vacuum() -> Result<()> { let t = TestContext::new().await; @@ -925,7 +944,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_housekeeping_db_closed() { let t = TestContext::new().await; @@ -945,14 +964,14 @@ mod tests { t.add_event_sender(event_sink).await; let a = t.get_config(Config::Selfavatar).await.unwrap().unwrap(); - assert_eq!(avatar_bytes, &async_std::fs::read(&a).await.unwrap()[..]); + assert_eq!(avatar_bytes, &tokio::fs::read(&a).await.unwrap()[..]); t.sql.close().await; housekeeping(&t).await.unwrap_err(); // housekeeping should fail as the db is closed t.sql.open(&t, "".to_string()).await.unwrap(); let a = t.get_config(Config::Selfavatar).await.unwrap().unwrap(); - assert_eq!(avatar_bytes, &async_std::fs::read(&a).await.unwrap()[..]); + assert_eq!(avatar_bytes, &tokio::fs::read(&a).await.unwrap()[..]); while let Ok(event) = event_source.try_recv() { match event.typ { @@ -969,7 +988,7 @@ mod tests { /// Regression test for a bug where housekeeping deleted drafts since their /// `hidden` flag is set. - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_housekeeping_dont_delete_drafts() { let t = TestContext::new_alice().await; @@ -996,7 +1015,7 @@ mod tests { /// /// Statements were not finalized due to a bug in sqlx: /// - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_db_reopen() -> Result<()> { use tempfile::tempdir; @@ -1006,7 +1025,7 @@ mod tests { // Create a separate empty database for testing. let dir = tempdir()?; let dbfile = dir.path().join("testdb.sqlite"); - let sql = Sql::new(dbfile.into()); + let sql = Sql::new(dbfile); // Create database with all the tables. sql.open(&t, "".to_string()).await.unwrap(); @@ -1028,7 +1047,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_migration_flags() -> Result<()> { let t = TestContext::new().await; t.evtracker.get_info_contains("Opened database").await; @@ -1067,7 +1086,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_check_passphrase() -> Result<()> { use tempfile::tempdir; @@ -1077,7 +1096,7 @@ mod tests { // Create a separate empty database for testing. let dir = tempdir()?; let dbfile = dir.path().join("testdb.sqlite"); - let sql = Sql::new(dbfile.clone().into()); + let sql = Sql::new(dbfile.clone()); sql.check_passphrase("foo".to_string()).await?; sql.open(&t, "foo".to_string()) @@ -1086,7 +1105,7 @@ mod tests { sql.close().await; // Reopen the database - let sql = Sql::new(dbfile.into()); + let sql = Sql::new(dbfile); // Test that we can't open encrypted database without a passphrase. assert!(sql.open(&t, "".to_string()).await.is_err()); diff --git a/src/stock_str.rs b/src/stock_str.rs index b340d21c99..fdd56a41a4 100644 --- a/src/stock_str.rs +++ b/src/stock_str.rs @@ -1167,7 +1167,7 @@ mod tests { assert_eq!(StockMessage::NoMessages.fallback(), "No messages."); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_set_stock_translation() { let t = TestContext::new().await; t.set_stock_translation(StockMessage::NoMessages, "xyz".to_string()) @@ -1176,7 +1176,7 @@ mod tests { assert_eq!(no_messages(&t).await, "xyz") } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_set_stock_translation_wrong_replacements() { let t = TestContext::new().await; assert!(t @@ -1191,13 +1191,13 @@ mod tests { .is_err()); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_stock_str() { let t = TestContext::new().await; assert_eq!(no_messages(&t).await, "No messages."); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_stock_string_repl_str() { let t = TestContext::new().await; let contact_id = Contact::create(&t.ctx, "Someone", "someone@example.org") @@ -1212,13 +1212,13 @@ mod tests { // We have no string using %1$d to test... } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_stock_string_repl_str2() { let t = TestContext::new().await; assert_eq!(msg_action_by_user(&t, "foo", "bar").await, "foo by bar."); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_stock_system_msg_simple() { let t = TestContext::new().await; assert_eq!( @@ -1227,7 +1227,7 @@ mod tests { ) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_stock_system_msg_add_member_by_me() { let t = TestContext::new().await; assert_eq!( @@ -1236,7 +1236,7 @@ mod tests { ) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_stock_system_msg_add_member_by_me_with_displayname() { let t = TestContext::new().await; Contact::create(&t, "Alice", "alice@example.org") @@ -1248,7 +1248,7 @@ mod tests { ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_stock_system_msg_add_member_by_other_with_displayname() { let t = TestContext::new().await; let contact_id = { @@ -1265,7 +1265,7 @@ mod tests { ); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_quota_exceeding_stock_str() -> anyhow::Result<()> { let t = TestContext::new().await; let str = quota_exceeding(&t, 81).await; @@ -1275,7 +1275,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_partial_download_msg_body() -> anyhow::Result<()> { let t = TestContext::new().await; let str = partial_download_msg_body(&t, 1024 * 1024).await; @@ -1283,7 +1283,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_update_device_chats() { let t = TestContext::new().await; t.update_device_chats().await.ok(); diff --git a/src/summary.rs b/src/summary.rs index ea25b343d7..ccef5a849e 100644 --- a/src/summary.rs +++ b/src/summary.rs @@ -189,7 +189,7 @@ mod tests { use super::*; use crate::test_utils as test; - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_summary_text() { let d = test::TestContext::new().await; let ctx = &d.ctx; diff --git a/src/sync.rs b/src/sync.rs index ab0e9717d4..28fb12299d 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -267,7 +267,7 @@ mod tests { use crate::token::Namespace; use anyhow::bail; - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_is_sync_sending_enabled() -> Result<()> { let t = TestContext::new_alice().await; assert!(!t.is_sync_sending_enabled().await?); @@ -278,7 +278,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_build_sync_json() -> Result<()> { let t = TestContext::new_alice().await; t.set_config_bool(Config::SendSyncMsgs, true).await?; @@ -323,7 +323,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_build_sync_json_sync_msgs_off() -> Result<()> { let t = TestContext::new_alice().await; t.set_config_bool(Config::SendSyncMsgs, false).await?; @@ -337,7 +337,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_parse_sync_items() -> Result<()> { let t = TestContext::new_alice().await; @@ -422,7 +422,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_execute_sync_items() -> Result<()> { let t = TestContext::new_alice().await; @@ -451,7 +451,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_send_sync_msg() -> Result<()> { let alice = TestContext::new_alice().await; alice.set_config_bool(Config::SendSyncMsgs, true).await?; diff --git a/src/test_utils.rs b/src/test_utils.rs index dd70a97fd1..038e6885be 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -6,17 +6,17 @@ use std::collections::BTreeMap; use std::ops::Deref; use std::panic; +use std::sync::Arc; use std::time::{Duration, Instant}; use ansi_term::Color; -use async_std::channel::{self, Receiver, Sender}; -use async_std::prelude::*; -use async_std::sync::{Arc, RwLock}; -use async_std::task; +use async_channel::{self as channel, Receiver, Sender}; use chat::ChatItem; use once_cell::sync::Lazy; use rand::Rng; use tempfile::{tempdir, TempDir}; +use tokio::sync::RwLock; +use tokio::task; use crate::chat::{self, Chat, ChatId}; use crate::chatlist::Chatlist; @@ -250,6 +250,17 @@ impl TestContext { Self::builder().configure_fiona().build().await } + /// Print current chat state. + pub async fn print_chats(&self) { + println!("\n========== Chats of {}: ==========", self.name()); + if let Ok(chats) = Chatlist::try_load(self, 0, None, None).await { + for (chat, _) in chats.iter() { + self.print_chat(*chat).await; + } + } + println!(); + } + /// Internal constructor. /// /// `name` is used to identify this context in e.g. log output. This is useful mostly @@ -266,7 +277,7 @@ impl TestContext { let mut context_names = CONTEXT_NAMES.write().unwrap(); context_names.insert(id, name); } - let ctx = Context::new(dbfile.into(), id, Events::new()) + let ctx = Context::new(&dbfile, id, Events::new()) .await .expect("failed to create context"); @@ -382,7 +393,7 @@ impl TestContext { break row; } if start.elapsed() < Duration::from_secs(3) { - async_std::task::sleep(Duration::from_millis(100)).await; + tokio::time::sleep(Duration::from_millis(100)).await; } else { panic!("no sent message found in jobs table"); } @@ -670,20 +681,6 @@ impl Deref for TestContext { } } -impl Drop for TestContext { - fn drop(&mut self) { - async_std::task::block_on(async { - println!("\n========== Chats of {}: ==========", self.name()); - if let Ok(chats) = Chatlist::try_load(self, 0, None, None).await { - for (chat, _) in chats.iter() { - self.print_chat(*chat).await; - } - } - println!(); - }); - } -} - pub enum LogEvent { /// Logged event. Event(Event), @@ -828,15 +825,14 @@ impl EventTracker { /// If no matching events are ready this will wait for new events to arrive and time out /// after 10 seconds. pub async fn get_matching bool>(&self, event_matcher: F) -> EventType { - async move { + tokio::time::timeout(Duration::from_secs(10), async move { loop { let event = self.0.recv().await.unwrap(); if event_matcher(&event.typ) { return event.typ; } } - } - .timeout(Duration::from_secs(10)) + }) .await .expect("timeout waiting for event match") } @@ -1011,21 +1007,21 @@ mod tests { // The following three tests demonstrate, when made to fail, the log output being // directed to the correct test output. - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_with_alice() { let alice = TestContext::builder().configure_alice().build().await; alice.ctx.emit_event(EventType::Info("hello".into())); // panic!("Alice fails"); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_with_bob() { let bob = TestContext::builder().configure_bob().build().await; bob.ctx.emit_event(EventType::Info("there".into())); // panic!("Bob fails"); } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_with_both() { let mut tcm = TestContextManager::new().await; let alice = tcm.alice().await; diff --git a/src/update_helper.rs b/src/update_helper.rs index 2db74d4153..7de265587f 100644 --- a/src/update_helper.rs +++ b/src/update_helper.rs @@ -63,7 +63,7 @@ mod tests { use crate::dc_tools::time; use crate::test_utils::TestContext; - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_params_update_timestamp() -> Result<()> { let mut params = Params::new(); let ts = time(); @@ -85,7 +85,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_out_of_order_subject() -> Result<()> { let t = TestContext::new_alice().await; @@ -126,7 +126,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_out_of_order_group_name() -> Result<()> { let t = TestContext::new_alice().await; diff --git a/src/webxdc.rs b/src/webxdc.rs index 0267b7e23f..8085b5b1f9 100644 --- a/src/webxdc.rs +++ b/src/webxdc.rs @@ -1,26 +1,27 @@ //! # Handle webxdc messages. +use std::convert::TryFrom; +use std::path::PathBuf; + +use anyhow::{anyhow, bail, ensure, format_err, Result}; +use deltachat_derive::FromSql; +use lettre_email::mime; +use lettre_email::PartBuilder; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use tokio::io::AsyncReadExt; + use crate::chat::Chat; use crate::contact::ContactId; use crate::context::Context; -use crate::dc_tools::{dc_create_smeared_timestamp, dc_open_file_std}; +use crate::dc_tools::dc_create_smeared_timestamp; +use crate::dc_tools::dc_get_abs_path; use crate::message::{Message, MessageState, MsgId, Viewtype}; use crate::mimeparser::SystemMessage; use crate::param::Param; use crate::param::Params; use crate::scheduler::InterruptInfo; use crate::{chat, EventType}; -use anyhow::{bail, ensure, format_err, Result}; -use async_std::path::PathBuf; -use deltachat_derive::FromSql; -use lettre_email::mime; -use lettre_email::PartBuilder; -use serde::{Deserialize, Serialize}; -use serde_json::Value; -use std::convert::TryFrom; -use std::fs::File; -use std::io::{Read, Seek, SeekFrom}; -use zip::ZipArchive; /// The current API version. /// If `min_api` in manifest.toml is set to a larger value, @@ -139,16 +140,12 @@ pub(crate) struct StatusUpdateItemAndSerial { impl Context { /// check if a file is an acceptable webxdc for sending or receiving. - pub(crate) async fn is_webxdc_file(&self, filename: &str, mut reader: R) -> Result - where - R: Read + Seek, - { + pub(crate) async fn is_webxdc_file(&self, filename: &str, file: &[u8]) -> Result { if !filename.ends_with(WEBXDC_SUFFIX) { return Ok(false); } - let size = reader.seek(SeekFrom::End(0))?; - if size > WEBXDC_RECEIVING_LIMIT { + if file.len() as u64 > WEBXDC_RECEIVING_LIMIT { info!( self, "{} exceeds receiving limit of {} bytes", &filename, WEBXDC_RECEIVING_LIMIT @@ -156,8 +153,7 @@ impl Context { return Ok(false); } - reader.seek(SeekFrom::Start(0))?; - let mut archive = match zip::ZipArchive::new(reader) { + let archive = match async_zip::read::mem::ZipFileReader::new(file).await { Ok(archive) => archive, Err(_) => { info!(self, "{} cannot be opened as zip-file", &filename); @@ -165,7 +161,7 @@ impl Context { } }; - if archive.by_name("index.html").is_err() { + if archive.entry("index.html").is_none() { info!(self, "{} misses index.html", &filename); return Ok(false); } @@ -176,18 +172,12 @@ impl Context { /// ensure that a file is an acceptable webxdc for sending /// (sending has more strict size limits). pub(crate) async fn ensure_sendable_webxdc_file(&self, path: &PathBuf) -> Result<()> { - let mut file = std::fs::File::open(path)?; - if !self - .is_webxdc_file(path.to_str().unwrap_or_default(), &mut file) - .await? - { - bail!( - "{} is not a valid webxdc file", - path.to_str().unwrap_or_default() - ); + let filename = path.to_str().unwrap_or_default(); + if !filename.ends_with(WEBXDC_SUFFIX) { + bail!("{} is not a valid webxdc file", filename); } - let size = file.seek(SeekFrom::End(0))?; + let size = tokio::fs::metadata(path).await?.len(); if size > WEBXDC_SENDING_LIMIT { bail!( "webxdc {} exceeds acceptable size of {} bytes", @@ -195,6 +185,26 @@ impl Context { WEBXDC_SENDING_LIMIT ); } + + let valid = match async_zip::read::fs::ZipFileReader::new(path).await { + Ok(archive) => { + if archive.entry("index.html").is_none() { + info!(self, "{} misses index.html", filename); + false + } else { + true + } + } + Err(_) => { + info!(self, "{} cannot be opened as zip-file", filename); + false + } + }; + + if !valid { + bail!("{} is not a valid webxdc file", filename); + } + Ok(()) } @@ -588,22 +598,28 @@ fn parse_webxdc_manifest(bytes: &[u8]) -> Result { Ok(manifest) } -fn get_blob(archive: &mut ZipArchive, name: &str) -> Result> { - let mut file = archive.by_name(name)?; +async fn get_blob(archive: &mut async_zip::read::fs::ZipFileReader, name: &str) -> Result> { + let (i, _) = archive + .entry(name) + .ok_or_else(|| anyhow!("no entry found for {}", name))?; + let mut reader = archive.entry_reader(i).await?; let mut buf = Vec::new(); - file.read_to_end(&mut buf)?; + reader.read_to_end(&mut buf).await?; Ok(buf) } impl Message { /// Get handle to a webxdc ZIP-archive. /// To check for file existance use archive.by_name(), to read a file, use get_blob(archive). - async fn get_webxdc_archive(&self, context: &Context) -> Result> { + async fn get_webxdc_archive( + &self, + context: &Context, + ) -> Result { let path = self .get_file(context) .ok_or_else(|| format_err!("No webxdc instance file."))?; - let file = dc_open_file_std(context, path)?; - let archive = zip::ZipArchive::new(file)?; + let path_abs = dc_get_abs_path(context, &path); + let archive = async_zip::read::fs::ZipFileReader::new(path_abs).await?; Ok(archive) } @@ -627,7 +643,7 @@ impl Message { let mut archive = self.get_webxdc_archive(context).await?; if name == "index.html" { - if let Ok(bytes) = get_blob(&mut archive, "manifest.toml") { + if let Ok(bytes) = get_blob(&mut archive, "manifest.toml").await { if let Ok(manifest) = parse_webxdc_manifest(&bytes) { if let Some(min_api) = manifest.min_api { if min_api > WEBXDC_API_VERSION { @@ -640,7 +656,7 @@ impl Message { } } - get_blob(&mut archive, name) + get_blob(&mut archive, name).await } /// Return info from manifest.toml or from fallbacks. @@ -648,7 +664,7 @@ impl Message { ensure!(self.viewtype == Viewtype::Webxdc, "No webxdc instance."); let mut archive = self.get_webxdc_archive(context).await?; - let mut manifest = if let Ok(bytes) = get_blob(&mut archive, "manifest.toml") { + let mut manifest = if let Ok(bytes) = get_blob(&mut archive, "manifest.toml").await { if let Ok(manifest) = parse_webxdc_manifest(&bytes) { manifest } else { @@ -680,9 +696,9 @@ impl Message { } else { self.get_filename().unwrap_or_default() }, - icon: if archive.by_name("icon.png").is_ok() { + icon: if archive.entry("icon.png").is_some() { "icon.png".to_string() - } else if archive.by_name("icon.jpg").is_ok() { + } else if archive.entry("icon.jpg").is_some() { "icon.jpg".to_string() } else { WEBXDC_DEFAULT_ICON.to_string() @@ -708,10 +724,8 @@ impl Message { #[cfg(test)] mod tests { - use std::io::Cursor; - - use async_std::fs::File; - use async_std::io::WriteExt; + use tokio::fs::File; + use tokio::io::AsyncWriteExt; use crate::chat::{ add_contact_to_chat, create_group_chat, forward_msgs, resend_msgs, send_msg, send_text_msg, @@ -726,7 +740,7 @@ mod tests { use super::*; #[allow(clippy::assertions_on_constants)] - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_webxdc_file_limits() -> Result<()> { assert!(WEBXDC_SENDING_LIMIT >= 32768); assert!(WEBXDC_SENDING_LIMIT < 16777216); @@ -735,41 +749,41 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_is_webxdc_file() -> Result<()> { let t = TestContext::new().await; assert!( !t.is_webxdc_file( "bad-ext-no-zip.txt", - Cursor::new(include_bytes!("../test-data/message/issue_523.txt")) + include_bytes!("../test-data/message/issue_523.txt") ) .await? ); assert!( !t.is_webxdc_file( "bad-ext-good-zip.txt", - Cursor::new(include_bytes!("../test-data/webxdc/minimal.xdc")) + include_bytes!("../test-data/webxdc/minimal.xdc") ) .await? ); assert!( !t.is_webxdc_file( "good-ext-no-zip.xdc", - Cursor::new(include_bytes!("../test-data/message/issue_523.txt")) + include_bytes!("../test-data/message/issue_523.txt") ) .await? ); assert!( !t.is_webxdc_file( "good-ext-no-index-html.xdc", - Cursor::new(include_bytes!("../test-data/webxdc/no-index-html.xdc")) + include_bytes!("../test-data/webxdc/no-index-html.xdc") ) .await? ); assert!( t.is_webxdc_file( "good-ext-good-zip.xdc", - Cursor::new(include_bytes!("../test-data/webxdc/minimal.xdc")) + include_bytes!("../test-data/webxdc/minimal.xdc") ) .await? ); @@ -796,7 +810,7 @@ mod tests { Message::load_from_db(t, instance_msg_id).await } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_send_webxdc_instance() -> Result<()> { let t = TestContext::new_alice().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?; @@ -820,7 +834,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_send_invalid_webxdc() -> Result<()> { let t = TestContext::new_alice().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?; @@ -852,7 +866,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_forward_webxdc_instance() -> Result<()> { let t = TestContext::new_alice().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?; @@ -895,7 +909,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_resend_webxdc_instance_and_info() -> Result<()> { // Alice uses webxdc in a group let alice = TestContext::new_alice().await; @@ -940,7 +954,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_receive_webxdc_instance() -> Result<()> { let t = TestContext::new_alice().await; dc_receive_imf( @@ -966,7 +980,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_webxdc_contact_request() -> Result<()> { let alice = TestContext::new_alice().await; let bob = TestContext::new_bob().await; @@ -1010,7 +1024,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_delete_webxdc_instance() -> Result<()> { let t = TestContext::new_alice().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?; @@ -1048,7 +1062,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_create_status_update_record() -> Result<()> { let t = TestContext::new_alice().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?; @@ -1142,7 +1156,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_receive_status_update() -> Result<()> { let t = TestContext::new_alice().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?; @@ -1238,7 +1252,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_send_webxdc_status_update() -> Result<()> { let alice = TestContext::new_alice().await; alice.set_config_bool(Config::BccSelf, true).await?; @@ -1338,7 +1352,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_render_webxdc_status_update_object() -> Result<()> { let t = TestContext::new_alice().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "a chat").await?; @@ -1364,7 +1378,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_render_webxdc_status_update_object_range() -> Result<()> { let t = TestContext::new_alice().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "a chat").await?; @@ -1402,7 +1416,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_pop_status_update() -> Result<()> { let t = TestContext::new_alice().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "a chat").await?; @@ -1462,7 +1476,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_draft_and_send_webxdc_status_update() -> Result<()> { let alice = TestContext::new_alice().await; let bob = TestContext::new_bob().await; @@ -1529,7 +1543,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_send_webxdc_status_update_to_non_webxdc() -> Result<()> { let t = TestContext::new_alice().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?; @@ -1541,7 +1555,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_webxdc_blob() -> Result<()> { let t = TestContext::new_alice().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?; @@ -1558,7 +1572,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_webxdc_blob_default_icon() -> Result<()> { let t = TestContext::new_alice().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?; @@ -1570,7 +1584,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_webxdc_blob_with_absolute_paths() -> Result<()> { let t = TestContext::new_alice().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?; @@ -1583,7 +1597,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_webxdc_blob_with_subdirs() -> Result<()> { let t = TestContext::new_alice().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?; @@ -1624,7 +1638,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_parse_webxdc_manifest() -> Result<()> { let result = parse_webxdc_manifest(r#"key = syntax error"#.as_bytes()); assert!(result.is_err()); @@ -1655,7 +1669,7 @@ sth_for_the = "future""# Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_parse_webxdc_manifest_min_api() -> Result<()> { let manifest = parse_webxdc_manifest(r#"min_api = 3"#.as_bytes())?; assert_eq!(manifest.min_api, Some(3)); @@ -1669,7 +1683,7 @@ sth_for_the = "future""# Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_parse_webxdc_manifest_source_code_url() -> Result<()> { let result = parse_webxdc_manifest(r#"source_code_url = 3"#.as_bytes()); assert!(result.is_err()); @@ -1683,7 +1697,7 @@ sth_for_the = "future""# Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_webxdc_min_api_too_large() -> Result<()> { let t = TestContext::new_alice().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "chat").await?; @@ -1702,7 +1716,7 @@ sth_for_the = "future""# Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_webxdc_info() -> Result<()> { let t = TestContext::new_alice().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?; @@ -1786,7 +1800,7 @@ sth_for_the = "future""# Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_webxdc_info_summary() -> Result<()> { let alice = TestContext::new_alice().await; let bob = TestContext::new_bob().await; @@ -1852,7 +1866,7 @@ sth_for_the = "future""# Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_webxdc_document_name() -> Result<()> { let alice = TestContext::new_alice().await; let bob = TestContext::new_bob().await; @@ -1894,7 +1908,7 @@ sth_for_the = "future""# Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_webxdc_info_msg() -> Result<()> { let alice = TestContext::new_alice().await; let bob = TestContext::new_bob().await; @@ -1985,7 +1999,7 @@ sth_for_the = "future""# Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_webxdc_info_msg_cleanup_series() -> Result<()> { let alice = TestContext::new_alice().await; let bob = TestContext::new_bob().await; @@ -2023,7 +2037,7 @@ sth_for_the = "future""# Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_webxdc_info_msg_no_cleanup_on_interrupted_series() -> Result<()> { let t = TestContext::new_alice().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "c").await?; @@ -2041,7 +2055,7 @@ sth_for_the = "future""# Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_webxdc_opportunistic_encryption() -> Result<()> { let alice = TestContext::new_alice().await; let bob = TestContext::new_bob().await; @@ -2093,7 +2107,7 @@ sth_for_the = "future""# Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_webxdc_chatlist_summary() -> Result<()> { let t = TestContext::new_alice().await; let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "chat").await?; @@ -2113,7 +2127,7 @@ sth_for_the = "future""# Ok(()) } - #[async_std::test] + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_webxdc_and_text() -> Result<()> { let alice = TestContext::new_alice().await; let bob = TestContext::new_bob().await;