mirror of
https://github.com/chatmail/core.git
synced 2026-04-26 18:06:35 +03:00
add tokio console support to repl tool and create a readme for the repl tool
This commit is contained in:
@@ -7,6 +7,7 @@ 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]
|
||||
|
||||
60
deltachat-repl/README.md
Normal file
60
deltachat-repl/README.md
Normal file
@@ -0,0 +1,60 @@
|
||||
# Delta Chat REPL
|
||||
|
||||
This is a simple [REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop) frontend build on top of delta chat core.
|
||||
It's purpose is to help with quick testing during development, it is not meant for end users.
|
||||
|
||||
Dependencies:
|
||||
- if you want to use `getqr` you need `qrencode` (macOS: `brew install qrencode`)
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
cargo run <path to deltachat db>
|
||||
```
|
||||
|
||||
Type in `help` to learn about what comands are available.
|
||||
|
||||
## Usage with `tokio-console`
|
||||
|
||||
Tokio is the async runtime that delta chat core uses.
|
||||
Core uses tokio tasks, which is something similar to a thread.
|
||||
`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 tokio-console`.
|
||||
|
||||
### Quick 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
|
||||
```
|
||||
|
||||
If it crashes you can just start it again and use the openpgp4fpr url instead of scanning the code from the terminal.
|
||||
Or install `qrencode` to fix the crash and run `getqr` again.
|
||||
|
||||
Use the qrcode/openpgp4fpr link to setup the contact on deltachat.
|
||||
Then write a message to that new contact, after that we 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, 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(),
|
||||
@@ -481,11 +481,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();
|
||||
tracing::subscriber::set_global_default({
|
||||
let subscribers = tracing_subscriber::Registry::default().with(
|
||||
tracing_subscriber::fmt::layer().with_filter(
|
||||
tracing_subscriber::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?;
|
||||
|
||||
124
src/tools.rs
124
src/tools.rs
@@ -708,6 +708,130 @@ 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 spawn 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 (used only if `tokio_unstable` is enabled).
|
||||
/// - `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 tokio::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)]
|
||||
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 spawn 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 (used only if `tokio_unstable` is enabled).
|
||||
/// - `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 tokio::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)]
|
||||
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