diff --git a/app/src/main/java/io/lbry/browser/tasks/CommentCreateTask.java b/app/src/main/java/io/lbry/browser/tasks/CommentCreateTask.java index 54f810e6..5cdce1d9 100644 --- a/app/src/main/java/io/lbry/browser/tasks/CommentCreateTask.java +++ b/app/src/main/java/io/lbry/browser/tasks/CommentCreateTask.java @@ -7,29 +7,18 @@ import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; -import java.math.BigDecimal; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.concurrent.TimeUnit; +import java.util.Objects; import io.lbry.browser.exceptions.ApiCallException; import io.lbry.browser.model.Comment; +import io.lbry.browser.utils.Comments; import io.lbry.browser.utils.Helper; -import io.lbry.browser.utils.Lbry; -import io.lbry.browser.utils.Lbryio; -import okhttp3.OkHttpClient; -import okhttp3.Request; import okhttp3.Response; public class CommentCreateTask extends AsyncTask { - private static final String STATUS_ENDPOINT = "https://comments.lbry.com"; - - private Comment comment; - private View progressView; - private CommentCreateWithTipHandler handler; + private final Comment comment; + private final View progressView; + private final CommentCreateWithTipHandler handler; private Exception error; public CommentCreateTask(Comment comment, View progressView, CommentCreateWithTipHandler handler) { @@ -46,29 +35,31 @@ public class CommentCreateTask extends AsyncTask { Comment createdComment = null; try { // check comments status endpoint - Request request = new Request.Builder().url(STATUS_ENDPOINT).build(); - OkHttpClient client = new OkHttpClient.Builder(). - writeTimeout(30, TimeUnit.SECONDS). - readTimeout(30, TimeUnit.SECONDS). - build(); - Response response = client.newCall(request).execute(); - JSONObject status = new JSONObject(response.body().string()); - String statusText = Helper.getJSONString("text", null, status); - boolean isRunning = Helper.getJSONBoolean("is_running", false, status); - if (!"ok".equalsIgnoreCase(statusText) || !isRunning) { - throw new ApiCallException("The comment server is not available at this time. Please try again later."); + Comments.checkCommentsEndpointStatus(); + + JSONObject comment_body = new JSONObject(); + comment_body.put("comment", comment.getText()); + comment_body.put("claim_id", comment.getClaimId()); + if (!Helper.isNullOrEmpty(comment.getParentId())) { + comment_body.put("parent_id", comment.getParentId()); + } + comment_body.put("channel_id", comment.getChannelId()); + comment_body.put("channel_name", comment.getChannelName()); + + JSONObject jsonChannelSign = Comments.channelSign(comment_body, comment.getChannelId(), comment.getChannelName()); + + if (jsonChannelSign.has("signature") && jsonChannelSign.has("signing_ts")) { + comment_body.put("signature", jsonChannelSign.getString("signature")); + comment_body.put("signing_ts", jsonChannelSign.getString("signing_ts")); } - Map options = new HashMap<>(); - options.put("comment", comment.getText()); - options.put("claim_id", comment.getClaimId()); - options.put("channel_id", comment.getChannelId()); - options.put("channel_name", comment.getChannelName()); - if (!Helper.isNullOrEmpty(comment.getParentId())) { - options.put("parent_id", comment.getParentId()); - } - JSONObject jsonObject = (JSONObject) Lbry.genericApiCall(Lbry.METHOD_COMMENT_CREATE, options); - createdComment = Comment.fromJSONObject(jsonObject); + Response resp = Comments.performRequest(comment_body, "comment.Create"); + String responseString = Objects.requireNonNull(resp.body()).string(); + resp.close(); + JSONObject jsonResponse = new JSONObject(responseString); + + if (jsonResponse.has("result")) + createdComment = Comment.fromJSONObject(jsonResponse.getJSONObject("result")); } catch (ApiCallException | ClassCastException | IOException | JSONException ex) { error = ex; } diff --git a/app/src/main/java/io/lbry/browser/tasks/CommentListTask.java b/app/src/main/java/io/lbry/browser/tasks/CommentListTask.java index 2833e003..36cf3131 100644 --- a/app/src/main/java/io/lbry/browser/tasks/CommentListTask.java +++ b/app/src/main/java/io/lbry/browser/tasks/CommentListTask.java @@ -14,6 +14,7 @@ import java.util.List; import java.util.Map; import io.lbry.browser.model.Comment; +import io.lbry.browser.utils.Comments; import io.lbry.browser.utils.Helper; import io.lbry.browser.utils.Lbry; @@ -21,8 +22,8 @@ public class CommentListTask extends AsyncTask> { private final int page; private final int pageSize; private final String claim; - private ProgressBar progressBar; - private CommentListHandler handler; + private final ProgressBar progressBar; + private final CommentListHandler handler; private Exception error; public CommentListTask(int page, int pageSize, String claim, ProgressBar progressBar, CommentListHandler handler) { @@ -52,7 +53,7 @@ public class CommentListTask extends AsyncTask> { options.put("skip_validation", true); options.put("visible", true); - JSONObject result = (JSONObject) Lbry.genericApiCall(Lbry.METHOD_COMMENT_LIST, options); + JSONObject result = (JSONObject) Lbry.parseResponse(Comments.performRequest(Lbry.buildJsonParams(options), "comment.List")); JSONArray items = result.getJSONArray("items"); List children = new ArrayList<>(); diff --git a/app/src/main/java/io/lbry/browser/utils/Comments.java b/app/src/main/java/io/lbry/browser/utils/Comments.java new file mode 100644 index 00000000..47d86fc6 --- /dev/null +++ b/app/src/main/java/io/lbry/browser/utils/Comments.java @@ -0,0 +1,99 @@ +package io.lbry.browser.utils; + +import android.os.Build; + +import org.apache.commons.codec.binary.Hex; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +import io.lbry.browser.exceptions.ApiCallException; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; + +public class Comments { + private static final String STATUS_ENDPOINT = "https://comments.lbry.com"; + public static final String COMMENT_SERVER_ENDPOINT = "https://comments.lbry.com/api/v2"; + + public static JSONObject channelSign(JSONObject commentBody, String channelId, String channelName) throws ApiCallException, JSONException { + byte[] commentBodyBytes = commentBody.getString("comment").getBytes(StandardCharsets.UTF_8); + String encodedCommentBody; + + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O_MR1) + encodedCommentBody = Hex.encodeHexString(commentBodyBytes, false); + else + encodedCommentBody = new String(Hex.encodeHex(commentBodyBytes)); + + Map signingParams = new HashMap<>(3); + signingParams.put("hexdata", encodedCommentBody); + signingParams.put("channel_id", channelId); + signingParams.put("channel_name", channelName); + + return (JSONObject) Lbry.genericApiCall("channel_sign", signingParams); + } + + /** + * Performs request to default Comment Server + * @param params JSON containing parameters to send to the server + * @param method One of the available methods for comments + * @return Response from the server + * @throws IOException throwable from OkHttpClient execute() + */ + public static Response performRequest(JSONObject params, String method) throws IOException { + return performRequest(COMMENT_SERVER_ENDPOINT, params, method); + } + + /** + * Performs the request to Comment Server + * @param commentServer Url where to direct the request + * @param params JSON containing parameters to send to the server + * @param method One of the available methods for comments + * @return Response from the server + * @throws IOException throwable from OkHttpClient execute() + */ + public static Response performRequest(String commentServer, JSONObject params, String method) throws IOException { + final MediaType JSON = MediaType.get("application/json; charset=utf-8"); + + Map requestParams = new HashMap<>(4); + requestParams.put("jsonrpc", "2.0"); + requestParams.put("id", TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())); + requestParams.put("method", method); + requestParams.put("params", params); + + RequestBody requestBody = RequestBody.create(Lbry.buildJsonParams(requestParams).toString(), JSON); + + Request commentCreateRequest = new Request.Builder() + .url(commentServer.concat("?m=").concat(method)) + .post(requestBody) + .build(); + + OkHttpClient client = new OkHttpClient.Builder().writeTimeout(30, TimeUnit.SECONDS) + .readTimeout(30, TimeUnit.SECONDS) + .build(); + + return client.newCall(commentCreateRequest).execute(); + } + + public static void checkCommentsEndpointStatus() throws IOException, JSONException, ApiCallException { + Request request = new Request.Builder().url(STATUS_ENDPOINT).build(); + OkHttpClient client = new OkHttpClient.Builder().writeTimeout(30, TimeUnit.SECONDS) + .readTimeout(30, TimeUnit.SECONDS) + .build(); + Response response = client.newCall(request).execute(); + JSONObject status = new JSONObject(Objects.requireNonNull(response.body()).string()); + String statusText = Helper.getJSONString("text", null, status); + boolean isRunning = Helper.getJSONBoolean("is_running", false, status); + if (!"ok".equalsIgnoreCase(statusText) || !isRunning) { + throw new ApiCallException("The comment server is not available at this time. Please try again later."); + } + } +}