Compare commits

..

14 Commits

Author SHA1 Message Date
Simon Laux
c14e5086d7 improve naming 2022-06-28 13:25:41 +02:00
Simon Laux
4779383401 commit types.ts
that dc-node has everything it needs to provide @deltachat/jsonrpc-client
without an extra ts compile step
2022-06-26 02:08:43 +02:00
Simon Laux
47d30ef6d3 add @deltachat/jsonrpc-client
to make sure its dependencies are installed, too
whwn installing dc-node
2022-06-26 01:48:01 +02:00
Simon Laux
3a38ffdfe0 disable jsonrpc by default 2022-06-26 00:06:43 +02:00
Simon Laux
33d548eccc put jsonrpc stuff in own module 2022-06-25 23:56:56 +02:00
Simon Laux
1700af2c8d remove selectAccount from highlevel client 2022-06-25 23:38:13 +02:00
Simon Laux
01920a1a00 activate other tests again 2022-06-25 23:38:13 +02:00
Simon Laux
7c67ea0b8a fix closing segfault
thanks again to link2xt for figguring this out
2022-06-25 23:38:13 +02:00
Simon Laux
0c64701984 break loop on empty response 2022-06-25 23:38:13 +02:00
Simon Laux
d2d35fe26b call a jsonrpc function in segfault example 2022-06-25 23:38:13 +02:00
Simon Laux
a0b4d016d5 add jsonrpc feature flag 2022-06-25 23:38:13 +02:00
Simon Laux
3ce70ee244 add jsonrpc crate to set_core_version 2022-06-25 23:38:13 +02:00
Simon Laux
c43c9b9107 add some files to npm ignore
that don't need to be in the npm package
2022-06-25 23:38:13 +02:00
Simon Laux
638d2ff932 add json api to cffi and expose it in dc node 2022-06-25 23:38:13 +02:00
19 changed files with 422 additions and 21 deletions

View File

@@ -40,3 +40,17 @@ node/old_docs.md
.vscode/
.github/
node/.prettierrc.yml
deltachat-jsonrpc/TODO.md
deltachat-jsonrpc/README.MD
deltachat-jsonrpc/.gitignore
deltachat-jsonrpc/typescript/.gitignore
deltachat-jsonrpc/typescript/.prettierignore
deltachat-jsonrpc/typescript/accounts/
deltachat-jsonrpc/typescript/index.html
deltachat-jsonrpc/typescript/node-demo.js
deltachat-jsonrpc/typescript/report_api_coverage.mjs
deltachat-jsonrpc/typescript/test
deltachat-jsonrpc/typescript/example.ts
.DS_Store

View File

