Exposing an interface that allows the fine tuning of the alpha parameter used to calculate the exponential moving average of measured latencies
This commit is contained in:
parent
3a19808ac5
commit
63eebf11c4
5 changed files with 91 additions and 13 deletions
|
@ -58,6 +58,7 @@ import cy.agorise.graphenej.network.NodeProvider;
|
|||
import cy.agorise.graphenej.operations.CustomOperation;
|
||||
import cy.agorise.graphenej.operations.LimitOrderCreateOperation;
|
||||
import cy.agorise.graphenej.operations.TransferOperation;
|
||||
import cy.agorise.graphenej.stats.ExponentialMovingAverage;
|
||||
import io.reactivex.Observer;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.annotations.Nullable;
|
||||
|
@ -79,29 +80,69 @@ public class NetworkService extends Service {
|
|||
public static final int NORMAL_CLOSURE_STATUS = 1000;
|
||||
|
||||
// Time to wait before retrying a connection attempt
|
||||
private final int DEFAULT_RETRY_DELAY = 5000;
|
||||
private final int DEFAULT_RETRY_DELAY = 500;
|
||||
|
||||
/**
|
||||
* Constant to be used as a key in order to pass the user name information, in case the
|
||||
* provided API nodes might require this information.
|
||||
*/
|
||||
public static final String KEY_USERNAME = "key_username";
|
||||
|
||||
/**
|
||||
* Constant to be used as a key in order to pass the password information, in case the
|
||||
* provided API nodes might require this information.
|
||||
* <p>
|
||||
* This information should be passed as an intent extra when calling the bindService
|
||||
* or startService methods.
|
||||
*/
|
||||
public static final String KEY_PASSWORD = "key_password";
|
||||
|
||||
/**
|
||||
* Constant used as a key in order to specify which APIs the application will be requiring.
|
||||
* <p>
|
||||
* This information should be passed as an intent extra when calling the bindService
|
||||
* or startService methods.
|
||||
*/
|
||||
public static final String KEY_REQUESTED_APIS = "key_requested_apis";
|
||||
|
||||
/**
|
||||
* Constant used as a key in order to let the NetworkService know whether or not it should
|
||||
* start a recurring node latency verification task.
|
||||
* <p>
|
||||
* This information should be passed as an intent extra when calling the bindService
|
||||
* or startService methods.
|
||||
*/
|
||||
public static final String KEY_ENABLE_LATENCY_VERIFIER = "key_enable_latency_verifier";
|
||||
|
||||
/**
|
||||
* Constant used as a key in order to specify the alpha (or smoothing) factor to be used in
|
||||
* the exponential moving average calculated from the different latency samples. This only
|
||||
* makes sense if the latency verification feature is enabled of course.
|
||||
* <p>
|
||||
* This information should be passed as an intent extra when calling the bindService
|
||||
* or startService methods.
|
||||
*/
|
||||
public static final String KEY_NODE_LATENCY_SMOOTHING_FACTOR = "key_node_latency_smoothing_factor";
|
||||
|
||||
/**
|
||||
* Key used to pass via intent a boolean extra to specify whether the connection should
|
||||
* be automatically established.
|
||||
* <p>
|
||||
* This information should be passed as an intent extra when calling the bindService
|
||||
* or startService methods.
|
||||
*/
|
||||
public static final String KEY_AUTO_CONNECT = "key_auto_connect";
|
||||
|
||||
/**
|
||||
* Key used to pass via intent a list of node URLs. The value passed should be a String
|
||||
* containing a simple comma separated list of URLs.
|
||||
*
|
||||
* <p>
|
||||
* For example:
|
||||
*
|
||||
* wss://domain1.com/ws,wss://domain2.com/ws,wss://domain3.com/ws
|
||||
* <p>
|
||||
* This information should be passed as an intent extra when calling the bindService
|
||||
* or startService methods.
|
||||
*/
|
||||
public static final String KEY_NODE_URLS = "key_node_urls";
|
||||
|
||||
|
@ -264,9 +305,10 @@ public class NetworkService extends Service {
|
|||
// a first round of measurements in order to be sure to select the
|
||||
// best node.
|
||||
if(verifyNodeLatency){
|
||||
double alpha = extras.getDouble(KEY_NODE_LATENCY_SMOOTHING_FACTOR, ExponentialMovingAverage.DEFAULT_ALPHA);
|
||||
ArrayList<FullNode> fullNodes = new ArrayList<>();
|
||||
for(String url : urls){
|
||||
fullNodes.add(new FullNode(url));
|
||||
fullNodes.add(new FullNode(url, alpha));
|
||||
}
|
||||
nodeLatencyVerifier = new NodeLatencyVerifier(fullNodes);
|
||||
fullNodePublishSubject = nodeLatencyVerifier.start();
|
||||
|
|
|
@ -15,6 +15,8 @@ import java.util.ArrayList;
|
|||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import cy.agorise.graphenej.stats.ExponentialMovingAverage;
|
||||
|
||||
/**
|
||||
* This class should be instantiated at the application level of the android app.
|
||||
*
|
||||
|
@ -52,6 +54,7 @@ public class NetworkServiceManager implements Application.ActivityLifecycleCallb
|
|||
private List<String> mCustomNodeUrls = new ArrayList<>();
|
||||
private boolean mAutoConnect;
|
||||
private boolean mVerifyLatency;
|
||||
private double alpha;
|
||||
|
||||
/**
|
||||
* Runnable used to schedule a service disconnection once the app is not visible to the user for
|
||||
|
@ -194,6 +197,7 @@ public class NetworkServiceManager implements Application.ActivityLifecycleCallb
|
|||
private List<String> customNodeUrls;
|
||||
private boolean autoconnect = true;
|
||||
private boolean verifyNodeLatency;
|
||||
private double alpha = ExponentialMovingAverage.DEFAULT_ALPHA;
|
||||
|
||||
/**
|
||||
* Sets the user name, if required to connect to a node.
|
||||
|
@ -269,6 +273,17 @@ public class NetworkServiceManager implements Application.ActivityLifecycleCallb
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the node latency verification's exponential moving average alpha parameter.
|
||||
* @param alpha The alpha parameter to use when computing the exponential moving average of the
|
||||
* measured latencies.
|
||||
* @return The Builder instance.
|
||||
*/
|
||||
public Builder setLatencyAverageAlpha(double alpha){
|
||||
this.alpha = alpha;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method used to build a {@link NetworkServiceManager} instance with all of the characteristics
|
||||
* passed as parameters.
|
||||
|
|
|
@ -8,14 +8,35 @@ import cy.agorise.graphenej.stats.ExponentialMovingAverage;
|
|||
public class FullNode implements Comparable {
|
||||
|
||||
private String mUrl;
|
||||
private ExponentialMovingAverage latency;
|
||||
private ExponentialMovingAverage mLatency;
|
||||
private boolean isConnected;
|
||||
|
||||
private FullNode(){}
|
||||
|
||||
/**
|
||||
* Constructor used to specify both the node URL and the alpha parameter that one wishes to set the
|
||||
* exponential moving average with.
|
||||
* <p>
|
||||
* The alpha parameter represents the degree of weighting decrease, and can be specified as any value
|
||||
* between 0 and 1. A higher alpha discounts older observations faster.
|
||||
*
|
||||
* @param url The node URL.
|
||||
* @param alpha The alpha parameter used to compute the exponential moving average.
|
||||
*/
|
||||
public FullNode(String url, double alpha){
|
||||
mLatency = new ExponentialMovingAverage(alpha);
|
||||
mUrl = url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor used to specify only the node URL.
|
||||
* <p>
|
||||
* The alpha parameter is set to the value specified at {@link ExponentialMovingAverage#DEFAULT_ALPHA}
|
||||
*
|
||||
* @param url The node URL.
|
||||
*/
|
||||
public FullNode(String url){
|
||||
latency = new ExponentialMovingAverage(ExponentialMovingAverage.DEFAULT_ALPHA);
|
||||
this.mUrl = url;
|
||||
this(url, ExponentialMovingAverage.DEFAULT_ALPHA);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -39,7 +60,7 @@ public class FullNode implements Comparable {
|
|||
* @return The exponential moving average object instance
|
||||
*/
|
||||
public ExponentialMovingAverage getLatencyAverage(){
|
||||
return latency;
|
||||
return mLatency;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -47,7 +68,7 @@ public class FullNode implements Comparable {
|
|||
* @return The latest latency average value
|
||||
*/
|
||||
public double getLatencyValue() {
|
||||
return latency.getAverage();
|
||||
return mLatency.getAverage();
|
||||
}
|
||||
|
||||
public boolean isConnected() {
|
||||
|
@ -59,17 +80,17 @@ public class FullNode implements Comparable {
|
|||
}
|
||||
|
||||
/**
|
||||
* Method that updates the latency average with a new value.
|
||||
* @param latency Most recent latency sample to be added to the exponential average
|
||||
* Method that updates the mLatency average with a new value.
|
||||
* @param latency Most recent mLatency sample to be added to the exponential average
|
||||
*/
|
||||
public void addLatencyValue(double latency) {
|
||||
this.latency.updateValue(latency);
|
||||
this.mLatency.updateValue(latency);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Object o) {
|
||||
FullNode node = (FullNode) o;
|
||||
return (int) Math.ceil(latency.getAverage() - node.getLatencyValue());
|
||||
return (int) Math.ceil(mLatency.getAverage() - node.getLatencyValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -154,7 +154,6 @@ public class NodeLatencyVerifier {
|
|||
long before = timestamps.get(fullNode);
|
||||
delay = after - before;
|
||||
}
|
||||
|
||||
fullNode.addLatencyValue(delay);
|
||||
subject.onNext(fullNode);
|
||||
}else{
|
||||
|
|
|
@ -38,6 +38,7 @@ public class SampleApplication extends Application {
|
|||
.setCustomNodeUrls(nodes)
|
||||
.setAutoConnect(true)
|
||||
.setNodeLatencyVerification(true)
|
||||
.setLatencyAverageAlpha(0.1f)
|
||||
.build(this);
|
||||
|
||||
// Registering this class as a listener to all activity's callback cycle events, in order to
|
||||
|
|
Loading…
Reference in a new issue