Performance (#626)

This commit is contained in:
Akinwale Ariwodola 2019-08-09 07:42:21 +01:00 committed by GitHub
parent 57691fcd99
commit d266b9f55b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 390 additions and 85 deletions

2
app

@ -1 +1 @@
Subproject commit 60b4210c530e82b6f6d47e0b4e41b35fe24a2617
Subproject commit 836ff2ae134d3cd3b114b88a64a7cdd0900582c9

View file

@ -74,8 +74,6 @@ public class LbrynetService extends PythonService {
public static LbrynetService serviceInstance;
private static final String SDK_URL = "http://127.0.0.1:5279";
private static final int SDK_POLL_INTERVAL = 500; // 500 milliseconds
private BroadcastReceiver stopServiceReceiver;
@ -192,86 +190,10 @@ public class LbrynetService extends PythonService {
}
}
private String sdkCall(String method) throws ConnectException {
return sdkCall(method, null);
}
private String sdkCall(String method, Map<String, String> params) throws ConnectException {
BufferedReader reader = null;
DataOutputStream dos = null;
HttpURLConnection conn = null;
try {
JSONObject request = new JSONObject();
request.put("method", method);
if (params != null) {
JSONObject requestParams = new JSONObject();
for (Map.Entry<String, String> entry : params.entrySet()) {
requestParams.put(entry.getKey(), entry.getValue());
}
request.put("params", requestParams);
}
URL url = new URL(SDK_URL);
conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-type", "application/json");
dos = new DataOutputStream(conn.getOutputStream());
dos.writeBytes(request.toString());
dos.flush();
dos.close();
if (conn.getResponseCode() == 200) {
reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
StringBuilder sb = new StringBuilder();
String input;
while ((input = reader.readLine()) != null) {
sb.append(input);
}
return sb.toString();
} else {
reader = new BufferedReader(new InputStreamReader(conn.getErrorStream(), "utf-8"));
StringBuilder sb = new StringBuilder();
String error;
while ((error = reader.readLine()) != null) {
sb.append(error);
}
return sb.toString();
}
} catch (ConnectException ex) {
// sdk not started yet. rethrow
throw ex;
} catch (IOException ex) {
Log.e(TAG, ex.getMessage(), ex);
// ignore and continue
} catch (Exception ex) {
Log.e(TAG, ex.getMessage(), ex);
// ignore
} finally {
try {
if (reader != null) {
reader.close();
}
if (conn != null) {
conn.disconnect();
}
} catch (IOException ex) {
// pass
}
}
return null;
}
private void pollFileList() {
try {
if (!streamManagerReady) {
String statusResponse = sdkCall("status");
String statusResponse = Utils.sdkCall("status");
if (statusResponse != null) {
JSONObject status = new JSONObject(statusResponse);
if (status.has("error")) {
@ -288,7 +210,7 @@ public class LbrynetService extends PythonService {
}
if (streamManagerReady) {
String fileList = sdkCall("file_list");
String fileList = Utils.sdkCall("file_list");
if (fileList != null) {
JSONObject response = new JSONObject(fileList);
if (!response.has("error")) {
@ -309,7 +231,7 @@ public class LbrynetService extends PythonService {
try {
Map<String, String> params = new HashMap<String, String>();
params.put("outpoint", outpoint);
return sdkCall("file_list", params);
return Utils.sdkCall("file_list", params);
} catch (ConnectException ex) {
return null;
}

View file

@ -10,7 +10,14 @@ import io.lbry.browser.BuildConfig;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.DataOutputStream;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.security.InvalidAlgorithmParameterException;
@ -21,6 +28,7 @@ import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Map;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
@ -28,6 +36,9 @@ import javax.crypto.CipherOutputStream;
import javax.crypto.spec.SecretKeySpec;
import javax.security.auth.x500.X500Principal;
import org.json.JSONObject;
import org.json.JSONException;
public final class Utils {
private static final String TAG = Utils.class.getName();
@ -46,6 +57,8 @@ public final class Utils {
private static final String SP_API_SECRET_KEY = "api_secret";
public static final String SDK_URL = "http://127.0.0.1:5279";
public static String getAndroidRelease() {
return android.os.Build.VERSION.RELEASE;
}
@ -243,6 +256,105 @@ public final class Utils {
return ks;
}
public static String performRequest(String url) throws ConnectException {
return performRequest(url, "GET", null);
}
public static String performRequest(String requestUrl, String requestMethod, String json) throws ConnectException {
BufferedReader reader = null;
DataOutputStream dos = null;
HttpURLConnection conn = null;
try {
URL url = new URL(requestUrl);
conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.setUseCaches(false);
conn.setRequestMethod(requestMethod);
if ("POST".equals(requestMethod)) {
conn.setDoOutput(true);
conn.setRequestProperty("Content-type", "application/json");
}
if (json != null) {
dos = new DataOutputStream(conn.getOutputStream());
dos.writeBytes(json);
dos.flush();
dos.close();
}
if (conn.getResponseCode() == 200) {
reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
StringBuilder sb = new StringBuilder();
String input;
while ((input = reader.readLine()) != null) {
sb.append(input);
}
return sb.toString();
} else {
reader = new BufferedReader(new InputStreamReader(conn.getErrorStream(), "utf-8"));
StringBuilder sb = new StringBuilder();
String error;
while ((error = reader.readLine()) != null) {
sb.append(error);
}
return sb.toString();
}
} catch (ConnectException ex) {
// unable to connect. rethrow
throw ex;
} catch (IOException ex) {
Log.e(TAG, ex.getMessage(), ex);
// pass
} catch (Exception ex) {
Log.e(TAG, ex.getMessage(), ex);
// pass
} finally {
try {
if (reader != null) {
reader.close();
}
if (conn != null) {
conn.disconnect();
}
} catch (IOException ex) {
// pass
}
}
return null;
}
public static String sdkCall(String method) throws ConnectException {
return sdkCall(method, null);
}
public static String sdkCall(String method, Map<String, String> params) throws ConnectException {
try {
JSONObject request = new JSONObject();
request.put("method", method);
if (params != null) {
JSONObject requestParams = new JSONObject();
for (Map.Entry<String, String> entry : params.entrySet()) {
requestParams.put(entry.getKey(), entry.getValue());
}
request.put("params", requestParams);
}
return performRequest(SDK_URL, "POST", request.toString());
} catch (ConnectException ex) {
// sdk not started yet. rethrow
throw ex;
} catch (JSONException ex) {
// normally shouldn't happen
Log.e(TAG, ex.getMessage(), ex);
// pass
}
return null;
}
private static byte[] rsaEncrypt(byte[] secret, KeyStore keyStore) throws Exception {
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(KEY_ALIAS, null);

View file

@ -0,0 +1,74 @@
package io.lbry.browser.reactmodules;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableMapKeySetIterator;
import com.facebook.react.bridge.ReadableType;
import com.facebook.react.bridge.WritableMap;
import io.lbry.browser.MainActivity;
import io.lbry.browser.Utils;
import java.util.List;
import java.util.ArrayList;
import org.json.JSONObject;
import org.json.JSONArray;
import org.json.JSONException;
public class RequestsModule extends ReactContextBaseJavaModule {
private Context context;
public RequestsModule(ReactApplicationContext reactContext) {
super(reactContext);
this.context = reactContext;
}
@Override
public String getName() {
return "Requests";
}
@ReactMethod
public void get(final String url, final Promise promise) {
(new AsyncTask<Void, Void, String>() {
@Override
protected String doInBackground(Void... params) {
try {
return Utils.performRequest(url);
} catch (Exception ex) {
return null;
}
}
protected void onPostExecute(String response) {
if (response == null) {
promise.reject(String.format("Request to %s returned null.", url));
return;
}
promise.resolve(response);
}
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
@ReactMethod
public void lbryioCall(String authToken, final Promise promise) {
// get the auth token here, or let the app pass it in?
}
@ReactMethod
public void lbryCall(final Promise promise) {
}
}

View file

@ -0,0 +1,193 @@
package io.lbry.browser.reactmodules;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableMapKeySetIterator;
import com.facebook.react.bridge.ReadableType;
import com.facebook.react.bridge.WritableMap;
import io.lbry.browser.MainActivity;
import java.util.List;
import java.util.ArrayList;
import org.json.JSONObject;
import org.json.JSONArray;
import org.json.JSONException;
public class StatePersistorModule extends ReactContextBaseJavaModule {
private Context context;
private List<ReadableMap> queue;
private ReadableMap filter;
private ReadableMap lastState;
private AsyncTask persistTask;
public StatePersistorModule(ReactApplicationContext reactContext) {
super(reactContext);
this.context = reactContext;
queue = new ArrayList<ReadableMap>();
}
@Override
public String getName() {
return "StatePersistor";
}
/*private WritableMap filterState(ReadableMap state) {
WritableMap filteredState = Arguments.createMap();
return state;
}*/
public boolean hasStateChanged(ReadableMap newState) {
return false;
}
@ReactMethod
public void update(ReadableMap state, ReadableMap filter) {
if (this.filter == null) {
this.filter = filter;
}
// process state updates from the queue using a background task
synchronized (this) {
queue.add(state);
}
persistState();
}
private void persistState() {
persistState(false);
}
private void persistState(final boolean flush) {
if (flush && persistTask != null) {
persistTask.cancel(true);
persistTask = null;
}
if (persistTask == null) {
persistTask = (new AsyncTask<Object, Void, Boolean>() {
protected Boolean doInBackground(Object... param) {
// get the first item in the queue
ReadableMap queuedState = null;
if (queue.size() > 0) {
synchronized (StatePersistorModule.this) {
queuedState = queue.remove(flush ? queue.size() - 1 : 0);
if (flush) {
// we only want the final state in this scenario
queue.clear();
}
}
}
if (queuedState != null) {
ReadableMap state = queuedState; //(ReadableMap) filterState(queuedState);
// convert to JSON object
try {
JSONObject json = readableMapToJSON(state);
// save the state file
// TODO: explore this option at a later date
throw new UnsupportedOperationException();
} catch (JSONException ex) {
// normally shouldn't happen, but if it does, reinsert into the queue
if (queuedState != null) {
synchronized (StatePersistorModule.this) {
queue.add(0, queuedState);
}
}
return false;
}
}
return false;
}
public void onPostExecute(Boolean result) {
if (queue.size() > 0) {
persistState();
}
persistTask = null;
}
});
persistTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
@ReactMethod
public void flush() {
persistState(true);
}
private static JSONObject readableMapToJSON(ReadableMap readableMap) throws JSONException {
JSONObject json = new JSONObject();
ReadableMapKeySetIterator iterator = readableMap.keySetIterator();
while (iterator.hasNextKey()) {
String key = iterator.nextKey();
switch (readableMap.getType(key)) {
case Map:
json.put(key, readableMapToJSON(readableMap.getMap(key)));
break;
case Array:
json.put(key, readableArrayToJSON(readableMap.getArray(key)));
break;
case Boolean:
json.put(key, readableMap.getBoolean(key));
break;
case Null:
json.put(key, JSONObject.NULL);
break;
case Number:
json.put(key, readableMap.getDouble(key));
break;
case String:
json.put(key, readableMap.getString(key));
break;
}
}
return json;
}
private static JSONArray readableArrayToJSON(ReadableArray readableArray) throws JSONException {
JSONArray array = new JSONArray();
for (int i = 0; i < readableArray.size(); i++) {
switch (readableArray.getType(i)) {
case Null:
break;
case Boolean:
array.put(readableArray.getBoolean(i));
break;
case Number:
array.put(readableArray.getDouble(i));
break;
case String:
array.put(readableArray.getString(i));
break;
case Map:
array.put(readableMapToJSON(readableArray.getMap(i)));
break;
case Array:
array.put(readableArrayToJSON(readableArray.getArray(i)));
break;
}
}
return array;
}
}

View file

@ -10,9 +10,11 @@ import io.lbry.browser.reactmodules.DaemonServiceControlModule;
import io.lbry.browser.reactmodules.FirstRunModule;
import io.lbry.browser.reactmodules.FirebaseModule;
import io.lbry.browser.reactmodules.GalleryModule;
import io.lbry.browser.reactmodules.RequestsModule;
import io.lbry.browser.reactmodules.ScreenOrientationModule;
import io.lbry.browser.reactmodules.StatePersistorModule;
import io.lbry.browser.reactmodules.VersionInfoModule;
import io.lbry.browser.reactmodules.UtilityModule;;
import io.lbry.browser.reactmodules.UtilityModule;
import java.util.ArrayList;
import java.util.Collections;
@ -33,7 +35,9 @@ public class LbryReactPackage implements ReactPackage {
modules.add(new FirstRunModule(reactContext));
modules.add(new FirebaseModule(reactContext));
modules.add(new GalleryModule(reactContext));
modules.add(new RequestsModule(reactContext));
modules.add(new ScreenOrientationModule(reactContext));
modules.add(new StatePersistorModule(reactContext));
modules.add(new UtilityModule(reactContext));
modules.add(new VersionInfoModule(reactContext));