mirror of
https://github.com/chatmail/core.git
synced 2026-05-08 17:36:29 +03:00
add json api to cffi and expose it in dc node
This commit is contained in:
@@ -16,6 +16,7 @@ crate-type = ["cdylib", "staticlib"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
deltachat = { path = "../", default-features = false }
|
deltachat = { path = "../", default-features = false }
|
||||||
|
deltachat-jsonrpc = { path = "../deltachat-jsonrpc" }
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
human-panic = "1"
|
human-panic = "1"
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ typedef struct _dc_provider dc_provider_t;
|
|||||||
typedef struct _dc_event dc_event_t;
|
typedef struct _dc_event dc_event_t;
|
||||||
typedef struct _dc_event_emitter dc_event_emitter_t;
|
typedef struct _dc_event_emitter dc_event_emitter_t;
|
||||||
typedef struct _dc_accounts_event_emitter dc_accounts_event_emitter_t;
|
typedef struct _dc_accounts_event_emitter dc_accounts_event_emitter_t;
|
||||||
|
typedef struct _dc_json_api_instance dc_json_api_instance_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @mainpage Getting started
|
* @mainpage Getting started
|
||||||
@@ -5178,6 +5178,55 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class dc_json_api_instance_t
|
||||||
|
*
|
||||||
|
* Opaque object for using the json rpc api from the cffi bindings.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the jsonrpc instance that is used to call the jsonrpc.
|
||||||
|
*
|
||||||
|
* @memberof dc_accounts_t
|
||||||
|
* @param account_manager The accounts object as created by dc_accounts_new().
|
||||||
|
* @return Returns the jsonrpc instance, NULL on errors.
|
||||||
|
* Must be freed using dc_json_api_unref() after usage.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
dc_json_api_instance_t* dc_get_json_api(dc_accounts_t* account_manager);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free a jsonrpc instance.
|
||||||
|
*
|
||||||
|
* @memberof dc_json_api_instance_t
|
||||||
|
* @param json_api_instance jsonrpc instance as returned from dc_get_json_api().
|
||||||
|
* If NULL is given, nothing is done and an error is logged.
|
||||||
|
*/
|
||||||
|
void dc_json_api_unref(dc_json_api_instance_t* json_api_instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes an asynchronous jsonrpc request,
|
||||||
|
* returns immediately and once the result is ready it can be retrieved via dc_get_next_json_response()
|
||||||
|
* the jsonrpc specification defines an invocation id that can then be used to match request and response.
|
||||||
|
*
|
||||||
|
* @memberof dc_json_api_instance_t
|
||||||
|
* @param json_api_instance jsonrpc instance as returned from dc_get_json_api().
|
||||||
|
* @param request JSON-RPC request as string
|
||||||
|
*/
|
||||||
|
void dc_json_request(dc_json_api_instance_t* json_api_instance, char* request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the next json_rpc response, blocks until there is a new event, so call this in a loop from a thread.
|
||||||
|
*
|
||||||
|
* @memberof dc_json_api_instance_t
|
||||||
|
* @param json_api_instance jsonrpc instance as returned from dc_get_json_api().
|
||||||
|
* @return JSON-RPC response as string
|
||||||
|
* If NULL is returned, the accounts_t belonging to the jsonrpc instance is unref'd and no more events will come;
|
||||||
|
* in this case, free the jsonrpc instance using dc_json_api_unref().
|
||||||
|
*/
|
||||||
|
char* dc_get_next_json_response(dc_json_api_instance_t* json_api_instance);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class dc_event_emitter_t
|
* @class dc_event_emitter_t
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ use std::future::Future;
|
|||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
use std::sync::Arc;
|
||||||
use std::time::{Duration, SystemTime};
|
use std::time::{Duration, SystemTime};
|
||||||
|
|
||||||
use anyhow::Context as _;
|
use anyhow::Context as _;
|
||||||
@@ -4108,11 +4109,11 @@ pub unsafe extern "C" fn dc_provider_unref(provider: *mut dc_provider_t) {
|
|||||||
/// Reader-writer lock wrapper for accounts manager to guarantee thread safety when using
|
/// Reader-writer lock wrapper for accounts manager to guarantee thread safety when using
|
||||||
/// `dc_accounts_t` in multiple threads at once.
|
/// `dc_accounts_t` in multiple threads at once.
|
||||||
pub struct AccountsWrapper {
|
pub struct AccountsWrapper {
|
||||||
inner: RwLock<Accounts>,
|
inner: Arc<RwLock<Accounts>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for AccountsWrapper {
|
impl Deref for AccountsWrapper {
|
||||||
type Target = RwLock<Accounts>;
|
type Target = Arc<RwLock<Accounts>>;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.inner
|
&self.inner
|
||||||
@@ -4121,7 +4122,7 @@ impl Deref for AccountsWrapper {
|
|||||||
|
|
||||||
impl AccountsWrapper {
|
impl AccountsWrapper {
|
||||||
fn new(accounts: Accounts) -> Self {
|
fn new(accounts: Accounts) -> Self {
|
||||||
let inner = RwLock::new(accounts);
|
let inner = Arc::new(RwLock::new(accounts));
|
||||||
Self { inner }
|
Self { inner }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4437,3 +4438,73 @@ pub unsafe extern "C" fn dc_accounts_get_next_event(
|
|||||||
.map(|ev| Box::into_raw(Box::new(ev)))
|
.map(|ev| Box::into_raw(Box::new(ev)))
|
||||||
.unwrap_or_else(ptr::null_mut)
|
.unwrap_or_else(ptr::null_mut)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use deltachat_jsonrpc::api::CommandApi;
|
||||||
|
use deltachat_jsonrpc::yerpc::{MessageHandle, RpcHandle};
|
||||||
|
|
||||||
|
pub struct dc_json_api_instance_t {
|
||||||
|
receiver: async_std::channel::Receiver<deltachat_jsonrpc::yerpc::Message>,
|
||||||
|
handle: MessageHandle<CommandApi>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn dc_get_json_api(
|
||||||
|
account_manager: *mut dc_accounts_t,
|
||||||
|
) -> *mut dc_json_api_instance_t {
|
||||||
|
if account_manager.is_null() {
|
||||||
|
eprintln!("ignoring careless call to dc_get_json_api()");
|
||||||
|
return ptr::null_mut();
|
||||||
|
}
|
||||||
|
|
||||||
|
let cmd_api =
|
||||||
|
deltachat_jsonrpc::api::CommandApi::new_from_cffi((*account_manager).inner.clone());
|
||||||
|
|
||||||
|
let (request_handle, receiver) = RpcHandle::new();
|
||||||
|
let handle = MessageHandle::new(request_handle, cmd_api);
|
||||||
|
|
||||||
|
let instance = dc_json_api_instance_t { receiver, handle };
|
||||||
|
|
||||||
|
Box::into_raw(Box::new(instance))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn dc_json_api_unref(json_api_instance: *mut dc_json_api_instance_t) {
|
||||||
|
if json_api_instance.is_null() {
|
||||||
|
eprintln!("ignoring careless call to dc_json_api_unref()");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Box::from_raw(json_api_instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn dc_json_request(
|
||||||
|
json_api_instance: *mut dc_json_api_instance_t,
|
||||||
|
request: *const libc::c_char,
|
||||||
|
) {
|
||||||
|
if json_api_instance.is_null() || request.is_null() {
|
||||||
|
eprintln!("ignoring careless call to dc_json_request()");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let api = &*json_api_instance;
|
||||||
|
let handle = &api.handle;
|
||||||
|
let request = to_string_lossy(request);
|
||||||
|
async_std::task::spawn(async move {
|
||||||
|
handle.handle_message(&request).await;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn dc_get_next_json_response(
|
||||||
|
json_api_instance: *mut dc_json_api_instance_t,
|
||||||
|
) -> *mut libc::c_char {
|
||||||
|
if json_api_instance.is_null() {
|
||||||
|
eprintln!("ignoring careless call to dc_get_next_json_response()");
|
||||||
|
return ptr::null_mut();
|
||||||
|
}
|
||||||
|
let api = &*json_api_instance;
|
||||||
|
async_std::task::block_on(api.receiver.recv())
|
||||||
|
.map(|result| serde_json::to_string(&result).unwrap_or_default().strdup())
|
||||||
|
.unwrap_or(ptr::null_mut())
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "deltachat-jsonrpc"
|
name = "deltachat-jsonrpc"
|
||||||
version = "0.1.0"
|
version = "1.86.0"
|
||||||
authors = ["Delta Chat Developers (ML) <delta@codespeak.net>"]
|
authors = ["Delta Chat Developers (ML) <delta@codespeak.net>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
default-run = "webserver"
|
default-run = "webserver"
|
||||||
|
|||||||
@@ -39,6 +39,10 @@ impl CommandApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_from_cffi(accounts: Arc<RwLock<Accounts>>) -> Self {
|
||||||
|
CommandApi { accounts }
|
||||||
|
}
|
||||||
|
|
||||||
async fn get_context(&self, id: u32) -> Result<deltachat::context::Context> {
|
async fn get_context(&self, id: u32) -> Result<deltachat::context::Context> {
|
||||||
let sc = self
|
let sc = self
|
||||||
.accounts
|
.accounts
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
pub mod api;
|
pub mod api;
|
||||||
pub use api::events;
|
pub use api::events;
|
||||||
|
|
||||||
|
pub use yerpc;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::api::{Accounts, CommandApi};
|
use super::api::{Accounts, CommandApi};
|
||||||
|
|||||||
@@ -19,10 +19,11 @@ interface NativeAccount {}
|
|||||||
export class AccountManager extends EventEmitter {
|
export class AccountManager extends EventEmitter {
|
||||||
dcn_accounts: NativeAccount
|
dcn_accounts: NativeAccount
|
||||||
accountDir: string
|
accountDir: string
|
||||||
|
json_rpc_started = false
|
||||||
|
|
||||||
constructor(cwd: string, os = 'deltachat-node') {
|
constructor(cwd: string, os = 'deltachat-node') {
|
||||||
debug('DeltaChat constructor')
|
|
||||||
super()
|
super()
|
||||||
|
debug('DeltaChat constructor')
|
||||||
|
|
||||||
this.accountDir = cwd
|
this.accountDir = cwd
|
||||||
this.dcn_accounts = binding.dcn_accounts_new(os, this.accountDir)
|
this.dcn_accounts = binding.dcn_accounts_new(os, this.accountDir)
|
||||||
@@ -114,6 +115,31 @@ export class AccountManager extends EventEmitter {
|
|||||||
debug('Started event handler')
|
debug('Started event handler')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
startJSONRPCHandler(callback: ((response: string) => void) | null) {
|
||||||
|
if (this.dcn_accounts === null) {
|
||||||
|
throw new Error('dcn_account is null')
|
||||||
|
}
|
||||||
|
if (!callback) {
|
||||||
|
throw new Error('no callback set')
|
||||||
|
}
|
||||||
|
if (this.json_rpc_started) {
|
||||||
|
throw new Error('jsonrpc was started already')
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.dcn_accounts_start_jsonrpc(this.dcn_accounts, callback.bind(this))
|
||||||
|
debug('Started jsonrpc handler')
|
||||||
|
this.json_rpc_started = true
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonRPCRequest(message: string) {
|
||||||
|
if (!this.json_rpc_started) {
|
||||||
|
throw new Error(
|
||||||
|
'jsonrpc is not active, start it with startJSONRPCHandler first'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
binding.dcn_json_rpc_request(this.dcn_accounts, message)
|
||||||
|
}
|
||||||
|
|
||||||
startIO() {
|
startIO() {
|
||||||
binding.dcn_accounts_start_io(this.dcn_accounts)
|
binding.dcn_accounts_start_io(this.dcn_accounts)
|
||||||
}
|
}
|
||||||
|
|||||||
11
node/segfault.js
Normal file
11
node/segfault.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
const {default:dc} = require("./dist")
|
||||||
|
|
||||||
|
const ac = new dc("testdtrdtrh")
|
||||||
|
|
||||||
|
ac.startJSONRPCHandler(console.log)
|
||||||
|
|
||||||
|
setTimeout(()=>{
|
||||||
|
ac.close() // This segfaults -> TODO Findout why?
|
||||||
|
|
||||||
|
console.log("still living")
|
||||||
|
}, 1000)
|
||||||
@@ -34,6 +34,9 @@ typedef struct dcn_accounts_t {
|
|||||||
dc_accounts_t* dc_accounts;
|
dc_accounts_t* dc_accounts;
|
||||||
napi_threadsafe_function threadsafe_event_handler;
|
napi_threadsafe_function threadsafe_event_handler;
|
||||||
uv_thread_t event_handler_thread;
|
uv_thread_t event_handler_thread;
|
||||||
|
napi_threadsafe_function threadsafe_jsonrpc_handler;
|
||||||
|
uv_thread_t jsonrpc_thread;
|
||||||
|
dc_json_api_instance_t* jsonrpc_instance;
|
||||||
int gc;
|
int gc;
|
||||||
} dcn_accounts_t;
|
} dcn_accounts_t;
|
||||||
|
|
||||||
@@ -2924,6 +2927,10 @@ NAPI_METHOD(dcn_accounts_unref) {
|
|||||||
uv_thread_join(&dcn_accounts->event_handler_thread);
|
uv_thread_join(&dcn_accounts->event_handler_thread);
|
||||||
dcn_accounts->event_handler_thread = 0;
|
dcn_accounts->event_handler_thread = 0;
|
||||||
}
|
}
|
||||||
|
if (dcn_accounts->jsonrpc_instance) {
|
||||||
|
dc_json_api_unref(dcn_accounts->jsonrpc_instance);
|
||||||
|
dcn_accounts->jsonrpc_instance = NULL;
|
||||||
|
}
|
||||||
dc_accounts_unref(dcn_accounts->dc_accounts);
|
dc_accounts_unref(dcn_accounts->dc_accounts);
|
||||||
dcn_accounts->dc_accounts = NULL;
|
dcn_accounts->dc_accounts = NULL;
|
||||||
|
|
||||||
@@ -3082,8 +3089,6 @@ static void accounts_event_handler_thread_func(void* arg)
|
|||||||
{
|
{
|
||||||
dcn_accounts_t* dcn_accounts = (dcn_accounts_t*)arg;
|
dcn_accounts_t* dcn_accounts = (dcn_accounts_t*)arg;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
TRACE("event_handler_thread_func starting");
|
TRACE("event_handler_thread_func starting");
|
||||||
|
|
||||||
dc_accounts_event_emitter_t * dc_accounts_event_emitter = dc_accounts_get_event_emitter(dcn_accounts->dc_accounts);
|
dc_accounts_event_emitter_t * dc_accounts_event_emitter = dc_accounts_get_event_emitter(dcn_accounts->dc_accounts);
|
||||||
@@ -3234,6 +3239,129 @@ NAPI_METHOD(dcn_accounts_start_event_handler) {
|
|||||||
NAPI_RETURN_UNDEFINED();
|
NAPI_RETURN_UNDEFINED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// JSON RPC
|
||||||
|
|
||||||
|
static void accounts_jsonrpc_thread_func(void* arg)
|
||||||
|
{
|
||||||
|
dcn_accounts_t* dcn_accounts = (dcn_accounts_t*)arg;
|
||||||
|
TRACE("accounts_jsonrpc_thread_func starting");
|
||||||
|
char* response;
|
||||||
|
while (true) {
|
||||||
|
if (dcn_accounts->jsonrpc_instance == NULL) {
|
||||||
|
TRACE("jsonrpc is null, bailing");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
response = dc_get_next_json_response(dcn_accounts->jsonrpc_instance);
|
||||||
|
if (response == NULL) {
|
||||||
|
//TRACE("received NULL event, skipping");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dcn_accounts->threadsafe_jsonrpc_handler) {
|
||||||
|
TRACE("threadsafe_jsonrpc_handler not set, bailing");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Don't process events if we're being garbage collected!
|
||||||
|
if (dcn_accounts->gc == 1) {
|
||||||
|
TRACE("dc_accounts has been destroyed, bailing");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
napi_status status = napi_call_threadsafe_function(dcn_accounts->threadsafe_jsonrpc_handler, response, napi_tsfn_blocking);
|
||||||
|
|
||||||
|
if (status == napi_closing) {
|
||||||
|
TRACE("JS function got released, bailing");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dc_json_api_unref(dcn_accounts->jsonrpc_instance);
|
||||||
|
dcn_accounts->jsonrpc_instance = NULL;
|
||||||
|
TRACE("accounts_jsonrpc_thread_func ended");
|
||||||
|
napi_release_threadsafe_function(dcn_accounts->threadsafe_jsonrpc_handler, napi_tsfn_release);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void call_accounts_js_jsonrpc_handler(napi_env env, napi_value js_callback, void* _context, void* data)
|
||||||
|
{
|
||||||
|
char* response = (char*)data;
|
||||||
|
napi_value global;
|
||||||
|
napi_status status = napi_get_global(env, &global);
|
||||||
|
if (status != napi_ok) {
|
||||||
|
napi_throw_error(env, NULL, "Unable to get global");
|
||||||
|
}
|
||||||
|
|
||||||
|
napi_value argv[1];
|
||||||
|
if (response != 0) {
|
||||||
|
status = napi_create_string_utf8(env, response, NAPI_AUTO_LENGTH, &argv[0]);
|
||||||
|
} else {
|
||||||
|
status = napi_create_string_utf8(env, "", NAPI_AUTO_LENGTH, &argv[0]);
|
||||||
|
}
|
||||||
|
if (status != napi_ok) {
|
||||||
|
napi_throw_error(env, NULL, "Unable to create argv for js jsonrpc_handler arguments");
|
||||||
|
}
|
||||||
|
free(response);
|
||||||
|
|
||||||
|
TRACE("calling back into js");
|
||||||
|
napi_value result;
|
||||||
|
status = napi_call_function(
|
||||||
|
env,
|
||||||
|
global,
|
||||||
|
js_callback,
|
||||||
|
1,
|
||||||
|
argv,
|
||||||
|
&result);
|
||||||
|
if (status != napi_ok) {
|
||||||
|
TRACE("Unable to call jsonrpc_handler callback2");
|
||||||
|
const napi_extended_error_info* error_result;
|
||||||
|
NAPI_STATUS_THROWS(napi_get_last_error_info(env, &error_result));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NAPI_METHOD(dcn_accounts_start_jsonrpc) {
|
||||||
|
NAPI_ARGV(2);
|
||||||
|
NAPI_DCN_ACCOUNTS();
|
||||||
|
napi_value callback = argv[1];
|
||||||
|
|
||||||
|
TRACE("calling..");
|
||||||
|
napi_value async_resource_name;
|
||||||
|
NAPI_STATUS_THROWS(napi_create_string_utf8(env, "dc_accounts_jsonrpc_callback", NAPI_AUTO_LENGTH, &async_resource_name));
|
||||||
|
|
||||||
|
TRACE("creating threadsafe function..");
|
||||||
|
|
||||||
|
NAPI_STATUS_THROWS(napi_create_threadsafe_function(
|
||||||
|
env,
|
||||||
|
callback,
|
||||||
|
0,
|
||||||
|
async_resource_name,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
dcn_accounts,
|
||||||
|
call_accounts_js_jsonrpc_handler,
|
||||||
|
&dcn_accounts->threadsafe_jsonrpc_handler));
|
||||||
|
TRACE("done");
|
||||||
|
|
||||||
|
dcn_accounts->gc = 0;
|
||||||
|
dcn_accounts->jsonrpc_instance = dc_get_json_api(dcn_accounts->dc_accounts);
|
||||||
|
|
||||||
|
TRACE("creating uv thread..");
|
||||||
|
uv_thread_create(&dcn_accounts->jsonrpc_thread, accounts_jsonrpc_thread_func, dcn_accounts);
|
||||||
|
|
||||||
|
NAPI_RETURN_UNDEFINED();
|
||||||
|
}
|
||||||
|
|
||||||
|
NAPI_METHOD(dcn_json_rpc_request) {
|
||||||
|
NAPI_ARGV(2);
|
||||||
|
NAPI_DCN_ACCOUNTS();
|
||||||
|
if (!dcn_accounts->jsonrpc_instance) {
|
||||||
|
const char* msg = "dcn_accounts->jsonrpc_instance is null, have you called dcn_accounts_start_jsonrpc()?";
|
||||||
|
NAPI_STATUS_THROWS(napi_throw_type_error(env, NULL, msg));
|
||||||
|
}
|
||||||
|
NAPI_ARGV_UTF8_MALLOC(request, 1);
|
||||||
|
dc_json_request(dcn_accounts->jsonrpc_instance, request);
|
||||||
|
free(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
NAPI_INIT() {
|
NAPI_INIT() {
|
||||||
/**
|
/**
|
||||||
@@ -3504,4 +3632,9 @@ NAPI_INIT() {
|
|||||||
NAPI_EXPORT_FUNCTION(dcn_send_webxdc_status_update);
|
NAPI_EXPORT_FUNCTION(dcn_send_webxdc_status_update);
|
||||||
NAPI_EXPORT_FUNCTION(dcn_get_webxdc_status_updates);
|
NAPI_EXPORT_FUNCTION(dcn_get_webxdc_status_updates);
|
||||||
NAPI_EXPORT_FUNCTION(dcn_msg_get_webxdc_blob);
|
NAPI_EXPORT_FUNCTION(dcn_msg_get_webxdc_blob);
|
||||||
|
|
||||||
|
|
||||||
|
/** jsonrpc **/
|
||||||
|
NAPI_EXPORT_FUNCTION(dcn_accounts_start_jsonrpc);
|
||||||
|
NAPI_EXPORT_FUNCTION(dcn_json_rpc_request);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
dcn_accounts_t* dcn_accounts; \
|
dcn_accounts_t* dcn_accounts; \
|
||||||
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&dcn_accounts)); \
|
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&dcn_accounts)); \
|
||||||
if (!dcn_accounts) { \
|
if (!dcn_accounts) { \
|
||||||
const char* msg = "Provided dnc_acounts is null"; \
|
const char* msg = "Provided dcn_acounts is null"; \
|
||||||
NAPI_STATUS_THROWS(napi_throw_type_error(env, NULL, msg)); \
|
NAPI_STATUS_THROWS(napi_throw_type_error(env, NULL, msg)); \
|
||||||
} \
|
} \
|
||||||
if (!dcn_accounts->dc_accounts) { \
|
if (!dcn_accounts->dc_accounts) { \
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import DeltaChat, { Message } from '../dist'
|
import DeltaChat, { Message } from '../dist'
|
||||||
import binding from '../binding'
|
import binding from '../binding'
|
||||||
|
|
||||||
import { strictEqual } from 'assert'
|
import { deepEqual, deepStrictEqual, strictEqual } from 'assert'
|
||||||
import chai, { expect } from 'chai'
|
import chai, { expect } from 'chai'
|
||||||
import chaiAsPromised from 'chai-as-promised'
|
import chaiAsPromised from 'chai-as-promised'
|
||||||
import { EventId2EventName, C } from '../dist/constants'
|
import { EventId2EventName, C } from '../dist/constants'
|
||||||
@@ -84,6 +84,96 @@ describe('static tests', function () {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe.only('JSON RPC', function () {
|
||||||
|
it('smoketest', async function () {
|
||||||
|
const { dc } = DeltaChat.newTemporary()
|
||||||
|
let promise_resolve
|
||||||
|
const promise = new Promise((res, _rej) => {
|
||||||
|
promise_resolve = res
|
||||||
|
})
|
||||||
|
dc.startJSONRPCHandler(promise_resolve)
|
||||||
|
dc.jsonRPCRequest(
|
||||||
|
JSON.stringify({
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
method: 'get_all_account_ids',
|
||||||
|
params: [],
|
||||||
|
id: 2,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
deepStrictEqual(
|
||||||
|
{
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
id: 2,
|
||||||
|
result: [1],
|
||||||
|
},
|
||||||
|
JSON.parse(await promise)
|
||||||
|
)
|
||||||
|
// TODO: fix that shutdown crashes!
|
||||||
|
dc.close()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('basic test', async function () {
|
||||||
|
const { dc } = DeltaChat.newTemporary()
|
||||||
|
|
||||||
|
const promises = {};
|
||||||
|
dc.startJSONRPCHandler((msg) => {
|
||||||
|
const response = JSON.parse(msg)
|
||||||
|
promises[response.id](response)
|
||||||
|
delete promises[response.id]
|
||||||
|
})
|
||||||
|
const call = (request) => {
|
||||||
|
dc.jsonRPCRequest(JSON.stringify(request))
|
||||||
|
return new Promise((res, _rej)=> {
|
||||||
|
promises[request.id] = res
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
deepStrictEqual(
|
||||||
|
{
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
id: 2,
|
||||||
|
result: [1],
|
||||||
|
},
|
||||||
|
await call({
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
method: 'get_all_account_ids',
|
||||||
|
params: [],
|
||||||
|
id: 2,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
deepStrictEqual(
|
||||||
|
{
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
id: 3,
|
||||||
|
result: 2,
|
||||||
|
},
|
||||||
|
await call({
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
method: 'add_account',
|
||||||
|
params: [],
|
||||||
|
id: 3,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
deepStrictEqual(
|
||||||
|
{
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
id: 4,
|
||||||
|
result: [1, 2],
|
||||||
|
},
|
||||||
|
await call({
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
method: 'get_all_account_ids',
|
||||||
|
params: [],
|
||||||
|
id: 4,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
dc.close()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('Basic offline Tests', function () {
|
describe('Basic offline Tests', function () {
|
||||||
it('opens a context', async function () {
|
it('opens a context', async function () {
|
||||||
const { dc, context } = DeltaChat.newTemporary()
|
const { dc, context } = DeltaChat.newTemporary()
|
||||||
|
|||||||
Reference in New Issue
Block a user