mirror of
https://github.com/chatmail/core.git
synced 2026-07-23 03:13:06 +03:00
Compare commits
25 Commits
link2xt/ba
...
simon/toki
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f029e442ff | ||
|
|
fe6543cd7a | ||
|
|
6845e81608 | ||
|
|
e4ccb5287b | ||
|
|
e9d32c1bc5 | ||
|
|
fbf2538fa2 | ||
|
|
3d4e96897e | ||
|
|
3ff271ba93 | ||
|
|
95aaaee43c | ||
|
|
087050c27d | ||
|
|
1404cbd3ef | ||
|
|
b965db6657 | ||
|
|
6749b90ff5 | ||
|
|
7bdac58040 | ||
|
|
06c4eb9df0 | ||
|
|
7eb34a56f6 | ||
|
|
6b0b551973 | ||
|
|
09aa9712c4 | ||
|
|
de7d6753a9 | ||
|
|
92c10e56d3 | ||
|
|
c71a6c4af9 | ||
|
|
308053dc44 | ||
|
|
f37fb9574d | ||
|
|
baa8da86ba | ||
|
|
2cd4af576a |
55
CHANGELOG.md
55
CHANGELOG.md
@@ -1,57 +1,5 @@
|
||||
# Changelog
|
||||
|
||||
## [1.148.4] - 2024-10-24
|
||||
|
||||
### Features / Changes
|
||||
|
||||
- Jsonrpc: add `private_tag` to `Account::Configured` Object ([#6107](https://github.com/deltachat/deltachat-core-rust/pull/6107)).
|
||||
|
||||
### Fixes
|
||||
|
||||
- Normalize proxy URLs before saving into proxy_url.
|
||||
- Do not wait for connections in maybe_add_gossip_peers().
|
||||
|
||||
## [1.148.3] - 2024-10-24
|
||||
|
||||
### Fixes
|
||||
|
||||
- Fix reception of realtime advertisements.
|
||||
|
||||
### Features / Changes
|
||||
|
||||
- Allow sending realtime messages up to 128 KB in size.
|
||||
|
||||
### API-Changes
|
||||
|
||||
- deltachat-rpc-client: Add EventType.WEBXDC_REALTIME_ADVERTISEMENT_RECEIVED.
|
||||
|
||||
### Documentation
|
||||
|
||||
- Fix DC_QR_PROXY docs ([#6099](https://github.com/deltachat/deltachat-core-rust/pull/6099)).
|
||||
|
||||
### Refactor
|
||||
|
||||
- Generate topic inside create_iroh_header().
|
||||
|
||||
### Tests
|
||||
|
||||
- Test that realtime advertisements work after chatting.
|
||||
|
||||
## [1.148.2] - 2024-10-23
|
||||
|
||||
### Fixes
|
||||
|
||||
- Never initialize Iroh if realtime is disabled.
|
||||
|
||||
### Features / Changes
|
||||
|
||||
- Add more logging for iroh initialization and peer addition.
|
||||
|
||||
### Build system
|
||||
|
||||
- `nix flake update nixpkgs`.
|
||||
- `nix flake update fenix`.
|
||||
|
||||
## [1.148.1] - 2024-10-23
|
||||
|
||||
### Build system
|
||||
@@ -5136,6 +5084,3 @@ https://github.com/deltachat/deltachat-core-rust/pulls?q=is%3Apr+is%3Aclosed
|
||||
[1.147.1]: https://github.com/deltachat/deltachat-core-rust/compare/v1.147.0..v1.147.1
|
||||
[1.148.0]: https://github.com/deltachat/deltachat-core-rust/compare/v1.147.1..v1.148.0
|
||||
[1.148.1]: https://github.com/deltachat/deltachat-core-rust/compare/v1.148.0..v1.148.1
|
||||
[1.148.2]: https://github.com/deltachat/deltachat-core-rust/compare/v1.148.1..v1.148.2
|
||||
[1.148.3]: https://github.com/deltachat/deltachat-core-rust/compare/v1.148.2..v1.148.3
|
||||
[1.148.4]: https://github.com/deltachat/deltachat-core-rust/compare/v1.148.3..v1.148.4
|
||||
|
||||
236
Cargo.lock
generated
236
Cargo.lock
generated
@@ -358,6 +358,28 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-stream"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476"
|
||||
dependencies = [
|
||||
"async-stream-impl",
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-stream-impl"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.77"
|
||||
@@ -384,6 +406,12 @@ dependencies = [
|
||||
"tokio-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic-waker"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
||||
|
||||
[[package]]
|
||||
name = "attohttpc"
|
||||
version = "0.24.1"
|
||||
@@ -953,6 +981,45 @@ dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console-api"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86ed14aa9c9f927213c6e4f3ef75faaad3406134efe84ba2cb7983431d5f0931"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"prost",
|
||||
"prost-types",
|
||||
"tonic",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console-subscriber"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2e3a111a37f3333946ebf9da370ba5c5577b18eb342ec683eb488dd21980302"
|
||||
dependencies = [
|
||||
"console-api",
|
||||
"crossbeam-channel",
|
||||
"crossbeam-utils",
|
||||
"futures-task",
|
||||
"hdrhistogram",
|
||||
"humantime",
|
||||
"hyper-util",
|
||||
"prost",
|
||||
"prost-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thread_local",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tonic",
|
||||
"tracing",
|
||||
"tracing-core",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const-oid"
|
||||
version = "0.9.6"
|
||||
@@ -1084,6 +1151,15 @@ dependencies = [
|
||||
"itertools",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.5"
|
||||
@@ -1270,7 +1346,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"hashbrown",
|
||||
"hashbrown 0.14.3",
|
||||
"lock_api",
|
||||
"once_cell",
|
||||
"parking_lot_core",
|
||||
@@ -1293,12 +1369,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "deltachat"
|
||||
version = "1.148.4"
|
||||
version = "1.148.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-broadcast",
|
||||
"async-channel 2.3.1",
|
||||
"async-compression",
|
||||
"async-imap",
|
||||
"async-native-tls",
|
||||
"async-smtp",
|
||||
@@ -1394,7 +1469,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "deltachat-jsonrpc"
|
||||
version = "1.148.4"
|
||||
version = "1.148.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-channel 2.3.1",
|
||||
@@ -1419,9 +1494,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "deltachat-repl"
|
||||
version = "1.148.4"
|
||||
version = "1.148.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"console-subscriber",
|
||||
"deltachat",
|
||||
"dirs",
|
||||
"log",
|
||||
@@ -1430,14 +1506,16 @@ dependencies = [
|
||||
"rusqlite",
|
||||
"rustyline",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deltachat-rpc-server"
|
||||
version = "1.148.4"
|
||||
version = "1.148.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"console-subscriber",
|
||||
"deltachat",
|
||||
"deltachat-jsonrpc",
|
||||
"futures-lite 2.3.0",
|
||||
@@ -1446,6 +1524,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"yerpc",
|
||||
]
|
||||
@@ -1464,7 +1543,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "deltachat_ffi"
|
||||
version = "1.148.4"
|
||||
version = "1.148.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"deltachat",
|
||||
@@ -2455,7 +2534,26 @@ dependencies = [
|
||||
"futures-sink",
|
||||
"futures-util",
|
||||
"http 0.2.12",
|
||||
"indexmap",
|
||||
"indexmap 2.2.5",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205"
|
||||
dependencies = [
|
||||
"atomic-waker",
|
||||
"bytes",
|
||||
"fnv",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"http 1.1.0",
|
||||
"indexmap 2.2.5",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
@@ -2472,6 +2570,12 @@ dependencies = [
|
||||
"crunchy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.3"
|
||||
@@ -2487,7 +2591,20 @@ version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
"hashbrown 0.14.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hdrhistogram"
|
||||
version = "7.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "765c9198f173dd59ce26ff9f95ef0aafd0a0fe01fb9d72841bc5066a4c06511d"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
"byteorder",
|
||||
"flate2",
|
||||
"nom",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2722,7 +2839,7 @@ dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"h2 0.3.26",
|
||||
"http 0.2.12",
|
||||
"http-body 0.4.6",
|
||||
"httparse",
|
||||
@@ -2745,6 +2862,7 @@ dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-util",
|
||||
"h2 0.4.6",
|
||||
"http 1.1.0",
|
||||
"http-body 1.0.0",
|
||||
"httparse",
|
||||
@@ -2774,6 +2892,19 @@ dependencies = [
|
||||
"webpki-roots",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-timeout"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3203a961e5c83b6f5498933e78b6b263e208c197b63e9c6c53cc82ffd3f63793"
|
||||
dependencies = [
|
||||
"hyper 1.4.1",
|
||||
"hyper-util",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.9"
|
||||
@@ -2896,6 +3027,16 @@ dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown 0.12.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.2.5"
|
||||
@@ -2903,7 +3044,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
"hashbrown 0.14.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2997,7 +3138,7 @@ dependencies = [
|
||||
"futures-concurrency",
|
||||
"futures-lite 2.3.0",
|
||||
"futures-util",
|
||||
"indexmap",
|
||||
"indexmap 2.2.5",
|
||||
"iroh-base",
|
||||
"iroh-blake3",
|
||||
"iroh-metrics",
|
||||
@@ -4481,6 +4622,38 @@ dependencies = [
|
||||
"unarray",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost"
|
||||
version = "0.13.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b0487d90e047de87f984913713b85c601c05609aad5b0df4b4573fbf69aa13f"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"prost-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost-derive"
|
||||
version = "0.13.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e9552f850d5f0964a4e4d0bf306459ac29323ddfbae05e35a7c0d35cb0803cc5"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.79",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost-types"
|
||||
version = "0.13.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4759aa0d3a6232fb8dbdb97b61de2c20047c68aca932c7ed76da9d788508d670"
|
||||
dependencies = [
|
||||
"prost",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "qr2term"
|
||||
version = "0.3.3"
|
||||
@@ -6002,6 +6175,7 @@ dependencies = [
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"tracing",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
@@ -6121,7 +6295,7 @@ dependencies = [
|
||||
"futures-io",
|
||||
"futures-sink",
|
||||
"futures-util",
|
||||
"hashbrown",
|
||||
"hashbrown 0.14.3",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
]
|
||||
@@ -6153,13 +6327,43 @@ version = "0.22.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"indexmap 2.2.5",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tonic"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52"
|
||||
dependencies = [
|
||||
"async-stream",
|
||||
"async-trait",
|
||||
"axum",
|
||||
"base64 0.22.1",
|
||||
"bytes",
|
||||
"h2 0.4.6",
|
||||
"http 1.1.0",
|
||||
"http-body 1.0.0",
|
||||
"http-body-util",
|
||||
"hyper 1.4.1",
|
||||
"hyper-timeout",
|
||||
"hyper-util",
|
||||
"percent-encoding",
|
||||
"pin-project",
|
||||
"prost",
|
||||
"socket2",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tower",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower"
|
||||
version = "0.4.13"
|
||||
@@ -6168,9 +6372,13 @@ checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"indexmap 1.9.3",
|
||||
"pin-project",
|
||||
"pin-project-lite",
|
||||
"rand 0.8.5",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "deltachat"
|
||||
version = "1.148.4"
|
||||
version = "1.148.1"
|
||||
edition = "2021"
|
||||
license = "MPL-2.0"
|
||||
rust-version = "1.77"
|
||||
@@ -42,7 +42,6 @@ anyhow = { workspace = true }
|
||||
async-broadcast = "0.7.1"
|
||||
async-channel = { workspace = true }
|
||||
async-imap = { version = "0.10.2", default-features = false, features = ["runtime-tokio", "compress"] }
|
||||
async-compression = { version = "0.4.15", default-features = false, features = ["tokio", "gzip"] }
|
||||
async-native-tls = { version = "0.5", default-features = false, features = ["runtime-tokio"] }
|
||||
async-smtp = { version = "0.9", default-features = false, features = ["runtime-tokio"] }
|
||||
async_zip = { version = "0.0.17", default-features = false, features = ["deflate", "tokio-fs"] }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "deltachat_ffi"
|
||||
version = "1.148.4"
|
||||
version = "1.148.1"
|
||||
description = "Deltachat FFI"
|
||||
edition = "2018"
|
||||
readme = "README.md"
|
||||
|
||||
@@ -2533,8 +2533,8 @@ void dc_stop_ongoing_process (dc_context_t* context);
|
||||
* ask the user if they want to use the given service for video chats;
|
||||
* if so, call dc_set_config_from_qr().
|
||||
*
|
||||
* - DC_QR_PROXY with dc_lot_t::text1=address:
|
||||
* ask the user if they want to use the given proxy.
|
||||
* - DC_QR_SOCKS5_PROXY with dc_lot_t::text1=host, dc_lot_t::text2=port:
|
||||
* ask the user if they want to use the given proxy and overwrite the previous one, if any.
|
||||
* if so, call dc_set_config_from_qr() and restart I/O.
|
||||
*
|
||||
* - DC_QR_ADDR with dc_lot_t::id=Contact ID:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "deltachat-jsonrpc"
|
||||
version = "1.148.4"
|
||||
version = "1.148.1"
|
||||
description = "DeltaChat JSON-RPC API"
|
||||
edition = "2021"
|
||||
default-run = "deltachat-jsonrpc-server"
|
||||
|
||||
@@ -18,7 +18,6 @@ use deltachat::constants::DC_MSG_ID_DAYMARKER;
|
||||
use deltachat::contact::{may_be_valid_addr, Contact, ContactId, Origin};
|
||||
use deltachat::context::get_info;
|
||||
use deltachat::ephemeral::Timer;
|
||||
use deltachat::location;
|
||||
use deltachat::message::get_msg_read_receipts;
|
||||
use deltachat::message::{
|
||||
self, delete_msgs, markseen_msgs, Message, MessageState, MsgId, Viewtype,
|
||||
@@ -35,6 +34,7 @@ use deltachat::stock_str::StockMessage;
|
||||
use deltachat::webxdc::StatusUpdateSerial;
|
||||
use deltachat::EventEmitter;
|
||||
use deltachat::{imex, info};
|
||||
use deltachat::{location, spawn_named_task};
|
||||
use sanitize_filename::is_sanitized;
|
||||
use tokio::fs;
|
||||
use tokio::sync::{watch, Mutex, RwLock};
|
||||
@@ -1777,7 +1777,7 @@ impl CommandApi {
|
||||
let ctx = self.get_context(account_id).await?;
|
||||
let fut = send_webxdc_realtime_advertisement(&ctx, MsgId::new(instance_msg_id)).await?;
|
||||
if let Some(fut) = fut {
|
||||
tokio::spawn(async move {
|
||||
spawn_named_task!("send_webxdc_realtime_advertisement", async move {
|
||||
fut.await.ok();
|
||||
info!(ctx, "send_webxdc_realtime_advertisement done")
|
||||
});
|
||||
|
||||
@@ -17,9 +17,6 @@ pub enum Account {
|
||||
// size: u32,
|
||||
profile_image: Option<String>, // TODO: This needs to be converted to work with blob http server.
|
||||
color: String,
|
||||
/// Optional tag as "Work", "Family".
|
||||
/// Meant to help profile owner to differ between profiles with similar names.
|
||||
private_tag: Option<String>,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
Unconfigured { id: u32 },
|
||||
@@ -34,14 +31,12 @@ impl Account {
|
||||
let color = color_int_to_hex_string(
|
||||
Contact::get_by_id(ctx, ContactId::SELF).await?.get_color(),
|
||||
);
|
||||
let private_tag = ctx.get_config(Config::PrivateTag).await?;
|
||||
Ok(Account::Configured {
|
||||
id,
|
||||
display_name,
|
||||
addr,
|
||||
profile_image,
|
||||
color,
|
||||
private_tag,
|
||||
})
|
||||
} else {
|
||||
Ok(Account::Unconfigured { id })
|
||||
|
||||
@@ -58,5 +58,5 @@
|
||||
},
|
||||
"type": "module",
|
||||
"types": "dist/deltachat.d.ts",
|
||||
"version": "1.148.4"
|
||||
"version": "1.148.1"
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
[package]
|
||||
name = "deltachat-repl"
|
||||
version = "1.148.4"
|
||||
version = "1.148.1"
|
||||
license = "MPL-2.0"
|
||||
edition = "2021"
|
||||
repository = "https://github.com/deltachat/deltachat-core-rust"
|
||||
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
console-subscriber = "0.4.0"
|
||||
deltachat = { workspace = true, features = ["internals"]}
|
||||
dirs = "5"
|
||||
log = { workspace = true }
|
||||
@@ -15,6 +16,7 @@ qr2term = "0.3.3"
|
||||
rusqlite = { workspace = true }
|
||||
rustyline = "14"
|
||||
tokio = { workspace = true, features = ["fs", "rt-multi-thread", "macros"] }
|
||||
tracing = "0.1.40"
|
||||
tracing-subscriber = { workspace = true, features = ["env-filter"] }
|
||||
|
||||
[features]
|
||||
|
||||
57
deltachat-repl/README.md
Normal file
57
deltachat-repl/README.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# Delta Chat REPL
|
||||
|
||||
This is a [REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop) frontend built on top of Delta Chat core.
|
||||
Its purpose is to help with testing during development, it is not meant for end users.
|
||||
|
||||
Dependencies:
|
||||
- If you want to use `getqr` you need `qrencode` (To install, use your system's package manager)
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
cargo run <path to deltachat db>
|
||||
```
|
||||
|
||||
Type in `help` to learn about what commands are available.
|
||||
|
||||
## Usage with `tokio-console`
|
||||
|
||||
Tokio is an async runtime that Delta Chat core uses.
|
||||
Core uses Tokio tasks, which are something similar to threads.
|
||||
`tokio-console` is like a task manager for these Tokio tasks.
|
||||
|
||||
Examples of tasks:
|
||||
- The event loop in the REPL tool which processes events received from core
|
||||
- The REPL loop itself which waits for and executes user commands
|
||||
- The IMAP task that manages IMAP connection in core
|
||||
|
||||
```
|
||||
RUSTFLAGS="--cfg tokio_unstable" cargo run <path to deltachat db>
|
||||
```
|
||||
|
||||
Then in a new console window start [`tokio-console`](https://github.com/tokio-rs/console).
|
||||
You can install it via `cargo install --locked tokio-console`.
|
||||
|
||||
### Example
|
||||
|
||||
An example session in the REPL tool:
|
||||
|
||||
```
|
||||
RUSTFLAGS="--cfg tokio_unstable" cargo run test-db/db
|
||||
setqr dcaccount:https://nine.testrun.org/new
|
||||
configure
|
||||
connect
|
||||
listchats
|
||||
getqr
|
||||
```
|
||||
|
||||
Use the qrcode/openpgp4fpr link to setup the contact on Delta Chat.
|
||||
Then write a message to that new contact, after that you can accept the chat in the REPL tool and send a reply:
|
||||
|
||||
```
|
||||
listchats
|
||||
accept 12
|
||||
chat 12
|
||||
send hi!
|
||||
chat
|
||||
```
|
||||
@@ -30,7 +30,7 @@ use rustyline::{
|
||||
};
|
||||
use tokio::fs;
|
||||
use tokio::runtime::Handle;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
use tracing_subscriber::{prelude::__tracing_subscriber_SubscriberExt, EnvFilter, Layer};
|
||||
|
||||
mod cmdline;
|
||||
use self::cmdline::*;
|
||||
@@ -317,7 +317,7 @@ async fn start(args: Vec<String>) -> Result<(), Error> {
|
||||
.await?;
|
||||
|
||||
let events = context.get_event_emitter();
|
||||
tokio::task::spawn(async move {
|
||||
spawn_named_task!("repl:receive_event", async move {
|
||||
while let Some(event) = events.recv().await {
|
||||
receive_event(event.typ);
|
||||
}
|
||||
@@ -333,7 +333,7 @@ async fn start(args: Vec<String>) -> Result<(), Error> {
|
||||
let mut selected_chat = ChatId::default();
|
||||
|
||||
let ctx = context.clone();
|
||||
let input_loop = tokio::task::spawn_blocking(move || {
|
||||
let input_loop = spawn_named_blocking_task!("repl:input_loop", move || {
|
||||
let h = DcHelper {
|
||||
completer: FilenameCompleter::new(),
|
||||
highlighter: MatchingBracketHighlighter::new(),
|
||||
@@ -353,7 +353,6 @@ async fn start(args: Vec<String>) -> Result<(), Error> {
|
||||
|
||||
match readline {
|
||||
Ok(line) => {
|
||||
// TODO: ignore "set mail_pw"
|
||||
rl.add_history_entry(line.as_str())?;
|
||||
let should_continue = Handle::current().block_on(async {
|
||||
match handle_cmd(line.trim(), ctx.clone(), &mut selected_chat).await {
|
||||
@@ -481,11 +480,22 @@ async fn handle_cmd(
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Error> {
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(
|
||||
EnvFilter::from_default_env().add_directive("deltachat_repl=info".parse()?),
|
||||
)
|
||||
.init();
|
||||
#[allow(unexpected_cfgs)]
|
||||
tracing::subscriber::set_global_default({
|
||||
let subscribers = tracing_subscriber::Registry::default().with(
|
||||
tracing_subscriber::fmt::layer().with_filter(
|
||||
EnvFilter::from_default_env().add_directive("deltachat_repl=info".parse()?),
|
||||
),
|
||||
);
|
||||
#[cfg(tokio_unstable)]
|
||||
{
|
||||
subscribers.with(console_subscriber::spawn())
|
||||
}
|
||||
#[cfg(not(tokio_unstable))]
|
||||
{
|
||||
subscribers
|
||||
}
|
||||
})?;
|
||||
|
||||
let args = std::env::args().collect();
|
||||
start(args).await?;
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "deltachat-rpc-client"
|
||||
version = "1.148.4"
|
||||
version = "1.148.1"
|
||||
description = "Python client for Delta Chat core JSON-RPC interface"
|
||||
classifiers = [
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
|
||||
@@ -63,7 +63,6 @@ class EventType(str, Enum):
|
||||
CHATLIST_ITEM_CHANGED = "ChatlistItemChanged"
|
||||
CONFIG_SYNCED = "ConfigSynced"
|
||||
WEBXDC_REALTIME_DATA = "WebxdcRealtimeData"
|
||||
WEBXDC_REALTIME_ADVERTISEMENT_RECEIVED = "WebxdcRealtimeAdvertisementReceived"
|
||||
|
||||
|
||||
class ChatId(IntEnum):
|
||||
|
||||
@@ -7,7 +7,6 @@ If you want to debug iroh at rust-trace/log level set
|
||||
RUST_LOG=iroh_net=trace,iroh_gossip=trace
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
@@ -108,15 +107,13 @@ def test_realtime_sequentially(acfactory, path_to_webxdc):
|
||||
assert snapshot.text == "ping2"
|
||||
|
||||
log("sending realtime data ac1 -> ac2")
|
||||
# Test that 128 KB of data can be sent in a single message.
|
||||
data = os.urandom(128000)
|
||||
ac1_webxdc_msg.send_webxdc_realtime_data(data)
|
||||
ac1_webxdc_msg.send_webxdc_realtime_data(b"foo")
|
||||
|
||||
log("ac2: waiting for realtime data")
|
||||
while 1:
|
||||
event = ac2.wait_for_event()
|
||||
if event.kind == EventType.WEBXDC_REALTIME_DATA:
|
||||
assert event.data == list(data)
|
||||
assert event.data == list(b"foo")
|
||||
break
|
||||
|
||||
|
||||
@@ -211,28 +208,3 @@ def test_no_reordering(acfactory, path_to_webxdc):
|
||||
if event.data[0] == i:
|
||||
break
|
||||
pytest.fail("Reordering detected")
|
||||
|
||||
|
||||
def test_advertisement_after_chatting(acfactory, path_to_webxdc):
|
||||
"""Test that realtime advertisement is assigned to the correct message after chatting."""
|
||||
ac1, ac2 = acfactory.get_online_accounts(2)
|
||||
ac1.set_config("webxdc_realtime_enabled", "1")
|
||||
ac2.set_config("webxdc_realtime_enabled", "1")
|
||||
|
||||
ac1_ac2_chat = ac1.create_chat(ac2)
|
||||
ac1_webxdc_msg = ac1_ac2_chat.send_message(text="WebXDC", file=path_to_webxdc)
|
||||
ac2_webxdc_msg = ac2.wait_for_incoming_msg()
|
||||
assert ac2_webxdc_msg.get_snapshot().text == "WebXDC"
|
||||
|
||||
ac1_ac2_chat.send_text("Hello!")
|
||||
ac2_hello_msg = ac2.wait_for_incoming_msg()
|
||||
ac2_hello_msg_snapshot = ac2_hello_msg.get_snapshot()
|
||||
assert ac2_hello_msg_snapshot.text == "Hello!"
|
||||
ac2_hello_msg_snapshot.chat.accept()
|
||||
|
||||
ac2_webxdc_msg.send_webxdc_realtime_advertisement()
|
||||
while 1:
|
||||
event = ac1.wait_for_event()
|
||||
if event.kind == EventType.WEBXDC_REALTIME_ADVERTISEMENT_RECEIVED:
|
||||
assert event.msg_id == ac1_webxdc_msg.id
|
||||
break
|
||||
|
||||
@@ -61,7 +61,7 @@ def test_qr_securejoin(acfactory, protect, tmp_path):
|
||||
# Setup second device for Alice
|
||||
# to test observing securejoin protocol.
|
||||
alice.export_backup(tmp_path)
|
||||
files = list(tmp_path.glob("*.tar.gz"))
|
||||
files = list(tmp_path.glob("*.tar"))
|
||||
alice2 = acfactory.get_unconfigured_account()
|
||||
alice2.import_backup(files[0])
|
||||
|
||||
|
||||
@@ -379,7 +379,7 @@ def test_import_export_backup(acfactory, tmp_path) -> None:
|
||||
alice = acfactory.new_configured_account()
|
||||
alice.export_backup(tmp_path)
|
||||
|
||||
files = list(tmp_path.glob("*.tar.gz"))
|
||||
files = list(tmp_path.glob("*.tar"))
|
||||
alice2 = acfactory.get_unconfigured_account()
|
||||
alice2.import_backup(files[0])
|
||||
|
||||
@@ -630,7 +630,7 @@ def test_markseen_contact_request(acfactory, tmp_path):
|
||||
|
||||
# Bob sets up a second device.
|
||||
bob.export_backup(tmp_path)
|
||||
files = list(tmp_path.glob("*.tar.gz"))
|
||||
files = list(tmp_path.glob("*.tar"))
|
||||
bob2 = acfactory.get_unconfigured_account()
|
||||
bob2.import_backup(files[0])
|
||||
bob2.start_io()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "deltachat-rpc-server"
|
||||
version = "1.148.4"
|
||||
version = "1.148.1"
|
||||
description = "DeltaChat JSON-RPC server"
|
||||
edition = "2021"
|
||||
readme = "README.md"
|
||||
@@ -22,6 +22,8 @@ tokio = { workspace = true, features = ["io-std"] }
|
||||
tokio-util = { workspace = true }
|
||||
tracing-subscriber = { workspace = true, features = ["env-filter"] }
|
||||
yerpc = { workspace = true, features = ["anyhow_expose", "openrpc"] }
|
||||
console-subscriber = "0.4.0"
|
||||
tracing = "0.1.40"
|
||||
|
||||
[features]
|
||||
default = ["vendored"]
|
||||
|
||||
@@ -35,3 +35,21 @@ languages other than Rust, for example:
|
||||
|
||||
Run `deltachat-rpc-server --version` to check the version of the server.
|
||||
Run `deltachat-rpc-server --openrpc` to get [OpenRPC](https://open-rpc.org/) specification of the provided JSON-RPC API.
|
||||
|
||||
## Usage with `tokio-console`
|
||||
|
||||
When built with `RUSTFLAGS="--cfg tokio_unstable"`, console-subscriber is enabled.
|
||||
That means that you can use [`tokio-console`](https://github.com/tokio-rs/console) to inspect active Tokio tasks.
|
||||
You can install it via `cargo install tokio-console`.
|
||||
|
||||
```sh
|
||||
RUSTFLAGS="--cfg tokio_unstable" cargo run
|
||||
```
|
||||
|
||||
### Usage in deltachat-desktop:
|
||||
|
||||
Follow steps from `deltachat-desktop/docs/UPDATE_CORE.md`, but run the `make_local_dev_version` script with the `tokio_unstable` rustflag:
|
||||
|
||||
```sh
|
||||
RUSTFLAGS="--cfg tokio_unstable" python3 deltachat-rpc-server/npm-package/scripts/make_local_dev_version.py
|
||||
```
|
||||
|
||||
@@ -15,5 +15,5 @@
|
||||
},
|
||||
"type": "module",
|
||||
"types": "index.d.ts",
|
||||
"version": "1.148.4"
|
||||
"version": "1.148.1"
|
||||
}
|
||||
|
||||
@@ -7,11 +7,11 @@ use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::{anyhow, Context as _, Result};
|
||||
use deltachat::constants::DC_VERSION_STR;
|
||||
use deltachat::{constants::DC_VERSION_STR, spawn_named_task};
|
||||
use deltachat_jsonrpc::api::{Accounts, CommandApi};
|
||||
use futures_lite::stream::StreamExt;
|
||||
use tokio::io::{self, AsyncBufReadExt, BufReader};
|
||||
use tracing_subscriber::EnvFilter;
|
||||
use tracing_subscriber::{prelude::*, EnvFilter};
|
||||
use yerpc::RpcServer as _;
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
@@ -67,10 +67,23 @@ async fn main_impl() -> Result<()> {
|
||||
// Logs from `log` crate and traces from `tracing` crate
|
||||
// are configurable with `RUST_LOG` environment variable
|
||||
// and go to stderr to avoid interferring with JSON-RPC using stdout.
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(EnvFilter::from_default_env())
|
||||
.with_writer(std::io::stderr)
|
||||
.init();
|
||||
#[allow(unexpected_cfgs)]
|
||||
tracing::subscriber::set_global_default({
|
||||
let subscribers = tracing_subscriber::Registry::default().with(
|
||||
tracing_subscriber::fmt::layer()
|
||||
.with_writer(std::io::stderr)
|
||||
.with_filter(EnvFilter::from_default_env()),
|
||||
);
|
||||
|
||||
#[cfg(tokio_unstable)]
|
||||
{
|
||||
subscribers.with(console_subscriber::spawn())
|
||||
}
|
||||
#[cfg(not(tokio_unstable))]
|
||||
{
|
||||
subscribers
|
||||
}
|
||||
})?;
|
||||
|
||||
let path = std::env::var("DC_ACCOUNTS_PATH").unwrap_or_else(|_| "accounts".to_string());
|
||||
log::info!("Starting with accounts directory `{}`.", path);
|
||||
@@ -87,7 +100,7 @@ async fn main_impl() -> Result<()> {
|
||||
|
||||
// Send task prints JSON responses to stdout.
|
||||
let cancel = main_cancel.clone();
|
||||
let send_task: JoinHandle<anyhow::Result<()>> = tokio::spawn(async move {
|
||||
let send_task: JoinHandle<anyhow::Result<()>> = spawn_named_task!("send_task", async move {
|
||||
let _cancel_guard = cancel.clone().drop_guard();
|
||||
loop {
|
||||
let message = tokio::select! {
|
||||
@@ -104,24 +117,25 @@ async fn main_impl() -> Result<()> {
|
||||
});
|
||||
|
||||
let cancel = main_cancel.clone();
|
||||
let sigterm_task: JoinHandle<anyhow::Result<()>> = tokio::spawn(async move {
|
||||
#[cfg(target_family = "unix")]
|
||||
{
|
||||
let _cancel_guard = cancel.clone().drop_guard();
|
||||
tokio::select! {
|
||||
_ = cancel.cancelled() => (),
|
||||
_ = sigterm.recv() => {
|
||||
log::info!("got SIGTERM");
|
||||
let sigterm_task: JoinHandle<anyhow::Result<()>> =
|
||||
spawn_named_task!("sigterm_task", async move {
|
||||
#[cfg(target_family = "unix")]
|
||||
{
|
||||
let _cancel_guard = cancel.clone().drop_guard();
|
||||
tokio::select! {
|
||||
_ = cancel.cancelled() => (),
|
||||
_ = sigterm.recv() => {
|
||||
log::info!("got SIGTERM");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let _ = cancel;
|
||||
Ok(())
|
||||
});
|
||||
let _ = cancel;
|
||||
Ok(())
|
||||
});
|
||||
|
||||
// Receiver task reads JSON requests from stdin.
|
||||
let cancel = main_cancel.clone();
|
||||
let recv_task: JoinHandle<anyhow::Result<()>> = tokio::spawn(async move {
|
||||
let recv_task: JoinHandle<anyhow::Result<()>> = spawn_named_task!("recv_task", async move {
|
||||
let _cancel_guard = cancel.clone().drop_guard();
|
||||
let stdin = io::stdin();
|
||||
let mut lines = BufReader::new(stdin).lines();
|
||||
@@ -143,7 +157,7 @@ async fn main_impl() -> Result<()> {
|
||||
};
|
||||
log::trace!("RPC recv {}", message);
|
||||
let session = session.clone();
|
||||
tokio::spawn(async move {
|
||||
spawn_named_task!("handle_incoming", async move {
|
||||
session.handle_incoming(&message).await;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -29,9 +29,11 @@ skip = [
|
||||
{ name = "futures-lite", version = "1.13.0" },
|
||||
{ name = "getrandom", version = "<0.2" },
|
||||
{ name = "h2", version = "0.3.26" },
|
||||
{ name = "hashbrown", version = "0.12.3"},
|
||||
{ name = "http-body", version = "0.4.6" },
|
||||
{ name = "http", version = "0.2.12" },
|
||||
{ name = "hyper", version = "0.14.28" },
|
||||
{ name = "indexmap", version = "1.9.3" },
|
||||
{ name = "nix", version = "0.26.4" },
|
||||
{ name = "quick-error", version = "<2.0" },
|
||||
{ name = "rand_chacha", version = "<0.3" },
|
||||
|
||||
@@ -55,5 +55,5 @@
|
||||
"test:mocha": "mocha node/test/test.mjs --growl --reporter=spec --bail --exit"
|
||||
},
|
||||
"types": "node/dist/index.d.ts",
|
||||
"version": "1.148.4"
|
||||
"version": "1.148.1"
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "deltachat"
|
||||
version = "1.148.4"
|
||||
version = "1.148.1"
|
||||
description = "Python bindings for the Delta Chat Core library using CFFI against the Rust-implemented libdeltachat"
|
||||
readme = "README.rst"
|
||||
requires-python = ">=3.7"
|
||||
|
||||
@@ -1 +1 @@
|
||||
2024-10-24
|
||||
2024-10-23
|
||||
@@ -400,36 +400,39 @@ impl Config {
|
||||
|
||||
#[cfg(not(target_os = "ios"))]
|
||||
async fn create_lock_task(dir: PathBuf) -> Result<Option<JoinHandle<anyhow::Result<()>>>> {
|
||||
use crate::spawn_named_task;
|
||||
|
||||
let lockfile = dir.join(LOCKFILE_NAME);
|
||||
let mut lock = fd_lock::RwLock::new(fs::File::create(lockfile).await?);
|
||||
let (locked_tx, locked_rx) = oneshot::channel();
|
||||
let lock_task: JoinHandle<anyhow::Result<()>> = tokio::spawn(async move {
|
||||
let mut timeout = Duration::from_millis(100);
|
||||
let _guard = loop {
|
||||
match lock.try_write() {
|
||||
Ok(guard) => break Ok(guard),
|
||||
Err(err) => {
|
||||
if timeout.as_millis() > 1600 {
|
||||
break Err(err);
|
||||
}
|
||||
// We need to wait for the previous lock_task to be aborted thus unlocking
|
||||
// the lockfile. We don't open configs for writing often outside of the
|
||||
// tests, so this adds delays to the tests, but otherwise ok.
|
||||
sleep(timeout).await;
|
||||
if err.kind() == std::io::ErrorKind::WouldBlock {
|
||||
timeout *= 2;
|
||||
let lock_task: JoinHandle<anyhow::Result<()>> =
|
||||
spawn_named_task!("lock_task", async move {
|
||||
let mut timeout = Duration::from_millis(100);
|
||||
let _guard = loop {
|
||||
match lock.try_write() {
|
||||
Ok(guard) => break Ok(guard),
|
||||
Err(err) => {
|
||||
if timeout.as_millis() > 1600 {
|
||||
break Err(err);
|
||||
}
|
||||
// We need to wait for the previous lock_task to be aborted thus unlocking
|
||||
// the lockfile. We don't open configs for writing often outside of the
|
||||
// tests, so this adds delays to the tests, but otherwise ok.
|
||||
sleep(timeout).await;
|
||||
if err.kind() == std::io::ErrorKind::WouldBlock {
|
||||
timeout *= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}?;
|
||||
locked_tx
|
||||
.send(())
|
||||
.ok()
|
||||
.context("Cannot notify about lockfile locking")?;
|
||||
let (_tx, rx) = oneshot::channel();
|
||||
rx.await?;
|
||||
Ok(())
|
||||
});
|
||||
}?;
|
||||
locked_tx
|
||||
.send(())
|
||||
.ok()
|
||||
.context("Cannot notify about lockfile locking")?;
|
||||
let (_tx, rx) = oneshot::channel();
|
||||
rx.await?;
|
||||
Ok(())
|
||||
});
|
||||
locked_rx.await?;
|
||||
Ok(Some(lock_task))
|
||||
}
|
||||
|
||||
@@ -12,12 +12,10 @@ use deltachat_contact_tools::{sanitize_bidi_characters, sanitize_single_line, Co
|
||||
use deltachat_derive::{FromSql, ToSql};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum_macros::EnumIter;
|
||||
use tokio::task;
|
||||
|
||||
use crate::aheader::EncryptPreference;
|
||||
use crate::blob::BlobObject;
|
||||
use crate::chatlist::Chatlist;
|
||||
use crate::chatlist_events;
|
||||
use crate::color::str_to_color;
|
||||
use crate::config::Config;
|
||||
use crate::constants::{
|
||||
@@ -50,6 +48,7 @@ use crate::tools::{
|
||||
truncate_msg_text, IsNoneOrEmpty, SystemTime,
|
||||
};
|
||||
use crate::webxdc::StatusUpdateSerial;
|
||||
use crate::{chatlist_events, spawn_named_task};
|
||||
|
||||
/// An chat item, such as a message or a marker.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
@@ -1476,7 +1475,7 @@ impl ChatId {
|
||||
/// and otherwise notifying the user accordingly.
|
||||
pub(crate) fn spawn_securejoin_wait(self, context: &Context, timeout: u64) {
|
||||
let context = context.clone();
|
||||
task::spawn(async move {
|
||||
spawn_named_task!("securejoin_wait", async move {
|
||||
tokio::time::sleep(Duration::from_secs(timeout)).await;
|
||||
let chat = Chat::load_from_db(&context, self).await?;
|
||||
chat.check_securejoin_wait(&context, 0).await?;
|
||||
|
||||
@@ -21,7 +21,6 @@ use futures::FutureExt;
|
||||
use futures_lite::FutureExt as _;
|
||||
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
|
||||
use server_params::{expand_param_vector, ServerParams};
|
||||
use tokio::task;
|
||||
|
||||
use crate::config::{self, Config};
|
||||
use crate::context::Context;
|
||||
@@ -35,10 +34,10 @@ use crate::message::{Message, Viewtype};
|
||||
use crate::oauth2::get_oauth2_addr;
|
||||
use crate::provider::{Protocol, Socket, UsernamePattern};
|
||||
use crate::smtp::Smtp;
|
||||
use crate::stock_str;
|
||||
use crate::sync::Sync::*;
|
||||
use crate::tools::time;
|
||||
use crate::{chat, e2ee, provider};
|
||||
use crate::{spawn_named_task, stock_str};
|
||||
use deltachat_contact_tools::addr_cmp;
|
||||
|
||||
macro_rules! progress {
|
||||
@@ -372,7 +371,9 @@ async fn configure(ctx: &Context, param: &EnteredLoginParam) -> Result<Configure
|
||||
progress!(ctx, 1);
|
||||
|
||||
let ctx2 = ctx.clone();
|
||||
let update_device_chats_handle = task::spawn(async move { ctx2.update_device_chats().await });
|
||||
let update_device_chats_handle = spawn_named_task!("update_device_chats", async move {
|
||||
ctx2.update_device_chats().await
|
||||
});
|
||||
|
||||
let configured_param = get_configured_param(ctx, param).await?;
|
||||
let strict_tls = configured_param.strict_tls();
|
||||
@@ -387,7 +388,7 @@ async fn configure(ctx: &Context, param: &EnteredLoginParam) -> Result<Configure
|
||||
let smtp_addr = configured_param.addr.clone();
|
||||
let proxy_config = configured_param.proxy_config.clone();
|
||||
|
||||
let smtp_config_task = task::spawn(async move {
|
||||
let smtp_config_task = spawn_named_task!("smtp_config", async move {
|
||||
let mut smtp = Smtp::new();
|
||||
smtp.connect(
|
||||
&context_smtp,
|
||||
|
||||
@@ -4,16 +4,12 @@
|
||||
|
||||
use deltachat_derive::{FromSql, ToSql};
|
||||
use once_cell::sync::Lazy;
|
||||
use percent_encoding::{AsciiSet, NON_ALPHANUMERIC};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::chat::ChatId;
|
||||
|
||||
pub static DC_VERSION_STR: Lazy<String> = Lazy::new(|| env!("CARGO_PKG_VERSION").to_string());
|
||||
|
||||
/// Set of characters to percent-encode in email addresses and names.
|
||||
pub(crate) const NON_ALPHANUMERIC_WITHOUT_DOT: &AsciiSet = &NON_ALPHANUMERIC.remove(b'.');
|
||||
|
||||
#[derive(
|
||||
Debug,
|
||||
Default,
|
||||
|
||||
@@ -37,7 +37,7 @@ use crate::peerstate::Peerstate;
|
||||
use crate::sql::{self, params_iter};
|
||||
use crate::sync::{self, Sync::*};
|
||||
use crate::tools::{duration_to_str, get_abs_path, smeared_time, time, SystemTime};
|
||||
use crate::{chat, chatlist_events, stock_str};
|
||||
use crate::{chat, chatlist_events, spawn_named_task, stock_str};
|
||||
|
||||
/// Time during which a contact is considered as seen recently.
|
||||
const SEEN_RECENTLY_SECONDS: i64 = 600;
|
||||
@@ -1791,7 +1791,7 @@ impl RecentlySeenLoop {
|
||||
pub(crate) fn new(context: Context) -> Self {
|
||||
let (interrupt_send, interrupt_recv) = channel::bounded(1);
|
||||
|
||||
let handle = task::spawn(Self::run(context, interrupt_recv));
|
||||
let handle = spawn_named_task!("recently_seen_loop", Self::run(context, interrupt_recv));
|
||||
Self {
|
||||
handle,
|
||||
interrupt_send,
|
||||
|
||||
@@ -5,6 +5,7 @@ use crate::context::Context;
|
||||
use crate::events::EventType;
|
||||
use crate::message::{Message, MsgId, Viewtype};
|
||||
use crate::param::Param;
|
||||
use crate::spawn_named_task;
|
||||
use crate::tools::time;
|
||||
use crate::webxdc::StatusUpdateItem;
|
||||
use async_channel::{self as channel, Receiver, Sender};
|
||||
@@ -150,7 +151,7 @@ pub(crate) async fn set_debug_logging_xdc(ctx: &Context, id: Option<MsgId>) -> a
|
||||
let (sender, debug_logging_recv) = channel::bounded(1000);
|
||||
let loop_handle = {
|
||||
let ctx = ctx.clone();
|
||||
task::spawn(async move {
|
||||
spawn_named_task!("xdc_debug_logging_loop", async move {
|
||||
debug_logging_loop(&ctx, debug_logging_recv).await
|
||||
})
|
||||
};
|
||||
|
||||
@@ -24,7 +24,6 @@ use rand::Rng;
|
||||
use ratelimit::Ratelimit;
|
||||
use url::Url;
|
||||
|
||||
use crate::chat::{self, ChatId, ChatIdBlocked};
|
||||
use crate::chatlist_events;
|
||||
use crate::config::Config;
|
||||
use crate::constants::{self, Blocked, Chattype, ShowEmails};
|
||||
@@ -48,6 +47,10 @@ use crate::scheduler::connectivity::ConnectivityStore;
|
||||
use crate::sql;
|
||||
use crate::stock_str;
|
||||
use crate::tools::{self, create_id, duration_to_str};
|
||||
use crate::{
|
||||
chat::{self, ChatId, ChatIdBlocked},
|
||||
spawn_named_task,
|
||||
};
|
||||
|
||||
pub(crate) mod capabilities;
|
||||
mod client;
|
||||
@@ -1556,7 +1559,9 @@ impl Session {
|
||||
} else if !context.push_subscriber.heartbeat_subscribed().await {
|
||||
let context = context.clone();
|
||||
// Subscribe for heartbeat notifications.
|
||||
tokio::spawn(async move { context.push_subscriber.subscribe(&context).await });
|
||||
spawn_named_task!("subscribe_to_heartbeat_notifications", async move {
|
||||
context.push_subscriber.subscribe(&context).await
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
72
src/imex.rs
72
src/imex.rs
@@ -11,7 +11,7 @@ use futures_lite::FutureExt;
|
||||
use pin_project::pin_project;
|
||||
|
||||
use tokio::fs::{self, File};
|
||||
use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt, ReadBuf};
|
||||
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
|
||||
use tokio_tar::Archive;
|
||||
|
||||
use crate::blob::BlobDirContents;
|
||||
@@ -123,7 +123,7 @@ pub async fn has_backup(_context: &Context, dir_name: &Path) -> Result<String> {
|
||||
let name = dirent.file_name();
|
||||
let name: String = name.to_string_lossy().into();
|
||||
if name.starts_with("delta-chat")
|
||||
&& (name.ends_with(".tar") || name.ends_with(".tar.gz"))
|
||||
&& name.ends_with(".tar")
|
||||
&& (newest_backup_name.is_empty() || name > newest_backup_name)
|
||||
{
|
||||
// We just use string comparison to determine which backup is newer.
|
||||
@@ -269,24 +269,30 @@ async fn import_backup(
|
||||
context.get_dbfile().display()
|
||||
);
|
||||
|
||||
let backup_file = ProgressReader::new(backup_file, context.clone(), file_size);
|
||||
if backup_to_import.extension() == Some(OsStr::new("gz")) {
|
||||
let backup_file = tokio::io::BufReader::new(backup_file);
|
||||
let backup_file = async_compression::tokio::bufread::GzipDecoder::new(backup_file);
|
||||
import_backup_stream(context, backup_file, passphrase).await?;
|
||||
} else {
|
||||
import_backup_stream(context, backup_file, passphrase).await?;
|
||||
}
|
||||
import_backup_stream(context, backup_file, file_size, passphrase).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Imports backup by reading a tar file from a stream.
|
||||
///
|
||||
/// `file_size` is used to calculate the progress
|
||||
/// and emit progress events.
|
||||
/// Ideally it is the sum of the entry
|
||||
/// sizes without the header overhead,
|
||||
/// but can be estimated as tar file size
|
||||
/// in which case the progress is underestimated
|
||||
/// and may not reach 99.9% by the end of import.
|
||||
/// Underestimating is better than
|
||||
/// overestimating because the progress
|
||||
/// jumps to 100% instead of getting stuck at 99.9%
|
||||
/// for some time.
|
||||
pub(crate) async fn import_backup_stream<R: tokio::io::AsyncRead + Unpin>(
|
||||
context: &Context,
|
||||
backup_file: R,
|
||||
file_size: u64,
|
||||
passphrase: String,
|
||||
) -> Result<()> {
|
||||
import_backup_stream_inner(context, backup_file, passphrase)
|
||||
import_backup_stream_inner(context, backup_file, file_size, passphrase)
|
||||
.await
|
||||
.0
|
||||
}
|
||||
@@ -313,19 +319,6 @@ struct ProgressReader<R> {
|
||||
}
|
||||
|
||||
impl<R> ProgressReader<R> {
|
||||
/// Creates a new `ProgressReader`.
|
||||
///
|
||||
/// `file_size` is used to calculate the progress
|
||||
/// and emit progress events.
|
||||
/// Ideally it is the sum of the entry
|
||||
/// sizes without the header overhead,
|
||||
/// but can be estimated as tar file size
|
||||
/// in which case the progress is underestimated
|
||||
/// and may not reach 99.9% by the end of import.
|
||||
/// Underestimating is better than
|
||||
/// overestimating because the progress
|
||||
/// jumps to 100% instead of getting stuck at 99.9%
|
||||
/// for some time.
|
||||
fn new(r: R, context: Context, file_size: u64) -> Self {
|
||||
Self {
|
||||
inner: r,
|
||||
@@ -365,8 +358,10 @@ where
|
||||
async fn import_backup_stream_inner<R: tokio::io::AsyncRead + Unpin>(
|
||||
context: &Context,
|
||||
backup_file: R,
|
||||
file_size: u64,
|
||||
passphrase: String,
|
||||
) -> (Result<()>,) {
|
||||
let backup_file = ProgressReader::new(backup_file, context.clone(), file_size);
|
||||
let mut archive = Archive::new(backup_file);
|
||||
|
||||
let mut entries = match archive.entries() {
|
||||
@@ -466,10 +461,10 @@ fn get_next_backup_path(
|
||||
tempdbfile.push(format!("{stem}-{i:02}-{addr}.db"));
|
||||
|
||||
let mut tempfile = folder.clone();
|
||||
tempfile.push(format!("{stem}-{i:02}-{addr}.tar.gz.part"));
|
||||
tempfile.push(format!("{stem}-{i:02}-{addr}.tar.part"));
|
||||
|
||||
let mut destfile = folder.clone();
|
||||
destfile.push(format!("{stem}-{i:02}-{addr}.tar.gz"));
|
||||
destfile.push(format!("{stem}-{i:02}-{addr}.tar"));
|
||||
|
||||
if !tempdbfile.exists() && !tempfile.exists() && !destfile.exists() {
|
||||
return Ok((tempdbfile, tempfile, destfile));
|
||||
@@ -509,13 +504,9 @@ async fn export_backup(context: &Context, dir: &Path, passphrase: String) -> Res
|
||||
file_size += blob.to_abs_path().metadata()?.len()
|
||||
}
|
||||
|
||||
let gzip_encoder = async_compression::tokio::write::GzipEncoder::new(file);
|
||||
let mut gzip_encoder =
|
||||
export_backup_stream(context, &temp_db_path, blobdir, gzip_encoder, file_size)
|
||||
.await
|
||||
.context("Exporting backup to file failed")?;
|
||||
gzip_encoder.shutdown().await?;
|
||||
|
||||
export_backup_stream(context, &temp_db_path, blobdir, file, file_size)
|
||||
.await
|
||||
.context("Exporting backup to file failed")?;
|
||||
fs::rename(temp_path, &dest_path).await?;
|
||||
context.emit_event(EventType::ImexFileWritten(dest_path));
|
||||
Ok(())
|
||||
@@ -552,10 +543,6 @@ impl<W> ProgressWriter<W> {
|
||||
context,
|
||||
}
|
||||
}
|
||||
|
||||
fn into_inner(self) -> W {
|
||||
self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<W> AsyncWrite for ProgressWriter<W>
|
||||
@@ -603,12 +590,12 @@ pub(crate) async fn export_backup_stream<'a, W>(
|
||||
blobdir: BlobDirContents<'a>,
|
||||
writer: W,
|
||||
file_size: u64,
|
||||
) -> Result<W>
|
||||
) -> Result<()>
|
||||
where
|
||||
W: tokio::io::AsyncWrite + tokio::io::AsyncWriteExt + Unpin + Send + 'static,
|
||||
{
|
||||
let progress_writer = ProgressWriter::new(writer, context.clone(), file_size);
|
||||
let mut builder = tokio_tar::Builder::new(progress_writer);
|
||||
let writer = ProgressWriter::new(writer, context.clone(), file_size);
|
||||
let mut builder = tokio_tar::Builder::new(writer);
|
||||
|
||||
builder
|
||||
.append_path_with_name(temp_db_path, DBFILE_BACKUP_NAME)
|
||||
@@ -620,9 +607,8 @@ where
|
||||
builder.append_file(path_in_archive, &mut file).await?;
|
||||
}
|
||||
|
||||
// Convert tar builder back into the underlying stream.
|
||||
let progress_writer = builder.into_inner().await?;
|
||||
Ok(progress_writer.into_inner())
|
||||
builder.finish().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Imports secret key from a file.
|
||||
|
||||
@@ -36,18 +36,17 @@ use futures_lite::FutureExt;
|
||||
use iroh_net::relay::RelayMode;
|
||||
use iroh_net::Endpoint;
|
||||
use tokio::fs;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use tokio::task::JoinHandle;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
||||
use crate::chat::add_device_msg;
|
||||
use crate::context::Context;
|
||||
use crate::imex::{BlobDirContents, ProgressReader};
|
||||
use crate::imex::BlobDirContents;
|
||||
use crate::message::{Message, Viewtype};
|
||||
use crate::qr::Qr;
|
||||
use crate::stock_str::backup_transfer_msg_body;
|
||||
use crate::tools::{create_id, time, TempPathGuard};
|
||||
use crate::EventType;
|
||||
use crate::{spawn_named_task, EventType};
|
||||
|
||||
use super::{export_backup_stream, export_database, import_backup_stream, DBFILE_BACKUP_NAME};
|
||||
|
||||
@@ -133,7 +132,7 @@ impl BackupProvider {
|
||||
let drop_token = drop_token.clone();
|
||||
let endpoint = endpoint.clone();
|
||||
let auth_token = auth_token.clone();
|
||||
tokio::spawn(async move {
|
||||
spawn_named_task!("accept_loop", async move {
|
||||
Self::accept_loop(
|
||||
context.clone(),
|
||||
endpoint,
|
||||
@@ -191,11 +190,9 @@ impl BackupProvider {
|
||||
|
||||
send_stream.write_all(&file_size.to_be_bytes()).await?;
|
||||
|
||||
let mut send_stream =
|
||||
export_backup_stream(&context, &dbfile, blobdir, send_stream, file_size)
|
||||
.await
|
||||
.context("Failed to write backup into QUIC stream")?;
|
||||
send_stream.shutdown().await?;
|
||||
export_backup_stream(&context, &dbfile, blobdir, send_stream, file_size)
|
||||
.await
|
||||
.context("Failed to write backup into QUIC stream")?;
|
||||
info!(context, "Finished writing backup into QUIC stream.");
|
||||
let mut buf = [0u8; 1];
|
||||
info!(context, "Waiting for acknowledgment.");
|
||||
@@ -313,8 +310,7 @@ pub async fn get_backup2(
|
||||
let mut file_size_buf = [0u8; 8];
|
||||
recv_stream.read_exact(&mut file_size_buf).await?;
|
||||
let file_size = u64::from_be_bytes(file_size_buf);
|
||||
let recv_stream = ProgressReader::new(recv_stream, context.clone(), file_size);
|
||||
import_backup_stream(context, recv_stream, passphrase)
|
||||
import_backup_stream(context, recv_stream, file_size, passphrase)
|
||||
.await
|
||||
.context("Failed to import backup from QUIC stream")?;
|
||||
info!(context, "Finished importing backup from the stream.");
|
||||
|
||||
@@ -12,13 +12,13 @@ use pgp::composed::Deserializable;
|
||||
pub use pgp::composed::{SignedPublicKey, SignedSecretKey};
|
||||
use pgp::ser::Serialize;
|
||||
use pgp::types::{KeyTrait, SecretKeyTrait};
|
||||
use tokio::runtime::Handle;
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::constants::KeyGenType;
|
||||
use crate::context::Context;
|
||||
use crate::log::LogExt;
|
||||
use crate::pgp::KeyPair;
|
||||
use crate::spawn_named_blocking_task;
|
||||
use crate::tools::{self, time_elapsed};
|
||||
|
||||
/// Convenience trait for working with keys.
|
||||
@@ -251,8 +251,10 @@ async fn generate_keypair(context: &Context) -> Result<KeyPair> {
|
||||
let keytype = KeyGenType::from_i32(context.get_config_int(Config::KeyGenType).await?)
|
||||
.unwrap_or_default();
|
||||
info!(context, "Generating keypair with type {}", keytype);
|
||||
let keypair = Handle::current()
|
||||
.spawn_blocking(move || crate::pgp::create_keypair(addr, keytype))
|
||||
let keypair =
|
||||
spawn_named_blocking_task!("generate_keypair", move || crate::pgp::create_keypair(
|
||||
addr, keytype
|
||||
))
|
||||
.await??;
|
||||
|
||||
store_self_keypair(context, &keypair, KeyPairUse::Default).await?;
|
||||
|
||||
@@ -20,7 +20,6 @@ use crate::e2ee::EncryptHelper;
|
||||
use crate::ephemeral::Timer as EphemeralTimer;
|
||||
use crate::headerdef::HeaderDef;
|
||||
use crate::html::new_html_mimepart;
|
||||
use crate::location;
|
||||
use crate::message::{self, Message, MsgId, Viewtype};
|
||||
use crate::mimeparser::SystemMessage;
|
||||
use crate::param::Param;
|
||||
@@ -33,6 +32,7 @@ use crate::tools::{
|
||||
create_outgoing_rfc724_mid, create_smeared_timestamp, remove_subject_prefix, time,
|
||||
};
|
||||
use crate::webxdc::StatusUpdateSerial;
|
||||
use crate::{location, peer_channels};
|
||||
|
||||
// attachments of 25 mb brutto should work on the majority of providers
|
||||
// (brutto examples: web.de=50, 1&1=40, t-online.de=32, gmail=25, posteo=50, yahoo=25, all-inkl=100).
|
||||
@@ -1387,7 +1387,8 @@ impl MimeFactory {
|
||||
let json = msg.param.get(Param::Arg).unwrap_or_default();
|
||||
parts.push(context.build_status_update_part(json));
|
||||
} else if msg.viewtype == Viewtype::Webxdc {
|
||||
headers.push(create_iroh_header(context, msg.id).await?);
|
||||
let topic = peer_channels::create_random_topic();
|
||||
headers.push(create_iroh_header(context, topic, msg.id).await?);
|
||||
if let (Some(json), _) = context
|
||||
.render_webxdc_status_update_object(
|
||||
msg.id,
|
||||
|
||||
@@ -11,6 +11,7 @@ use crate::context::Context;
|
||||
use crate::net::proxy::ProxyConfig;
|
||||
use crate::net::session::SessionStream;
|
||||
use crate::net::tls::wrap_rustls;
|
||||
use crate::spawn_named_task;
|
||||
|
||||
/// HTTP(S) GET response.
|
||||
#[derive(Debug)]
|
||||
@@ -85,7 +86,7 @@ where
|
||||
|
||||
let io = TokioIo::new(stream);
|
||||
let (sender, conn) = hyper::client::conn::http1::handshake(io).await?;
|
||||
tokio::task::spawn(conn);
|
||||
spawn_named_task!("http_connection", conn);
|
||||
|
||||
Ok(sender)
|
||||
}
|
||||
|
||||
@@ -12,14 +12,13 @@ use fast_socks5::client::Socks5Stream;
|
||||
use fast_socks5::util::target_addr::ToTargetAddr;
|
||||
use fast_socks5::AuthenticationMethod;
|
||||
use fast_socks5::Socks5Command;
|
||||
use percent_encoding::{percent_encode, utf8_percent_encode, NON_ALPHANUMERIC};
|
||||
use percent_encoding::{percent_encode, NON_ALPHANUMERIC};
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tokio::net::TcpStream;
|
||||
use tokio_io_timeout::TimeoutStream;
|
||||
use url::Url;
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::constants::NON_ALPHANUMERIC_WITHOUT_DOT;
|
||||
use crate::context::Context;
|
||||
use crate::net::connect_tcp;
|
||||
use crate::net::session::SessionStream;
|
||||
@@ -42,12 +41,6 @@ impl PartialEq for ShadowsocksConfig {
|
||||
|
||||
impl Eq for ShadowsocksConfig {}
|
||||
|
||||
impl ShadowsocksConfig {
|
||||
fn to_url(&self) -> String {
|
||||
self.server_config.to_url()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct HttpConfig {
|
||||
/// HTTP proxy host.
|
||||
@@ -91,17 +84,6 @@ impl HttpConfig {
|
||||
};
|
||||
Ok(http_config)
|
||||
}
|
||||
|
||||
fn to_url(&self, scheme: &str) -> String {
|
||||
let host = utf8_percent_encode(&self.host, NON_ALPHANUMERIC_WITHOUT_DOT);
|
||||
if let Some((user, password)) = &self.user_password {
|
||||
let user = utf8_percent_encode(user, NON_ALPHANUMERIC);
|
||||
let password = utf8_percent_encode(password, NON_ALPHANUMERIC);
|
||||
format!("{scheme}://{user}:{password}@{host}:{}", self.port)
|
||||
} else {
|
||||
format!("{scheme}://{host}:{}", self.port)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
@@ -141,17 +123,6 @@ impl Socks5Config {
|
||||
|
||||
Ok(socks_stream)
|
||||
}
|
||||
|
||||
fn to_url(&self) -> String {
|
||||
let host = utf8_percent_encode(&self.host, NON_ALPHANUMERIC_WITHOUT_DOT);
|
||||
if let Some((user, password)) = &self.user_password {
|
||||
let user = utf8_percent_encode(user, NON_ALPHANUMERIC);
|
||||
let password = utf8_percent_encode(password, NON_ALPHANUMERIC);
|
||||
format!("socks5://{user}:{password}@{host}:{}", self.port)
|
||||
} else {
|
||||
format!("socks5://{host}:{}", self.port)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
@@ -246,7 +217,7 @@ where
|
||||
|
||||
impl ProxyConfig {
|
||||
/// Creates a new proxy configuration by parsing given proxy URL.
|
||||
pub(crate) fn from_url(url: &str) -> Result<Self> {
|
||||
fn from_url(url: &str) -> Result<Self> {
|
||||
let url = Url::parse(url).context("Cannot parse proxy URL")?;
|
||||
match url.scheme() {
|
||||
"http" => {
|
||||
@@ -301,19 +272,6 @@ impl ProxyConfig {
|
||||
}
|
||||
}
|
||||
|
||||
/// Serializes proxy config into an URL.
|
||||
///
|
||||
/// This function can be used to normalize proxy URL
|
||||
/// by parsing it and serializing back.
|
||||
pub(crate) fn to_url(&self) -> String {
|
||||
match self {
|
||||
Self::Http(http_config) => http_config.to_url("http"),
|
||||
Self::Https(http_config) => http_config.to_url("https"),
|
||||
Self::Socks5(socks5_config) => socks5_config.to_url(),
|
||||
Self::Shadowsocks(shadowsocks_config) => shadowsocks_config.to_url(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Migrates legacy `socks5_host`, `socks5_port`, `socks5_user` and `socks5_password`
|
||||
/// config into `proxy_url` if `proxy_url` is unset or empty.
|
||||
///
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
//! (scoped per WebXDC app instance/message-id). The other peers can then join the gossip with `joinRealtimeChannel().setListener()`
|
||||
//! and `joinRealtimeChannel().send()` just like the other peers.
|
||||
|
||||
use anyhow::{anyhow, bail, Context as _, Result};
|
||||
use anyhow::{anyhow, Context as _, Result};
|
||||
use email::Header;
|
||||
use futures_lite::StreamExt;
|
||||
use iroh_gossip::net::{Event, Gossip, GossipEvent, JoinOptions, GOSSIP_ALPN};
|
||||
@@ -45,7 +45,7 @@ use crate::context::Context;
|
||||
use crate::headerdef::HeaderDef;
|
||||
use crate::message::{Message, MsgId, Viewtype};
|
||||
use crate::mimeparser::SystemMessage;
|
||||
use crate::EventType;
|
||||
use crate::{spawn_named_task, EventType};
|
||||
|
||||
/// The length of an ed25519 `PublicKey`, in bytes.
|
||||
const PUBLIC_KEY_LENGTH: usize = 32;
|
||||
@@ -125,7 +125,7 @@ impl Iroh {
|
||||
.split();
|
||||
|
||||
let ctx = ctx.clone();
|
||||
let subscribe_loop = tokio::spawn(async move {
|
||||
let subscribe_loop = spawn_named_task!("subscribe_loop", async move {
|
||||
if let Err(e) = subscribe_loop(&ctx, gossip_receiver, topic, msg_id, join_tx).await {
|
||||
warn!(ctx, "subscribe_loop failed: {e}")
|
||||
}
|
||||
@@ -143,10 +143,9 @@ impl Iroh {
|
||||
self.endpoint.add_node_addr(peer.clone())?;
|
||||
}
|
||||
|
||||
self.gossip.join_with_opts(
|
||||
topic,
|
||||
JoinOptions::with_bootstrap(peers.into_iter().map(|peer| peer.node_id)),
|
||||
);
|
||||
self.gossip
|
||||
.join(topic, peers.into_iter().map(|peer| peer.node_id).collect())
|
||||
.await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -233,7 +232,6 @@ impl ChannelState {
|
||||
impl Context {
|
||||
/// Create iroh endpoint and gossip.
|
||||
async fn init_peer_channels(&self) -> Result<Iroh> {
|
||||
info!(self, "Initializing peer channels.");
|
||||
let secret_key = SecretKey::generate();
|
||||
let public_key = secret_key.public();
|
||||
|
||||
@@ -260,20 +258,16 @@ impl Context {
|
||||
|
||||
// create gossip
|
||||
let my_addr = endpoint.node_addr().await?;
|
||||
let gossip_config = iroh_gossip::proto::topic::Config {
|
||||
// Allow messages up to 128 KB in size.
|
||||
// We set the limit to 128 KiB to account for internal overhead,
|
||||
// but only guarantee 128 KB of payload to WebXDC developers.
|
||||
max_message_size: 128 * 1024,
|
||||
..Default::default()
|
||||
};
|
||||
let gossip = Gossip::from_endpoint(endpoint.clone(), gossip_config, &my_addr.info);
|
||||
let gossip = Gossip::from_endpoint(endpoint.clone(), Default::default(), &my_addr.info);
|
||||
|
||||
// spawn endpoint loop that forwards incoming connections to the gossiper
|
||||
let context = self.clone();
|
||||
|
||||
// Shuts down on deltachat shutdown
|
||||
tokio::spawn(endpoint_loop(context, endpoint.clone(), gossip.clone()));
|
||||
spawn_named_task!(
|
||||
"endpoint_loop",
|
||||
endpoint_loop(context, endpoint.clone(), gossip.clone())
|
||||
);
|
||||
|
||||
Ok(Iroh {
|
||||
endpoint,
|
||||
@@ -286,10 +280,6 @@ impl Context {
|
||||
|
||||
/// Get or initialize the iroh peer channel.
|
||||
pub async fn get_or_try_init_peer_channel(&self) -> Result<&Iroh> {
|
||||
if !self.get_config_bool(Config::WebxdcRealtimeEnabled).await? {
|
||||
bail!("Attempt to get Iroh when realtime is disabled");
|
||||
}
|
||||
|
||||
let ctx = self.clone();
|
||||
self.iroh
|
||||
.get_or_try_init(|| async { ctx.init_peer_channels().await })
|
||||
@@ -427,15 +417,15 @@ pub async fn leave_webxdc_realtime(ctx: &Context, msg_id: MsgId) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Creates a new random gossip topic.
|
||||
fn create_random_topic() -> TopicId {
|
||||
pub(crate) fn create_random_topic() -> TopicId {
|
||||
TopicId::from_bytes(rand::random())
|
||||
}
|
||||
|
||||
/// Creates `Iroh-Gossip-Header` with a new random topic
|
||||
/// and stores the topic for the message.
|
||||
pub(crate) async fn create_iroh_header(ctx: &Context, msg_id: MsgId) -> Result<Header> {
|
||||
let topic = create_random_topic();
|
||||
pub(crate) async fn create_iroh_header(
|
||||
ctx: &Context,
|
||||
topic: TopicId,
|
||||
msg_id: MsgId,
|
||||
) -> Result<Header> {
|
||||
insert_topic_stub(ctx, msg_id, topic).await?;
|
||||
Ok(Header::new(
|
||||
HeaderDef::IrohGossipTopic.get_headername().to_string(),
|
||||
@@ -455,7 +445,7 @@ async fn endpoint_loop(context: Context, endpoint: Endpoint, gossip: Gossip) {
|
||||
info!(context, "IROH_REALTIME: accepting iroh connection");
|
||||
let gossip = gossip.clone();
|
||||
let context = context.clone();
|
||||
tokio::spawn(async move {
|
||||
spawn_named_task!("handle_connection", async move {
|
||||
if let Err(err) = handle_connection(&context, conn, gossip).await {
|
||||
warn!(context, "IROH_REALTIME: iroh connection error: {err}");
|
||||
}
|
||||
@@ -962,10 +952,6 @@ mod tests {
|
||||
// creates iroh endpoint as side effect
|
||||
leave_webxdc_realtime(alice, MsgId::new(1)).await.unwrap();
|
||||
|
||||
assert!(alice.ctx.iroh.get().is_none());
|
||||
|
||||
// This internal function should return error
|
||||
// if accidentally called with the setting disabled.
|
||||
assert!(alice.ctx.get_or_try_init_peer_channel().await.is_err());
|
||||
assert!(alice.ctx.iroh.get().is_none())
|
||||
}
|
||||
}
|
||||
|
||||
47
src/pgp.rs
47
src/pgp.rs
@@ -16,10 +16,10 @@ use pgp::crypto::hash::HashAlgorithm;
|
||||
use pgp::crypto::sym::SymmetricKeyAlgorithm;
|
||||
use pgp::types::{CompressionAlgorithm, KeyTrait, Mpi, PublicKeyTrait, StringToKey};
|
||||
use rand::{thread_rng, CryptoRng, Rng};
|
||||
use tokio::runtime::Handle;
|
||||
|
||||
use crate::constants::KeyGenType;
|
||||
use crate::key::{DcKey, Fingerprint};
|
||||
use crate::spawn_named_blocking_task;
|
||||
|
||||
#[allow(missing_docs)]
|
||||
#[cfg(test)]
|
||||
@@ -250,33 +250,32 @@ pub async fn pk_encrypt(
|
||||
) -> Result<String> {
|
||||
let lit_msg = Message::new_literal_bytes("", plain);
|
||||
|
||||
Handle::current()
|
||||
.spawn_blocking(move || {
|
||||
let pkeys: Vec<SignedPublicKeyOrSubkey> = public_keys_for_encryption
|
||||
.iter()
|
||||
.filter_map(select_pk_for_encryption)
|
||||
.collect();
|
||||
let pkeys_refs: Vec<&SignedPublicKeyOrSubkey> = pkeys.iter().collect();
|
||||
spawn_named_blocking_task!("pk_encrypt", move || {
|
||||
let pkeys: Vec<SignedPublicKeyOrSubkey> = public_keys_for_encryption
|
||||
.iter()
|
||||
.filter_map(select_pk_for_encryption)
|
||||
.collect();
|
||||
let pkeys_refs: Vec<&SignedPublicKeyOrSubkey> = pkeys.iter().collect();
|
||||
|
||||
let mut rng = thread_rng();
|
||||
let mut rng = thread_rng();
|
||||
|
||||
let encrypted_msg = if let Some(ref skey) = private_key_for_signing {
|
||||
let signed_msg = lit_msg.sign(skey, || "".into(), HASH_ALGORITHM)?;
|
||||
let compressed_msg = if compress {
|
||||
signed_msg.compress(CompressionAlgorithm::ZLIB)?
|
||||
} else {
|
||||
signed_msg
|
||||
};
|
||||
compressed_msg.encrypt_to_keys(&mut rng, SYMMETRIC_KEY_ALGORITHM, &pkeys_refs)?
|
||||
let encrypted_msg = if let Some(ref skey) = private_key_for_signing {
|
||||
let signed_msg = lit_msg.sign(skey, || "".into(), HASH_ALGORITHM)?;
|
||||
let compressed_msg = if compress {
|
||||
signed_msg.compress(CompressionAlgorithm::ZLIB)?
|
||||
} else {
|
||||
lit_msg.encrypt_to_keys(&mut rng, SYMMETRIC_KEY_ALGORITHM, &pkeys_refs)?
|
||||
signed_msg
|
||||
};
|
||||
compressed_msg.encrypt_to_keys(&mut rng, SYMMETRIC_KEY_ALGORITHM, &pkeys_refs)?
|
||||
} else {
|
||||
lit_msg.encrypt_to_keys(&mut rng, SYMMETRIC_KEY_ALGORITHM, &pkeys_refs)?
|
||||
};
|
||||
|
||||
let encoded_msg = encrypted_msg.to_armored_string(Default::default())?;
|
||||
let encoded_msg = encrypted_msg.to_armored_string(Default::default())?;
|
||||
|
||||
Ok(encoded_msg)
|
||||
})
|
||||
.await?
|
||||
Ok(encoded_msg)
|
||||
})
|
||||
.await?
|
||||
}
|
||||
|
||||
/// Signs `plain` text using `private_key_for_signing`.
|
||||
@@ -367,7 +366,7 @@ pub async fn symm_encrypt(passphrase: &str, plain: &[u8]) -> Result<String> {
|
||||
let lit_msg = Message::new_literal_bytes("", plain);
|
||||
let passphrase = passphrase.to_string();
|
||||
|
||||
tokio::task::spawn_blocking(move || {
|
||||
spawn_named_blocking_task!("symm_encrypt", move || {
|
||||
let mut rng = thread_rng();
|
||||
let s2k = StringToKey::new_default(&mut rng);
|
||||
let msg =
|
||||
@@ -388,7 +387,7 @@ pub async fn symm_decrypt<T: std::io::Read + std::io::Seek>(
|
||||
let (enc_msg, _) = Message::from_armor_single(ctext)?;
|
||||
|
||||
let passphrase = passphrase.to_string();
|
||||
tokio::task::spawn_blocking(move || {
|
||||
spawn_named_blocking_task!("symm_decrypt", move || {
|
||||
let msg = enc_msg.decrypt_with_password(|| passphrase)?;
|
||||
|
||||
match msg.get_content()? {
|
||||
|
||||
17
src/qr.rs
17
src/qr.rs
@@ -20,7 +20,7 @@ use crate::events::EventType;
|
||||
use crate::key::Fingerprint;
|
||||
use crate::message::Message;
|
||||
use crate::net::http::post_empty;
|
||||
use crate::net::proxy::{ProxyConfig, DEFAULT_SOCKS_PORT};
|
||||
use crate::net::proxy::DEFAULT_SOCKS_PORT;
|
||||
use crate::peerstate::Peerstate;
|
||||
use crate::token;
|
||||
use crate::tools::validate_id;
|
||||
@@ -723,10 +723,6 @@ pub async fn set_config_from_qr(context: &Context, qr: &str) -> Result<()> {
|
||||
.get_config(Config::ProxyUrl)
|
||||
.await?
|
||||
.unwrap_or_default();
|
||||
|
||||
// Normalize the URL.
|
||||
let url = ProxyConfig::from_url(&url)?.to_url();
|
||||
|
||||
let proxy_urls: Vec<&str> = std::iter::once(url.as_str())
|
||||
.chain(
|
||||
old_proxy_url_value
|
||||
@@ -1791,17 +1787,6 @@ mod tests {
|
||||
)
|
||||
);
|
||||
|
||||
// SOCKS5 config does not have port 1080 explicitly specified,
|
||||
// but should bring `socks5://1.2.3.4:1080` to the top instead of creating another entry.
|
||||
set_config_from_qr(&t, "socks5://1.2.3.4").await?;
|
||||
assert_eq!(
|
||||
t.get_config(Config::ProxyUrl).await?,
|
||||
Some(
|
||||
"socks5://1.2.3.4:1080\nss://YWVzLTEyOC1nY206dGVzdA@192.168.100.1:8888#Example1\nsocks5://foo:666\nsocks5://Da:x%26%25%24X@jau:1080"
|
||||
.to_string()
|
||||
)
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -1442,59 +1442,27 @@ async fn add_parts(
|
||||
}
|
||||
|
||||
if let Some(node_addr) = mime_parser.get_header(HeaderDef::IrohNodeAddr) {
|
||||
chat_id = DC_CHAT_ID_TRASH;
|
||||
match serde_json::from_str::<NodeAddr>(node_addr).context("Failed to parse node address") {
|
||||
Ok(node_addr) => {
|
||||
info!(context, "Adding iroh peer with address {node_addr:?}.");
|
||||
match mime_parser.get_header(HeaderDef::InReplyTo) {
|
||||
Some(in_reply_to) => match rfc724_mid_exists(context, in_reply_to).await? {
|
||||
Some((instance_id, _ts_sent)) => {
|
||||
context.emit_event(EventType::WebxdcRealtimeAdvertisementReceived {
|
||||
msg_id: instance_id,
|
||||
});
|
||||
if let Some(topic) =
|
||||
get_iroh_topic_for_msg(context, instance_id).await?
|
||||
{
|
||||
let node_id = node_addr.node_id;
|
||||
let relay_server =
|
||||
node_addr.relay_url().map(|relay| relay.as_str());
|
||||
iroh_add_peer_for_topic(
|
||||
context,
|
||||
instance_id,
|
||||
topic,
|
||||
node_id,
|
||||
relay_server,
|
||||
)
|
||||
.await?;
|
||||
if context
|
||||
.get_config_bool(Config::WebxdcRealtimeEnabled)
|
||||
.await?
|
||||
{
|
||||
let iroh = context.get_or_try_init_peer_channel().await?;
|
||||
iroh.maybe_add_gossip_peers(topic, vec![node_addr]).await?;
|
||||
}
|
||||
info!(context, "Added iroh peer to the topic of {instance_id}.");
|
||||
} else {
|
||||
warn!(
|
||||
context,
|
||||
"Could not add iroh peer because {instance_id} has no topic."
|
||||
);
|
||||
}
|
||||
}
|
||||
None => {
|
||||
warn!(
|
||||
context,
|
||||
"Cannot add iroh peer because WebXDC instance does not exist."
|
||||
);
|
||||
}
|
||||
},
|
||||
None => {
|
||||
warn!(
|
||||
context,
|
||||
"Cannot add iroh peer because the message has no In-Reply-To."
|
||||
);
|
||||
}
|
||||
let instance_id = parent.context("Failed to get parent message")?.id;
|
||||
context.emit_event(EventType::WebxdcRealtimeAdvertisementReceived {
|
||||
msg_id: instance_id,
|
||||
});
|
||||
if let Some(topic) = get_iroh_topic_for_msg(context, instance_id).await? {
|
||||
let node_id = node_addr.node_id;
|
||||
let relay_server = node_addr.relay_url().map(|relay| relay.as_str());
|
||||
iroh_add_peer_for_topic(context, instance_id, topic, node_id, relay_server)
|
||||
.await?;
|
||||
let iroh = context.get_or_try_init_peer_channel().await?;
|
||||
iroh.maybe_add_gossip_peers(topic, vec![node_addr]).await?;
|
||||
} else {
|
||||
warn!(
|
||||
context,
|
||||
"Could not add iroh peer because {instance_id} has no topic"
|
||||
);
|
||||
}
|
||||
chat_id = DC_CHAT_ID_TRASH;
|
||||
}
|
||||
Err(err) => {
|
||||
warn!(context, "Couldn't parse NodeAddr: {err:#}.");
|
||||
|
||||
@@ -19,12 +19,12 @@ use crate::download::{download_msg, DownloadState};
|
||||
use crate::ephemeral::{self, delete_expired_imap_messages};
|
||||
use crate::events::EventType;
|
||||
use crate::imap::{session::Session, FolderMeaning, Imap};
|
||||
use crate::location;
|
||||
use crate::log::LogExt;
|
||||
use crate::message::MsgId;
|
||||
use crate::smtp::{send_smtp_messages, Smtp};
|
||||
use crate::sql;
|
||||
use crate::tools::{self, duration_to_str, maybe_add_time_based_warnings, time, time_elapsed};
|
||||
use crate::{location, spawn_named_task};
|
||||
|
||||
pub(crate) mod connectivity;
|
||||
|
||||
@@ -164,7 +164,7 @@ impl SchedulerState {
|
||||
}
|
||||
|
||||
let (tx, rx) = oneshot::channel();
|
||||
tokio::spawn(async move {
|
||||
spawn_named_task!("pause", async move {
|
||||
rx.await.ok();
|
||||
let mut inner = context.scheduler.inner.write().await;
|
||||
match *inner {
|
||||
@@ -849,7 +849,10 @@ impl Scheduler {
|
||||
let (inbox_start_send, inbox_start_recv) = oneshot::channel();
|
||||
let handle = {
|
||||
let ctx = ctx.clone();
|
||||
task::spawn(inbox_loop(ctx, inbox_start_send, inbox_handlers))
|
||||
spawn_named_task!(
|
||||
"inbox_loop",
|
||||
inbox_loop(ctx, inbox_start_send, inbox_handlers)
|
||||
)
|
||||
};
|
||||
let inbox = SchedBox {
|
||||
meaning: FolderMeaning::Inbox,
|
||||
@@ -866,7 +869,10 @@ impl Scheduler {
|
||||
let (conn_state, handlers) = ImapConnectionState::new(ctx).await?;
|
||||
let (start_send, start_recv) = oneshot::channel();
|
||||
let ctx = ctx.clone();
|
||||
let handle = task::spawn(simple_imap_loop(ctx, start_send, handlers, meaning));
|
||||
let handle = spawn_named_task!(
|
||||
"simple_imap_loop",
|
||||
simple_imap_loop(ctx, start_send, handlers, meaning)
|
||||
);
|
||||
oboxes.push(SchedBox {
|
||||
meaning,
|
||||
conn_state,
|
||||
@@ -878,20 +884,20 @@ impl Scheduler {
|
||||
|
||||
let smtp_handle = {
|
||||
let ctx = ctx.clone();
|
||||
task::spawn(smtp_loop(ctx, smtp_start_send, smtp_handlers))
|
||||
spawn_named_task!("smtp_loop", smtp_loop(ctx, smtp_start_send, smtp_handlers))
|
||||
};
|
||||
start_recvs.push(smtp_start_recv);
|
||||
|
||||
let ephemeral_handle = {
|
||||
let ctx = ctx.clone();
|
||||
task::spawn(async move {
|
||||
spawn_named_task!("ephemeral_loop", async move {
|
||||
ephemeral::ephemeral_loop(&ctx, ephemeral_interrupt_recv).await;
|
||||
})
|
||||
};
|
||||
|
||||
let location_handle = {
|
||||
let ctx = ctx.clone();
|
||||
task::spawn(async move {
|
||||
spawn_named_task!("location_loop", async move {
|
||||
location::location_loop(&ctx, location_interrupt_recv).await;
|
||||
})
|
||||
};
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
//! Implementation of [SecureJoin protocols](https://securejoin.delta.chat/).
|
||||
|
||||
use anyhow::{ensure, Context as _, Error, Result};
|
||||
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
|
||||
use percent_encoding::{utf8_percent_encode, AsciiSet, NON_ALPHANUMERIC};
|
||||
|
||||
use crate::aheader::EncryptPreference;
|
||||
use crate::chat::{self, get_chat_id_by_grpid, Chat, ChatId, ChatIdBlocked, ProtectionStatus};
|
||||
use crate::chatlist_events;
|
||||
use crate::config::Config;
|
||||
use crate::constants::{Blocked, Chattype, NON_ALPHANUMERIC_WITHOUT_DOT};
|
||||
use crate::constants::{Blocked, Chattype};
|
||||
use crate::contact::{Contact, ContactId, Origin};
|
||||
use crate::context::Context;
|
||||
use crate::e2ee::ensure_secret_key_exists;
|
||||
@@ -34,6 +34,9 @@ use qrinvite::QrInvite;
|
||||
|
||||
use crate::token::Namespace;
|
||||
|
||||
/// Set of characters to percent-encode in email addresses and names.
|
||||
pub const NON_ALPHANUMERIC_WITHOUT_DOT: &AsciiSet = &NON_ALPHANUMERIC.remove(b'.');
|
||||
|
||||
fn inviter_progress(context: &Context, contact_id: ContactId, progress: usize) {
|
||||
debug_assert!(
|
||||
progress <= 1000,
|
||||
|
||||
@@ -6,7 +6,6 @@ pub mod send;
|
||||
use anyhow::{bail, format_err, Context as _, Error, Result};
|
||||
use async_smtp::response::{Category, Code, Detail};
|
||||
use async_smtp::{EmailAddress, SmtpTransport};
|
||||
use tokio::task;
|
||||
|
||||
use crate::chat::{add_info_msg_with_cmd, ChatId};
|
||||
use crate::config::Config;
|
||||
@@ -21,9 +20,9 @@ use crate::mimefactory::MimeFactory;
|
||||
use crate::net::proxy::ProxyConfig;
|
||||
use crate::net::session::SessionBufStream;
|
||||
use crate::scheduler::connectivity::ConnectivityStore;
|
||||
use crate::sql;
|
||||
use crate::stock_str::unencrypted_email;
|
||||
use crate::tools::{self, time_elapsed};
|
||||
use crate::{spawn_named_task, sql};
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct Smtp {
|
||||
@@ -56,7 +55,7 @@ impl Smtp {
|
||||
// Closing connection with a QUIT command may take some time, especially if it's a
|
||||
// stale connection and an attempt to send the command times out. Send a command in a
|
||||
// separate task to avoid waiting for reply or timeout.
|
||||
task::spawn(async move { transport.quit().await });
|
||||
spawn_named_task!("disconnect SMTP", async move { transport.quit().await });
|
||||
}
|
||||
self.last_success = None;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ use crate::peerstate::Peerstate;
|
||||
use crate::pgp::KeyPair;
|
||||
use crate::receive_imf::receive_imf;
|
||||
use crate::securejoin::{get_securejoin_qr, join_securejoin};
|
||||
use crate::spawn_named_task;
|
||||
use crate::stock_str::StockStrings;
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
@@ -969,7 +970,7 @@ impl InnerLogSink {
|
||||
/// Subscribes this log sink to event emitter.
|
||||
pub fn subscribe(&self, event_emitter: EventEmitter) {
|
||||
let sender = self.sender.clone();
|
||||
task::spawn(async move {
|
||||
spawn_named_task!("InnerLogSink", async move {
|
||||
while let Some(event) = event_emitter.recv().await {
|
||||
sender.try_send(LogEvent::Event(event.clone())).ok();
|
||||
}
|
||||
|
||||
126
src/tools.rs
126
src/tools.rs
@@ -708,6 +708,132 @@ pub(crate) fn inc_and_check<T: PrimInt + AddAssign + std::fmt::Debug>(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Spawns a named asynchronous task if the `tokio_unstable` feature is enabled.
|
||||
///
|
||||
/// Spawns a new asynchronous task, returning a [tokio::task::JoinHandle] for it.
|
||||
/// The provided future will start running in the background immediately when the function is called, even if you don't await the returned JoinHandle.
|
||||
/// See [tokio::task::spawn].
|
||||
///
|
||||
/// If the rustflag `tokio_unstable` is active, the task will be given the specified `name`
|
||||
/// for easier identification in monitoring tools (like tokio-console).
|
||||
/// If `tokio_unstable` is not set, the task is spawned normally without a name.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// - `name`: The name of the task.
|
||||
/// - `future`: The future to be executed, which must implement `Future`, be `Send`, and `'static`.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A [tokio::task::JoinHandle] that can be awaited to retrieve the output of the future.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the task fails to spawn when `tokio_unstable` is enabled.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use deltachat::spawn_named_task; // or inside of core: crate::spawn_named_task
|
||||
///
|
||||
/// let handle = spawn_named_task!("my_task", async {
|
||||
/// // Your async code here
|
||||
/// });
|
||||
///
|
||||
/// let result = handle.await.unwrap();
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! spawn_named_task {
|
||||
($name:expr, $future:expr) => {{
|
||||
#[inline(always)]
|
||||
#[allow(unused_variables, unexpected_cfgs)]
|
||||
pub fn __spawn_named_task<Fut>(
|
||||
name: &str,
|
||||
future: Fut,
|
||||
) -> ::tokio::task::JoinHandle<Fut::Output>
|
||||
where
|
||||
Fut: ::std::future::Future + Send + 'static,
|
||||
Fut::Output: Send + 'static,
|
||||
{
|
||||
#[cfg(tokio_unstable)]
|
||||
{
|
||||
::tokio::task::Builder::new()
|
||||
.name(name)
|
||||
.spawn(future)
|
||||
.expect("Failed to spawn task")
|
||||
}
|
||||
#[cfg(not(tokio_unstable))]
|
||||
{
|
||||
::tokio::task::spawn(future)
|
||||
}
|
||||
}
|
||||
__spawn_named_task($name, $future)
|
||||
}};
|
||||
}
|
||||
|
||||
/// Spawns a named blocking task if the `tokio_unstable` feature is enabled.
|
||||
///
|
||||
/// Spawns a new blocking task, returning a [tokio::task::JoinHandle] for it.
|
||||
/// The provided future will start running in the background immediately when the function is called, even if you don't await the returned JoinHandle.
|
||||
/// See [tokio::task::spawn_blocking].
|
||||
///
|
||||
/// If the rustflag `tokio_unstable` is active, the task will be given the specified `name`
|
||||
/// for easier identification in monitoring tools (like tokio-console).
|
||||
/// If `tokio_unstable` is not set, the task is spawned normally without a name.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// - `name`: The name of the task
|
||||
/// - `future`: The future to be executed, which must implement `Future`, be `Send`, and `'static`.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// A [tokio::task::JoinHandle] that can be awaited to retrieve the output of the future.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the task fails to spawn when `tokio_unstable` is enabled.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use deltachat::spawn_named_blocking_task; // or inside of core: crate::spawn_named_blocking_task
|
||||
///
|
||||
/// let handle = spawn_named_blocking_task!("my_task", async {
|
||||
/// // Your async code here
|
||||
/// });
|
||||
///
|
||||
/// let result = handle.await.unwrap();
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! spawn_named_blocking_task {
|
||||
($name:expr, $future:expr) => {{
|
||||
#[inline(always)]
|
||||
#[allow(unused_variables, unexpected_cfgs)]
|
||||
pub fn __spawn_named_blocking_task<Fut, ReturnType>(
|
||||
name: &str,
|
||||
future: Fut,
|
||||
) -> ::tokio::task::JoinHandle<ReturnType>
|
||||
where
|
||||
Fut: FnOnce() -> ReturnType + Send + 'static,
|
||||
ReturnType: Send + 'static,
|
||||
{
|
||||
#[cfg(tokio_unstable)]
|
||||
{
|
||||
::tokio::task::Builder::new()
|
||||
.name(name)
|
||||
.spawn_blocking(future)
|
||||
.expect("Failed to spawn task")
|
||||
}
|
||||
#[cfg(not(tokio_unstable))]
|
||||
{
|
||||
::tokio::task::spawn_blocking(future)
|
||||
}
|
||||
}
|
||||
__spawn_named_blocking_task($name, $future)
|
||||
}};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#![allow(clippy::indexing_slicing)]
|
||||
|
||||
Reference in New Issue
Block a user