From 2e6f98f4e4def7fce7823aea2551c002b4f6d859 Mon Sep 17 00:00:00 2001 From: link2xt Date: Tue, 9 May 2023 19:10:58 +0000 Subject: [PATCH] api: add dc_jsonrpc_blocking_call() --- Cargo.lock | 5 +++-- deltachat-ffi/Cargo.toml | 1 + deltachat-ffi/deltachat.h | 12 ++++++++++++ deltachat-ffi/src/lib.rs | 27 ++++++++++++++++++++++++++- deltachat-jsonrpc/Cargo.toml | 2 +- python/tests/test_4_lowlevel.py | 17 +++++++++++++++++ 6 files changed, 60 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7545582b6..b3a006e0d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1295,6 +1295,7 @@ dependencies = [ "serde_json", "thiserror", "tokio", + "yerpc", ] [[package]] @@ -5754,9 +5755,9 @@ dependencies = [ [[package]] name = "yerpc" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6a0257f42e6bdc187f37074723b6094da3502cee21ae517b3c54d2c37d506e7" +checksum = "b2c26a804eaa30c1ff1a296dc6dd1a7d7c622750dafcd0d6b2ed5e3c5c3beb22" dependencies = [ "anyhow", "async-channel", diff --git a/deltachat-ffi/Cargo.toml b/deltachat-ffi/Cargo.toml index 39faa6cc3..5ccf92bcb 100644 --- a/deltachat-ffi/Cargo.toml +++ b/deltachat-ffi/Cargo.toml @@ -25,6 +25,7 @@ anyhow = "1" thiserror = "1" rand = "0.8" once_cell = "1.17.0" +yerpc = { version = "0.4.4", features = ["anyhow_expose"] } [features] default = ["vendored"] diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index 419282037..af8cac124 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -5720,6 +5720,18 @@ void dc_jsonrpc_request(dc_jsonrpc_instance_t* jsonrpc_instance, const char* req */ char* dc_jsonrpc_next_response(dc_jsonrpc_instance_t* jsonrpc_instance); +/** + * Make a JSON-RPC call and return a response. + * + * @memberof dc_jsonrpc_instance_t + * @param jsonrpc_instance jsonrpc instance as returned from dc_jsonrpc_init(). + * @param method JSON-RPC method name, e.g. `check_email_validity`. + * @param params JSON-RPC method parameters, e.g. `["alice@example.org"]`. + * @return JSON-RPC response as string, must be freed using dc_str_unref() after usage. + * On error, NULL is returned. + */ +char* dc_jsonrpc_blocking_call(dc_jsonrpc_instance_t* jsonrpc_instance, const char *method, const char *params); + /** * @class dc_event_emitter_t * diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index ebbe0d119..320f5c23f 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -4967,7 +4967,7 @@ pub unsafe extern "C" fn dc_accounts_get_event_emitter( #[cfg(feature = "jsonrpc")] mod jsonrpc { use deltachat_jsonrpc::api::CommandApi; - use deltachat_jsonrpc::yerpc::{OutReceiver, RpcClient, RpcSession}; + use deltachat_jsonrpc::yerpc::{OutReceiver, RpcClient, RpcServer, RpcSession}; use super::*; @@ -5039,4 +5039,29 @@ mod jsonrpc { .map(|result| serde_json::to_string(&result).unwrap_or_default().strdup()) .unwrap_or(ptr::null_mut()) } + + #[no_mangle] + pub unsafe extern "C" fn dc_jsonrpc_blocking_call( + jsonrpc_instance: *mut dc_jsonrpc_instance_t, + method: *const libc::c_char, + params: *const libc::c_char, + ) -> *mut libc::c_char { + if jsonrpc_instance.is_null() { + eprintln!("ignoring careless call to dc_jsonrpc_blocking_call()"); + return ptr::null_mut(); + } + let api = &*jsonrpc_instance; + let method = to_string_lossy(method); + let params = to_string_lossy(params); + let params: Option = match serde_json::from_str(¶ms) { + Ok(params) => Some(params), + Err(_) => None, + }; + let params = params.map(yerpc::Params::into_value).unwrap_or_default(); + let res = block_on(api.handle.server().handle_request(method, params)); + match res { + Ok(res) => res.to_string().strdup(), + Err(_) => ptr::null_mut(), + } + } } diff --git a/deltachat-jsonrpc/Cargo.toml b/deltachat-jsonrpc/Cargo.toml index 918e123a3..767a0ee90 100644 --- a/deltachat-jsonrpc/Cargo.toml +++ b/deltachat-jsonrpc/Cargo.toml @@ -21,7 +21,7 @@ log = "0.4" async-channel = { version = "1.8.0" } futures = { version = "0.3.28" } serde_json = "1.0.96" -yerpc = { version = "0.4.3", features = ["anyhow_expose"] } +yerpc = { version = "0.4.4", features = ["anyhow_expose"] } typescript-type-def = { version = "0.5.5", features = ["json_value"] } tokio = { version = "1.28.0" } sanitize-filename = "0.4" diff --git a/python/tests/test_4_lowlevel.py b/python/tests/test_4_lowlevel.py index 84a751ea4..1c3f15bea 100644 --- a/python/tests/test_4_lowlevel.py +++ b/python/tests/test_4_lowlevel.py @@ -9,6 +9,7 @@ from deltachat.testplugin import ( create_dict_from_files_in_path, write_dict_to_dir, ) +from deltachat.cutil import from_optional_dc_charpointer # from deltachat.account import EventLogger @@ -215,3 +216,19 @@ def test_logged_ac_process_ffi_failure(acfactory): assert "ac_process_ffi_event" in res assert "ZeroDivisionError" in res assert "Traceback" in res + + +def test_jsonrpc_blocking_call(tmpdir): + accounts_fname = tmpdir.join("accounts") + accounts = ffi.gc( + lib.dc_accounts_new(ffi.NULL, accounts_fname.strpath.encode("ascii")), + lib.dc_accounts_unref, + ) + jsonrpc = ffi.gc(lib.dc_jsonrpc_init(accounts), lib.dc_jsonrpc_unref) + res = from_optional_dc_charpointer( + lib.dc_jsonrpc_blocking_call(jsonrpc, b"check_email_validity", b'["alice@example.org"]'), + ) + assert res == "true" + + res = from_optional_dc_charpointer(lib.dc_jsonrpc_blocking_call(jsonrpc, b"check_email_validity", b'["alice"]')) + assert res == "false"