Skip to content

Commit

Permalink
Merge pull request #2479 from deltachat/link2xt/jsonrpc
Browse files Browse the repository at this point in the history
Add DcJsonrpcInstance class
  • Loading branch information
adbenitez authored May 5, 2023
2 parents 4e89b34 + 0b85cd2 commit 4461358
Show file tree
Hide file tree
Showing 23 changed files with 281 additions and 30 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ dependencies {
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'com.journeyapps:zxing-android-embedded:3.4.0' // QR Code scanner
implementation 'com.fasterxml.jackson.core:jackson-databind:2.11.1' // used as JSON library
implementation 'com.google.code.gson:gson:2.10.1' // used as JSON library
implementation "me.leolin:ShortcutBadger:1.1.16" // display messagecount on the home screen icon.
implementation 'com.jpardogo.materialtabstrip:library:1.0.9' // used in the emoji selector for the tab selection.
implementation 'com.github.chrisbanes:PhotoView:2.1.3' // does the zooming on photos / media
Expand Down
43 changes: 43 additions & 0 deletions jni/dc_wrapper.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,11 @@ JNIEXPORT jlong Java_com_b44t_messenger_DcAccounts_getEventEmitterCPtr(JNIEnv *e
return (jlong)dc_accounts_get_event_emitter(get_dc_accounts(env, obj));
}

JNIEXPORT jlong Java_com_b44t_messenger_DcAccounts_getJsonrpcInstanceCPtr(JNIEnv *env, jobject obj)
{
return (jlong)dc_jsonrpc_init(get_dc_accounts(env, obj));
}


JNIEXPORT void Java_com_b44t_messenger_DcAccounts_startIo(JNIEnv *env, jobject obj)
{
Expand Down Expand Up @@ -2137,3 +2142,41 @@ JNIEXPORT jbyteArray Java_com_b44t_messenger_DcHttpResponse_getBlob(JNIEnv *env,
dc_str_unref((char*)ptr);
return ret;
}

/*******************************************************************************
* DcJsonrpcInstance
******************************************************************************/

static dc_jsonrpc_instance_t* get_dc_jsonrpc_instance(JNIEnv *env, jobject obj)
{
static jfieldID fid = 0;
if (fid==0) {
jclass cls = (*env)->GetObjectClass(env, obj);
fid = (*env)->GetFieldID(env, cls, "jsonrpcInstanceCPtr", "J" /*Signature, J=long*/);
}
if (fid) {
return (dc_jsonrpc_instance_t*)(*env)->GetLongField(env, obj, fid);
}
return NULL;
}


JNIEXPORT void Java_com_b44t_messenger_DcJsonrpcInstance_unrefJsonrpcInstanceCPtr(JNIEnv *env, jobject obj)
{
dc_jsonrpc_unref(get_dc_jsonrpc_instance(env, obj));
}

JNIEXPORT void Java_com_b44t_messenger_DcJsonrpcInstance_request(JNIEnv *env, jobject obj, jstring request)
{
CHAR_REF(request);
dc_jsonrpc_request(get_dc_jsonrpc_instance(env, obj), requestPtr);
CHAR_UNREF(request);
}

JNIEXPORT jstring Java_com_b44t_messenger_DcJsonrpcInstance_getNextResponse(JNIEnv *env, jobject obj)
{
char* temp = dc_jsonrpc_next_response(get_dc_jsonrpc_instance(env, obj));
jstring ret = JSTRING_NEW(temp);
dc_str_unref(temp);
return ret;
}
8 changes: 4 additions & 4 deletions scripts/ndk-make.sh
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ if test -z $1 || test $1 = armeabi-v7a; then
TARGET_CC="$TOOLCHAIN/bin/armv7a-linux-androideabi16-clang" \
TARGET_AR="$TOOLCHAIN/bin/llvm-ar" \
TARGET_RANLIB="$TOOLCHAIN/bin/llvm-ranlib" \
cargo build $RELEASEFLAG --target armv7-linux-androideabi -p deltachat_ffi
cargo build $RELEASEFLAG --target armv7-linux-androideabi -p deltachat_ffi --features jsonrpc
cp target/armv7-linux-androideabi/$RELEASE/libdeltachat.a $jnidir/armeabi-v7a
fi

Expand All @@ -124,7 +124,7 @@ if test -z $1 || test $1 = arm64-v8a; then
TARGET_CC="$TOOLCHAIN/bin/aarch64-linux-android21-clang" \
TARGET_AR="$TOOLCHAIN/bin/llvm-ar" \
TARGET_RANLIB="$TOOLCHAIN/bin/llvm-ranlib" \
cargo build $RELEASEFLAG --target aarch64-linux-android -p deltachat_ffi
cargo build $RELEASEFLAG --target aarch64-linux-android -p deltachat_ffi --features jsonrpc
cp target/aarch64-linux-android/$RELEASE/libdeltachat.a $jnidir/arm64-v8a
fi

Expand All @@ -133,7 +133,7 @@ if test -z $1 || test $1 = x86; then
TARGET_CC="$TOOLCHAIN/bin/i686-linux-android16-clang" \
TARGET_AR="$TOOLCHAIN/bin/llvm-ar" \
TARGET_RANLIB="$TOOLCHAIN/bin/llvm-ranlib" \
cargo build $RELEASEFLAG --target i686-linux-android -p deltachat_ffi
cargo build $RELEASEFLAG --target i686-linux-android -p deltachat_ffi --features jsonrpc
cp target/i686-linux-android/$RELEASE/libdeltachat.a $jnidir/x86
fi

Expand All @@ -142,7 +142,7 @@ if test -z $1 || test $1 = x86_64; then
TARGET_CC="$TOOLCHAIN/bin/x86_64-linux-android21-clang" \
TARGET_AR="$TOOLCHAIN/bin/llvm-ar" \
TARGET_RANLIB="$TOOLCHAIN/bin/llvm-ranlib" \
cargo build $RELEASEFLAG --target x86_64-linux-android -p deltachat_ffi
cargo build $RELEASEFLAG --target x86_64-linux-android -p deltachat_ffi --features jsonrpc
cp target/x86_64-linux-android/$RELEASE/libdeltachat.a $jnidir/x86_64
fi

Expand Down
2 changes: 2 additions & 0 deletions src/com/b44t/messenger/DcAccounts.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public void unref() {
}

public DcEventEmitter getEventEmitter () { return new DcEventEmitter(getEventEmitterCPtr()); }
public DcJsonrpcInstance getJsonrpcInstance () { return new DcJsonrpcInstance(getJsonrpcInstanceCPtr()); }
public native void startIo ();
public native void stopIo ();
public native void maybeNetwork ();
Expand All @@ -38,6 +39,7 @@ public void unref() {
private native long createAccountsCPtr (String osName, String dir);
private native void unrefAccountsCPtr ();
private native long getEventEmitterCPtr ();
private native long getJsonrpcInstanceCPtr ();
private native long getAccountCPtr (int accountId);
private native long getSelectedAccountCPtr ();
}
21 changes: 21 additions & 0 deletions src/com/b44t/messenger/DcJsonrpcInstance.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.b44t.messenger;

public class DcJsonrpcInstance {

public DcJsonrpcInstance(long jsonrpcInstanceCPtr) {
this.jsonrpcInstanceCPtr = jsonrpcInstanceCPtr;
}

@Override protected void finalize() throws Throwable {
super.finalize();
unrefJsonrpcInstanceCPtr();
jsonrpcInstanceCPtr = 0;
}

public native void request(String request);
public native String getNextResponse();

// working with raw c-data
private long jsonrpcInstanceCPtr; // CAVE: the name is referenced in the JNI
private native void unrefJsonrpcInstanceCPtr();
}
33 changes: 33 additions & 0 deletions src/com/b44t/messenger/rpc/HttpResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.b44t.messenger.rpc;

import android.util.Base64;

public class HttpResponse {
// base64-encoded response body.
private String blob;
// MIME type, e.g. "text/plain" or "text/html".
private String mimetype;
// Encoding, e.g. "utf-8".
private String encoding;

public HttpResponse(String blob, String mimetype, String encoding) {
this.blob = blob;
this.mimetype = mimetype;
this.encoding = encoding;
}

public byte[] getBlob() {
if (blob == null) {
return null;
}
return Base64.decode(blob, Base64.NO_WRAP | Base64.NO_PADDING);
}

public String getMimetype() {
return mimetype;
}

public String getEncoding() {
return encoding;
}
}
128 changes: 128 additions & 0 deletions src/com/b44t/messenger/rpc/Rpc.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package com.b44t.messenger.rpc;

import com.b44t.messenger.DcJsonrpcInstance;
import com.b44t.messenger.util.concurrent.SettableFuture;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;

public class Rpc {
private final Map<Integer, SettableFuture<JsonElement>> requestFutures = new ConcurrentHashMap<>();
private final DcJsonrpcInstance dcJsonrpcInstance;
private int requestId = 0;
private final Gson gson = new GsonBuilder().serializeNulls().create();

public Rpc(DcJsonrpcInstance dcJsonrpcInstance) {
this.dcJsonrpcInstance = dcJsonrpcInstance;
}

private void processResponse() throws JsonSyntaxException {
String jsonResponse = dcJsonrpcInstance.getNextResponse();
Response response = gson.fromJson(jsonResponse, Response.class);

if (response.id == 0) { // Got JSON-RPC notification/event, ignore
return;
}

SettableFuture<JsonElement> future = requestFutures.remove(response.id);
if (future == null) { // Got a response with unknown ID, ignore
return;
}

if (response.error != null) {
future.setException(new RpcException(response.error.toString()));
} else if (response.result != null) {
future.set(response.result);
} else {
future.setException(new RpcException("Got JSON-RPC response witout result or error: " + jsonResponse));
}
}

public void start() {
new Thread(() -> {
while (true) {
try {
processResponse();
} catch (JsonSyntaxException e) {
e.printStackTrace();
}
}
}, "jsonrpcThread").start();
}

public SettableFuture<JsonElement> call(String method, Object... params) {
int id;
synchronized (this) {
id = ++requestId;
}
String jsonRequest = gson.toJson(new Request(method, params, id));
SettableFuture<JsonElement> future = new SettableFuture<>();
requestFutures.put(id, future);
dcJsonrpcInstance.request(jsonRequest);
return future;
}

public JsonElement getResult(String method, Object... params) throws RpcException {
try {
return call(method, params).get();
} catch (ExecutionException e) {
throw (RpcException)e.getCause();
} catch (InterruptedException e) {
throw new RpcException(e.getMessage());
}
}

public int addAccount() throws RpcException {
return gson.fromJson(getResult("add_account"), int.class);
}

public void startIO() throws RpcException {
getResult("start_io_for_all_accounts");
}

public void stopIO() throws RpcException {
getResult("stop_io_for_all_accounts");
}

public Map<String, String> getSystemInfo() throws RpcException {
TypeToken<Map<String, String>> mapType = new TypeToken<Map<String, String>>(){};
return gson.fromJson(getResult("get_system_info"), mapType);
}

public HttpResponse getHttpResponse(int accountId, String url) throws RpcException {
return gson.fromJson(getResult("get_http_response", accountId, url), HttpResponse.class);
}


private static class Request {
public String jsonrpc = "2.0";
public String method;
public Object[] params;
public int id;

public Request(String method, Object[] params, int id) {
this.method = method;
this.params = params;
this.id = id;
}
}

private static class Response {
public int id = 0;
public JsonElement result;
public JsonElement error;

public Response(int id, JsonElement result, JsonElement error) {
this.id = id;
this.result = result;
this.error = error;
}
}
}
11 changes: 11 additions & 0 deletions src/com/b44t/messenger/rpc/RpcException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.b44t.messenger.rpc;

/**
* An exception occurred while processing a request in Delta Chat core.
**/
public class RpcException extends Exception {

public RpcException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.thoughtcrime.securesms.util.concurrent;
package com.b44t.messenger.util.concurrent;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.thoughtcrime.securesms.util.concurrent;
package com.b44t.messenger.util.concurrent;

import java.util.LinkedList;
import java.util.List;
Expand Down
5 changes: 5 additions & 0 deletions src/org/thoughtcrime/securesms/ApplicationContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.b44t.messenger.DcContext;
import com.b44t.messenger.DcEvent;
import com.b44t.messenger.DcEventEmitter;
import com.b44t.messenger.rpc.Rpc;

import org.thoughtcrime.securesms.components.emoji.EmojiProvider;
import org.thoughtcrime.securesms.connect.AccountManager;
Expand Down Expand Up @@ -52,6 +53,7 @@ public class ApplicationContext extends MultiDexApplication {
private static final String TAG = ApplicationContext.class.getSimpleName();

public DcAccounts dcAccounts;
public Rpc rpc;
public DcContext dcContext;
public DcLocationManager dcLocationManager;
public DcEventCenter eventCenter;
Expand Down Expand Up @@ -88,6 +90,7 @@ public void onCreate() {
System.loadLibrary("native-utils");

dcAccounts = new DcAccounts("Android "+BuildConfig.VERSION_NAME, new File(getFilesDir(), "accounts").getAbsolutePath());
rpc = new Rpc(dcAccounts.getJsonrpcInstance());
AccountManager.getInstance().migrateToDcAccounts(this);
int[] allAccounts = dcAccounts.getAll();
for (int accountId : allAccounts) {
Expand Down Expand Up @@ -122,6 +125,8 @@ public void onCreate() {
Log.i("DeltaChat", "shutting down event handler");
}, "eventThread").start();

rpc.start();

// set translations before starting I/O to avoid sending untranslated MDNs (issue #2288)
DcHelper.setStockTranslations(this);

Expand Down
4 changes: 2 additions & 2 deletions src/org/thoughtcrime/securesms/ConversationActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@
import com.b44t.messenger.DcContext;
import com.b44t.messenger.DcEvent;
import com.b44t.messenger.DcMsg;
import com.b44t.messenger.util.concurrent.ListenableFuture;
import com.b44t.messenger.util.concurrent.SettableFuture;

import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.attachments.UriAttachment;
Expand Down Expand Up @@ -114,8 +116,6 @@
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.concurrent.AssertedSuccessListener;
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
import org.thoughtcrime.securesms.util.concurrent.SettableFuture;
import org.thoughtcrime.securesms.util.guava.Optional;
import org.thoughtcrime.securesms.util.views.Stub;
import org.thoughtcrime.securesms.video.recode.VideoRecoder;
Expand Down
Loading

0 comments on commit 4461358

Please sign in to comment.