@@ -21,7 +21,7 @@ add_custom_command(
PREFIX=${CMAKE_INSTALL_PREFIX}
LIBDIR=${CMAKE_INSTALL_FULL_LIBDIR}
INCLUDEDIR=${CMAKE_INSTALL_FULL_INCLUDEDIR}
${CARGO} build --release --no-default-features
${CARGO} build --release --no-default-features --features jsonrpc
# Build in `deltachat-ffi` directory instead of using
# `--package deltachat_ffi` to avoid feature resolver version

3
Cargo.lock generated
View File

@@ -1314,7 +1314,7 @@ dependencies = [
[[package]]
name = "deltachat-jsonrpc"
version = "0.1.0"
version = "1.86.0"
dependencies = [
"anyhow",
"async-channel",
@@ -1349,6 +1349,7 @@ dependencies = [
"anyhow",
"async-std",
"deltachat",
"deltachat-jsonrpc",
"human-panic",
"libc",
"num-traits",

View File

@@ -16,6 +16,7 @@ crate-type = ["cdylib", "staticlib"]
[dependencies]
deltachat = { path = "../", default-features = false }
deltachat-jsonrpc = { path = "../deltachat-jsonrpc", optional = true }
libc = "0.2"
human-panic = "1"
num-traits = "0.2"
@@ -29,4 +30,5 @@ rand = "0.7"
default = ["vendored"]
vendored = ["deltachat/vendored"]
nightly = ["deltachat/nightly"]
jsonrpc = ["deltachat-jsonrpc"]

View File

@@ -23,7 +23,7 @@ typedef struct _dc_provider dc_provider_t;
typedef struct _dc_event dc_event_t;
typedef struct _dc_event_emitter dc_event_emitter_t;
typedef struct _dc_accounts_event_emitter dc_accounts_event_emitter_t;
typedef struct _dc_jsonrpc_instance dc_jsonrpc_instance_t;
/**
* @mainpage Getting started
@@ -5178,6 +5178,55 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
*/
/**
* @class dc_jsonrpc_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_jsonrpc_unref() after usage.
*
*/
dc_jsonrpc_instance_t* dc_jsonrpc_init(dc_accounts_t* account_manager);
/**
* Free a jsonrpc instance.
*
* @memberof dc_jsonrpc_instance_t
* @param jsonrpc_instance jsonrpc instance as returned from dc_jsonrpc_init().
* If NULL is given, nothing is done and an error is logged.
*/
void dc_jsonrpc_unref(dc_jsonrpc_instance_t* jsonrpc_instance);
/**
* Makes an asynchronous jsonrpc request,
* returns immediately and once the result is ready it can be retrieved via dc_jsonrpc_next_response()
* the jsonrpc specification defines an invocation id that can then be used to match request and response.
*
* @memberof dc_jsonrpc_instance_t
* @param jsonrpc_instance jsonrpc instance as returned from dc_jsonrpc_init().
* @param request JSON-RPC request as string
*/
void dc_jsonrpc_request(dc_jsonrpc_instance_t* jsonrpc_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_jsonrpc_instance_t
* @param jsonrpc_instance jsonrpc instance as returned from dc_jsonrpc_init().
* @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_jsonrpc_unref().
*/
char* dc_jsonrpc_next_response(dc_jsonrpc_instance_t* jsonrpc_instance);
/**
* @class dc_event_emitter_t
*

View File

@@ -18,6 +18,7 @@ use std::fmt::Write;
use std::ops::Deref;
use std::ptr;
use std::str::FromStr;
use std::sync::Arc;
use std::time::{Duration, SystemTime};
use anyhow::Context as _;
@@ -4093,11 +4094,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
/// `dc_accounts_t` in multiple threads at once.
pub struct AccountsWrapper {
inner: RwLock<Accounts>,
inner: Arc<RwLock<Accounts>>,
}
impl Deref for AccountsWrapper {
type Target = RwLock<Accounts>;
type Target = Arc<RwLock<Accounts>>;
fn deref(&self) -> &Self::Target {
&self.inner
@@ -4106,7 +4107,7 @@ impl Deref for AccountsWrapper {
impl AccountsWrapper {
fn new(accounts: Accounts) -> Self {
let inner = RwLock::new(accounts);
let inner = Arc::new(RwLock::new(accounts));
Self { inner }
}
}
@@ -4424,3 +4425,77 @@ pub unsafe extern "C" fn dc_accounts_get_next_event(
.map(|ev| Box::into_raw(Box::new(ev)))
.unwrap_or_else(ptr::null_mut)
}
#[cfg(feature = "jsonrpc")]
mod jsonrpc {
use super::*;
use deltachat_jsonrpc::api::CommandApi;
use deltachat_jsonrpc::yerpc::{MessageHandle, RpcHandle};
pub struct dc_jsonrpc_instance_t {
receiver: async_std::channel::Receiver<deltachat_jsonrpc::yerpc::Message>,
handle: MessageHandle<CommandApi>,
}
#[no_mangle]
pub unsafe extern "C" fn dc_jsonrpc_init(
account_manager: *mut dc_accounts_t,
) -> *mut dc_jsonrpc_instance_t {
if account_manager.is_null() {
eprintln!("ignoring careless call to dc_jsonrpc_init()");
return ptr::null_mut();
}
let cmd_api =
deltachat_jsonrpc::api::CommandApi::new_from_arc((*account_manager).inner.clone());
let (request_handle, receiver) = RpcHandle::new();
let handle = MessageHandle::new(request_handle, cmd_api);
let instance = dc_jsonrpc_instance_t { receiver, handle };
Box::into_raw(Box::new(instance))
}
#[no_mangle]
pub unsafe extern "C" fn dc_jsonrpc_unref(jsonrpc_instance: *mut dc_jsonrpc_instance_t) {
if jsonrpc_instance.is_null() {
eprintln!("ignoring careless call to dc_jsonrpc_unref()");
return;
}
Box::from_raw(jsonrpc_instance);
}
#[no_mangle]
pub unsafe extern "C" fn dc_jsonrpc_request(
jsonrpc_instance: *mut dc_jsonrpc_instance_t,
request: *const libc::c_char,
) {
if jsonrpc_instance.is_null() || request.is_null() {
eprintln!("ignoring careless call to dc_jsonrpc_request()");
return;
}
let api = &*jsonrpc_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_jsonrpc_next_response(
jsonrpc_instance: *mut dc_jsonrpc_instance_t,
) -> *mut libc::c_char {
if jsonrpc_instance.is_null() {
eprintln!("ignoring careless call to dc_jsonrpc_next_response()");
return ptr::null_mut();
}
let api = &*jsonrpc_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())
}
}

View File

@@ -1,5 +1,3 @@
accounts/
types.ts
.cargo

View File

@@ -1,6 +1,6 @@
[package]
name = "deltachat-jsonrpc"
version = "0.1.0"
version = "1.86.0"
authors = ["Delta Chat Developers (ML) <delta@codespeak.net>"]
edition = "2021"
default-run = "webserver"

View File

@@ -39,6 +39,10 @@ impl CommandApi {
}
}
pub fn new_from_arc(accounts: Arc<RwLock<Accounts>>) -> Self {
CommandApi { accounts }
}
async fn get_context(&self, id: u32) -> Result<deltachat::context::Context> {
let sc = self
.accounts

View File

@@ -1,6 +1,8 @@
pub mod api;
pub use api::events;
pub use yerpc;
#[cfg(test)]
mod tests {
use super::api::{Accounts, CommandApi};

View File

@@ -0,0 +1,15 @@
// AUTO-GENERATED by typescript-type-def
export type U32=number;
export type Account=(({"type":"Configured";}&{"id":U32;"display_name":(string|null);"addr":(string|null);"profile_image":(string|null);"color":string;})|({"type":"Unconfigured";}&{"id":U32;}));
export type ProviderInfo={"before_login_hint":string;"overview_page":string;"status":U32;};
export type ChatListEntry=[U32,U32];
export type I64=number;
export type Usize=number;
export type ChatListItemFetchResult=(({"type":"ChatListItem";}&{"id":U32;"name":string;"avatarPath":(string|null);"color":string;"lastUpdated":(I64|null);"summaryText1":string;"summaryText2":string;"summaryStatus":U32;"isProtected":boolean;"isGroup":boolean;"freshMessageCounter":Usize;"isSelfTalk":boolean;"isDeviceTalk":boolean;"isSendingLocation":boolean;"isSelfInGroup":boolean;"isArchived":boolean;"isPinned":boolean;"isMuted":boolean;"isContactRequest":boolean;})|{"type":"ArchiveLink";}|({"type":"Error";}&{"id":U32;"error":string;}));
export type Contact={"address":string;"color":string;"auth_name":string;"status":string;"display_name":string;"id":U32;"name":string;"profile_image":(string|null);"name_and_addr":string;"is_blocked":boolean;"is_verified":boolean;};
export type FullChat={"id":U32;"name":string;"is_protected":boolean;"profile_image":(string|null);"archived":boolean;"chat_type":U32;"is_unpromoted":boolean;"is_self_talk":boolean;"contacts":(Contact)[];"contact_ids":(U32)[];"color":string;"fresh_message_counter":Usize;"is_contact_request":boolean;"is_device_chat":boolean;"self_in_group":boolean;"is_muted":boolean;"ephemeral_timer":U32;"can_send":boolean;};
export type I32=number;
export type U64=number;
export type Message={"id":U32;"chat_id":U32;"from_id":U32;"quoted_text":(string|null);"quoted_message_id":(U32|null);"text":(string|null);"has_location":boolean;"has_html":boolean;"view_type":U32;"state":U32;"timestamp":I64;"sort_timestamp":I64;"received_timestamp":I64;"has_deviating_timestamp":boolean;"subject":string;"show_padlock":boolean;"is_setupmessage":boolean;"is_info":boolean;"is_forwarded":boolean;"duration":I32;"dimensions_height":I32;"dimensions_width":I32;"videochat_type":(U32|null);"videochat_url":(string|null);"override_sender_name":(string|null);"sender":Contact;"setup_code_begin":(string|null);"file":(string|null);"file_mime":(string|null);"file_bytes":U64;"file_name":(string|null);};
export type __AllTyps=[string,boolean,Record<string,string>,U32,U32,null,(U32)[],U32,null,(U32|null),(Account)[],U32,Account,U32,string,(ProviderInfo|null),U32,boolean,U32,Record<string,string>,U32,string,(string|null),null,U32,Record<string,(string|null)>,null,U32,string,(string|null),U32,(string)[],Record<string,(string|null)>,U32,null,U32,null,U32,string,U32,U32,string,null,U32,(U32|null),(string|null),(U32|null),(ChatListEntry)[],U32,(ChatListEntry)[],Record<U32,ChatListItemFetchResult>,U32,U32,FullChat,U32,U32,null,U32,U32,null,U32,U32,U32,(U32)[],U32,U32,Message,U32,(U32)[],Record<U32,Message>,U32,U32,Contact,U32,string,(string|null),U32,U32,U32,U32,U32,U32,null,U32,U32,null,U32,(Contact)[],U32,U32,(string|null),(U32)[],U32,U32,(string|null),(Contact)[],U32,(U32)[],Record<U32,Contact>,U32,string,U32,U32];

View File

@@ -39,11 +39,6 @@ export class BaseDeltachat<
});
}
async selectAccount(id: number) {
await this.rpc.selectAccount(id);
this.account = await this.rpc.getAccountInfo(id);
}
async listAccounts(): Promise<T.Account[]> {
return await this.rpc.getAllAccounts();
}

View File

@@ -19,10 +19,11 @@ interface NativeAccount {}
export class AccountManager extends EventEmitter {
dcn_accounts: NativeAccount
accountDir: string
jsonRpcStarted = false
constructor(cwd: string, os = 'deltachat-node') {
debug('DeltaChat constructor')
super()
debug('DeltaChat constructor')
this.accountDir = cwd
this.dcn_accounts = binding.dcn_accounts_new(os, this.accountDir)
@@ -114,6 +115,31 @@ export class AccountManager extends EventEmitter {
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.jsonRpcStarted) {
throw new Error('jsonrpc was started already')
}
binding.dcn_accounts_start_jsonrpc(this.dcn_accounts, callback.bind(this))
debug('Started jsonrpc handler')
this.jsonRpcStarted = true
}
jsonRPCRequest(message: string) {
if (!this.jsonRpcStarted) {
throw new Error(
'jsonrpc is not active, start it with startJSONRPCHandler first'
)
}
binding.dcn_json_rpc_request(this.dcn_accounts, message)
}
startIO() {
binding.dcn_accounts_start_io(this.dcn_accounts)
}

View File

@@ -9,7 +9,7 @@ const buildArgs = [
'build',
'--release',
'--features',
'vendored',
'vendored,jsonrpc',
'-p',
'deltachat_ffi'
]

View File

@@ -34,6 +34,9 @@ typedef struct dcn_accounts_t {
dc_accounts_t* dc_accounts;
napi_threadsafe_function threadsafe_event_handler;
uv_thread_t event_handler_thread;
napi_threadsafe_function threadsafe_jsonrpc_handler;
uv_thread_t jsonrpc_thread;
dc_jsonrpc_instance_t* jsonrpc_instance;
int gc;
} dcn_accounts_t;
@@ -2932,6 +2935,11 @@ NAPI_METHOD(dcn_accounts_unref) {
uv_thread_join(&dcn_accounts->event_handler_thread);
dcn_accounts->event_handler_thread = 0;
}
if (dcn_accounts->jsonrpc_instance) {
dc_jsonrpc_request(dcn_accounts->jsonrpc_instance, "{}");
uv_thread_join(&dcn_accounts->jsonrpc_thread);
dcn_accounts->jsonrpc_instance = NULL;
}
dc_accounts_unref(dcn_accounts->dc_accounts);
dcn_accounts->dc_accounts = NULL;
@@ -3090,8 +3098,6 @@ static void accounts_event_handler_thread_func(void* arg)
{
dcn_accounts_t* dcn_accounts = (dcn_accounts_t*)arg;
TRACE("event_handler_thread_func starting");
dc_accounts_event_emitter_t * dc_accounts_event_emitter = dc_accounts_get_event_emitter(dcn_accounts->dc_accounts);
@@ -3242,6 +3248,125 @@ NAPI_METHOD(dcn_accounts_start_event_handler) {
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) {
response = dc_jsonrpc_next_response(dcn_accounts->jsonrpc_instance);
if (response == NULL) {
// done or broken
break;
}
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_jsonrpc_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_jsonrpc_init(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_jsonrpc_request(dcn_accounts->jsonrpc_instance, request);
free(request);
}
NAPI_INIT() {
/**
@@ -3512,4 +3637,9 @@ NAPI_INIT() {
NAPI_EXPORT_FUNCTION(dcn_send_webxdc_status_update);
NAPI_EXPORT_FUNCTION(dcn_get_webxdc_status_updates);
NAPI_EXPORT_FUNCTION(dcn_msg_get_webxdc_blob);
/** jsonrpc **/
NAPI_EXPORT_FUNCTION(dcn_accounts_start_jsonrpc);
NAPI_EXPORT_FUNCTION(dcn_json_rpc_request);
}

View File

@@ -23,7 +23,7 @@
dcn_accounts_t* dcn_accounts; \
NAPI_STATUS_THROWS(napi_get_value_external(env, argv[0], (void**)&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)); \
} \
if (!dcn_accounts->dc_accounts) { \

View File

@@ -2,7 +2,7 @@
import DeltaChat, { Message } from '../dist'
import binding from '../binding'
import { strictEqual } from 'assert'
import { deepEqual, deepStrictEqual, strictEqual } from 'assert'
import chai, { expect } from 'chai'
import chaiAsPromised from 'chai-as-promised'
import { EventId2EventName, C } from '../dist/constants'
@@ -84,6 +84,95 @@ describe('static tests', function () {
})
})
describe('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)
)
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 () {
it('opens a context', async function () {
const { dc, context } = DeltaChat.newTemporary()

View File

@@ -1,5 +1,6 @@
{
"dependencies": {
"@deltachat/jsonrpc-client": "file:deltachat-jsonrpc/typescript",
"debug": "^4.1.1",
"napi-macros": "^2.0.0",
"node-gyp-build": "^4.1.0"

View File

@@ -63,7 +63,7 @@ def main():
parser = ArgumentParser(prog="set_core_version")
parser.add_argument("newversion")
toml_list = ["Cargo.toml", "deltachat-ffi/Cargo.toml"]
toml_list = ["Cargo.toml", "deltachat-ffi/Cargo.toml", "deltachat-jsonrpc/Cargo.toml"]
try:
opts = parser.parse_args()
except SystemExit: