mirror of
https://github.com/ArcaneChat/android.git
synced 2026-07-03 14:05:24 +02:00
124 lines
3.7 KiB
Java
124 lines
3.7 KiB
Java
/* Autogenerated file, do not edit manually */
|
|
package chat.delta.rpc;
|
|
|
|
import chat.delta.util.SettableFuture;
|
|
|
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
import com.fasterxml.jackson.core.type.TypeReference;
|
|
import com.fasterxml.jackson.databind.JsonNode;
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
|
import java.io.IOException;
|
|
import java.util.Map;
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
import java.util.concurrent.ExecutionException;
|
|
|
|
/* Basic RPC Transport implementation */
|
|
public abstract class BaseTransport implements Rpc.Transport {
|
|
private final Map<Integer, SettableFuture<JsonNode>> requestFutures = new ConcurrentHashMap<>();
|
|
private int requestId = 0;
|
|
private final ObjectMapper mapper = new ObjectMapper();
|
|
private Thread worker;
|
|
|
|
/* Send a Request as raw JSON String to the RPC server */
|
|
protected abstract void sendRequest(String jsonRequest);
|
|
|
|
/* Get next Response as raw JSON String from the RPC server */
|
|
protected abstract String getResponse();
|
|
|
|
public ObjectMapper getObjectMapper() {
|
|
return mapper;
|
|
}
|
|
|
|
public void call(String method, JsonNode... params) throws RpcException {
|
|
innerCall(method, params);
|
|
}
|
|
|
|
public <T> T callForResult(TypeReference<T> resultType, String method, JsonNode... params) throws RpcException {
|
|
try {
|
|
JsonNode node = innerCall(method, params);
|
|
if (node.isNull()) return null;
|
|
return mapper.readValue(node.traverse(), resultType);
|
|
} catch (IOException e) {
|
|
throw new RpcException(e.getMessage());
|
|
}
|
|
}
|
|
|
|
private JsonNode innerCall(String method, JsonNode... params) throws RpcException {
|
|
int id;
|
|
synchronized (this) {
|
|
id = ++requestId;
|
|
ensureWorkerThread();
|
|
}
|
|
try {
|
|
String jsonRequest = mapper.writeValueAsString(new Request(method, params, id));
|
|
SettableFuture<JsonNode> future = new SettableFuture<>();
|
|
requestFutures.put(id, future);
|
|
sendRequest(jsonRequest);
|
|
return future.get();
|
|
} catch (ExecutionException e) {
|
|
throw (RpcException)e.getCause();
|
|
} catch (InterruptedException e) {
|
|
throw new RpcException(e.getMessage());
|
|
} catch (JsonProcessingException e) {
|
|
throw new RpcException(e.getMessage());
|
|
}
|
|
}
|
|
|
|
private void ensureWorkerThread() {
|
|
if (worker != null) return;
|
|
|
|
worker = new Thread(() -> {
|
|
while (true) {
|
|
try {
|
|
processResponse();
|
|
} catch (JsonProcessingException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
}, "jsonrpcThread");
|
|
worker.start();
|
|
}
|
|
|
|
private void processResponse() throws JsonProcessingException {
|
|
String jsonResponse = getResponse();
|
|
Response response = mapper.readValue(jsonResponse, Response.class);
|
|
|
|
if (response.id == 0) { // Got JSON-RPC notification/event, ignore
|
|
return;
|
|
}
|
|
|
|
SettableFuture<JsonNode> 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 without result or error: " + jsonResponse));
|
|
}
|
|
}
|
|
|
|
private static class Request {
|
|
private final String jsonrpc = "2.0";
|
|
public final String method;
|
|
public final JsonNode[] params;
|
|
public final int id;
|
|
|
|
public Request(String method, JsonNode[] params, int id) {
|
|
this.method = method;
|
|
this.params = params;
|
|
this.id = id;
|
|
}
|
|
}
|
|
|
|
private static class Response {
|
|
public String jsonrpc;
|
|
public int id;
|
|
public JsonNode result;
|
|
public JsonNode error;
|
|
}
|
|
} |