Skip to content

Commit

Permalink
Merge pull request #520 from alvasw/create_json_rpc_lib
Browse files Browse the repository at this point in the history
Create json-rpc library
  • Loading branch information
alvasw authored Oct 24, 2022
2 parents 8d73094 + 65ab4d9 commit bce6d24
Show file tree
Hide file tree
Showing 10 changed files with 350 additions and 0 deletions.
11 changes: 11 additions & 0 deletions wallets/json-rpc/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
plugins {
id 'bisq.gradle.plugin.BisqPlugin'
}

dependencies {
implementation 'com.squareup.okhttp3:okhttp:4.10.0'
implementation 'com.squareup.moshi:moshi:1.14.0'

testImplementation libs.assertj.core
testImplementation 'com.squareup.okhttp3:mockwebserver:4.10.0'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/

package bisq.wallets.json_rpc;

import java.util.UUID;

public class JsonRpcCall {
private final String jsonrpc = "2.0";
private final String id;
private final String method;
private final Object params;

public JsonRpcCall(String method, Object params) {
this.id = UUID.randomUUID().toString();
this.method = method;
this.params = params;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/

package bisq.wallets.json_rpc;

import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.Moshi;
import okhttp3.*;

import java.io.IOException;
import java.util.Objects;

public class JsonRpcClient {

public static final String AUTHORIZATION_HEADER_NAME = "Authorization";

private final JsonRpcEndpointSpec rpcEndpointSpec;

private final OkHttpClient client = new OkHttpClient();
private final MediaType jsonMediaType = MediaType.parse("application/json");

private final Moshi moshi = new Moshi.Builder().build();
private final JsonAdapter<JsonRpcCall> jsonRpcCallJsonAdapter = moshi.adapter(JsonRpcCall.class);

public JsonRpcClient(JsonRpcEndpointSpec rpcEndpointSpec) {
this.rpcEndpointSpec = rpcEndpointSpec;
}

public <T, R> R call(RpcCall<T, R> rpcCall) throws IOException {
JsonRpcCall jsonRpcCall = new JsonRpcCall(rpcCall.getRpcMethodName(), rpcCall.request);
String jsonRequest = jsonRpcCallJsonAdapter.toJson(jsonRpcCall);
Request request = buildRequest(jsonRequest);

try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

ResponseBody responseBody = response.body();
Objects.requireNonNull(responseBody);

JsonAdapter<R> jsonAdapter = rpcCall.getJsonAdapter();
return jsonAdapter.fromJson(responseBody.source());
}
}

private Request buildRequest(String body) {
return new Request.Builder()
.url(rpcEndpointSpec.getUrl())
.addHeader(AUTHORIZATION_HEADER_NAME, rpcEndpointSpec.getAuthHeaderValue())
.post(RequestBody.create(body, jsonMediaType))
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/

package bisq.wallets.json_rpc;

import lombok.Getter;
import okhttp3.Credentials;
import okhttp3.HttpUrl;

@Getter
public class JsonRpcEndpointSpec {
private final HttpUrl url;
private final String username;
private final String password;

public JsonRpcEndpointSpec(String url, String username, String password) {
this(HttpUrl.parse(url), username, password);
}

public JsonRpcEndpointSpec(HttpUrl url, String username, String password) {
this.url = url;
this.username = username;
this.password = password;
}

public String getAuthHeaderValue() {
return Credentials.basic(username, password);
}
}
44 changes: 44 additions & 0 deletions wallets/json-rpc/src/main/java/bisq/wallets/json_rpc/RpcCall.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/

package bisq.wallets.json_rpc;

import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.Moshi;
import lombok.Getter;

public abstract class RpcCall<T, R> {

@Getter
protected final T request;

private final Moshi moshi = new Moshi.Builder().build();

public RpcCall(T request) {
this.request = request;
}

public abstract String getRpcMethodName();

public abstract boolean isResponseValid(R response);

public abstract Class<R> getRpcResponseClass();

public JsonAdapter<R> getJsonAdapter() {
return moshi.adapter(getRpcResponseClass());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/

package bisq.wallets.json_rpc;

import java.util.HashMap;
import java.util.Map;

public class DummyGetBlockChainInfoRpcCall extends RpcCall<Map<String, String>, DummyJsonRpcResponse> {
public DummyGetBlockChainInfoRpcCall() {
super(new HashMap<>());
}

@Override
public String getRpcMethodName() {
return "getblockchaininfo";
}

@Override
public boolean isResponseValid(DummyJsonRpcResponse response) {
return true;
}

@Override
public Class<DummyJsonRpcResponse> getRpcResponseClass() {
return DummyJsonRpcResponse.class;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/

package bisq.wallets.json_rpc;

public class DummyJsonRpcResponse {
GetBlockChainInfoDummyResponse result;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/

package bisq.wallets.json_rpc;

public class GetBlockChainInfoDummyResponse {
String chain;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/

package bisq.wallets.json_rpc;

import okhttp3.HttpUrl;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import okhttp3.mockwebserver.RecordedRequest;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.IOException;

import static org.assertj.core.api.Assertions.assertThat;

public class JsonRpcClientTest {

private final MockWebServer server = new MockWebServer();

@BeforeEach
void setUp() throws IOException {
String mockResponse = "{\"result\":{\"chain\":\"regtest\",\"blocks\":102,\"headers\":102,\"bestblockhash\":\"5e5bcaaa2690bf99da1046334e4a2d783901608718a5b647846e67ffe0802bc8\",\"difficulty\":4.656542373906925e-10,\"time\":1663343392,\"mediantime\":1663060997,\"verificationprogress\":1,\"initialblockdownload\":true,\"chainwork\":\"00000000000000000000000000000000000000000000000000000000000000ce\",\"size_on_disk\":31048,\"pruned\":false,\"warnings\":\"\"},\"error\":null,\"id\":\"curltest\"}";
server.enqueue(new MockResponse().setBody(mockResponse));
server.start();
}

@AfterEach
void tearDown() throws IOException {
server.shutdown();
}

@Test
void dummyGetBlockchainInfoTest() throws Exception {
HttpUrl baseUrl = server.url("/");
JsonRpcEndpointSpec endpointSpec = new JsonRpcEndpointSpec(baseUrl, "bisq", "bisq");
JsonRpcClient jsonRpcClient = new JsonRpcClient(endpointSpec);

var rpcCall = new DummyGetBlockChainInfoRpcCall();
DummyJsonRpcResponse dummyJsonRpcResponse = jsonRpcClient.call(rpcCall);

assertThat(dummyJsonRpcResponse).isNotNull();
assertThat(dummyJsonRpcResponse.result.chain).isEqualTo("regtest");

RecordedRequest recordedRequest = server.takeRequest();
assertThat("/").isEqualTo(recordedRequest.getPath());

String authHeader = recordedRequest.getHeader(JsonRpcClient.AUTHORIZATION_HEADER_NAME);
assertThat(authHeader).isNotNull();
}
}
1 change: 1 addition & 0 deletions wallets/settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ include 'bitcoind'
include 'electrum'
include 'elementsd'

include 'json-rpc'
include 'process'
include 'regtest'

Expand Down

0 comments on commit bce6d24

Please sign in to comment.