diff --git a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/GrapheneApiGenerator.java b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/GrapheneApiGenerator.java index 8272895..1e58d06 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/apigenerator/GrapheneApiGenerator.java +++ b/app/src/main/java/cy/agorise/crystalwallet/apigenerator/GrapheneApiGenerator.java @@ -12,12 +12,14 @@ import cy.agorise.crystalwallet.dao.BitsharesAssetDao; import cy.agorise.crystalwallet.dao.CryptoCoinBalanceDao; import cy.agorise.crystalwallet.dao.CryptoCurrencyDao; import cy.agorise.crystalwallet.dao.CrystalDatabase; +import cy.agorise.crystalwallet.enums.CryptoNet; import cy.agorise.crystalwallet.models.BitsharesAsset; import cy.agorise.crystalwallet.models.BitsharesAssetInfo; import cy.agorise.crystalwallet.models.CryptoCoinBalance; import cy.agorise.crystalwallet.models.CryptoCoinTransaction; import cy.agorise.crystalwallet.models.CryptoCurrency; import cy.agorise.crystalwallet.models.CryptoCurrencyEquivalence; +import cy.agorise.crystalwallet.network.CryptoNetManager; import cy.agorise.crystalwallet.network.WebSocketThread; import cy.agorise.graphenej.Address; import cy.agorise.graphenej.Asset; @@ -58,12 +60,8 @@ public abstract class GrapheneApiGenerator { //TODO network connections //TODO make to work with all Graphene type, not only bitshares - public static String url = "http://185.208.208.147:11012"; public static String faucetUrl = "http://185.208.208.147:5010"; - private static String equivalentUrl = "http://185.208.208.147:8090"; - //public static String url = "wss://bitshares.openledger.info/ws"; - //private static Str ing equivalentUrl = "wss://bitshares.openledger.info/ws"; - + private static String equivalentUrl = "wss://bitshares.openledger.info/ws"; // The message broker for bitshares private static SubscriptionMessagesHub bitsharesSubscriptionHub = new SubscriptionMessagesHub("", "", true, new NodeErrorListener() { @@ -77,7 +75,7 @@ public abstract class GrapheneApiGenerator { /** * The subscription thread for the real time updates */ - private static WebSocketThread subscriptionThread = new WebSocketThread(bitsharesSubscriptionHub,url); + private static WebSocketThread subscriptionThread = new WebSocketThread(bitsharesSubscriptionHub, CryptoNetManager.getURL(CryptoNet.BITSHARES)); /** * This is used for manager each listener in the subscription thread */ @@ -110,7 +108,7 @@ public abstract class GrapheneApiGenerator { public void onError(BaseResponse.Error error) { request.getListener().fail(request.getId()); } - }),url); + }),CryptoNetManager.getURL(CryptoNet.BITSHARES)); thread.start(); } @@ -138,7 +136,7 @@ public abstract class GrapheneApiGenerator { public void onError(BaseResponse.Error error) { request.getListener().fail(request.getId()); } - }),url); + }),CryptoNetManager.getURL(CryptoNet.BITSHARES)); thread.start(); } @@ -165,7 +163,7 @@ public abstract class GrapheneApiGenerator { public void onError(BaseResponse.Error error) { request.getListener().fail(request.getId()); } - }),url); + }),CryptoNetManager.getURL(CryptoNet.BITSHARES)); thread.start(); } @@ -192,7 +190,7 @@ public abstract class GrapheneApiGenerator { public void onError(BaseResponse.Error error) { request.getListener().fail(request.getId()); } - }),url); + }),CryptoNetManager.getURL(CryptoNet.BITSHARES)); thread.start(); } @@ -219,7 +217,7 @@ public abstract class GrapheneApiGenerator { public void onError(BaseResponse.Error error) { request.getListener().fail(request.getId()); } - }),url); + }),CryptoNetManager.getURL(CryptoNet.BITSHARES)); thread.start(); } @@ -243,7 +241,7 @@ public abstract class GrapheneApiGenerator { public void onError(BaseResponse.Error error) { request.getListener().fail(request.getId()); } - }),url); + }),CryptoNetManager.getURL(CryptoNet.BITSHARES)); thread.start(); } @@ -288,7 +286,7 @@ public abstract class GrapheneApiGenerator { public void onError(BaseResponse.Error error) { request.getListener().fail(request.getId()); } - }),url); + }),CryptoNetManager.getURL(CryptoNet.BITSHARES)); thread.start(); } @@ -336,7 +334,7 @@ public abstract class GrapheneApiGenerator { public void onError(BaseResponse.Error error) { request.getListener().fail(request.getId()); } - }),url); + }),CryptoNetManager.getURL(CryptoNet.BITSHARES)); thread.start(); } @@ -509,7 +507,7 @@ public abstract class GrapheneApiGenerator { public void onError(BaseResponse.Error error) { } - }),url); + }),CryptoNetManager.getURL(CryptoNet.BITSHARES)); thread.start(); @@ -536,7 +534,7 @@ public abstract class GrapheneApiGenerator { public void onError(BaseResponse.Error error) { request.getListener().fail(request.getId()); } - }),url); + }),CryptoNetManager.getURL(CryptoNet.BITSHARES)); thread.start(); } diff --git a/app/src/main/java/cy/agorise/crystalwallet/application/CrystalApplication.java b/app/src/main/java/cy/agorise/crystalwallet/application/CrystalApplication.java index fc5f6c7..8b55ef4 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/application/CrystalApplication.java +++ b/app/src/main/java/cy/agorise/crystalwallet/application/CrystalApplication.java @@ -6,6 +6,8 @@ import android.content.Intent; import com.idescout.sql.SqlScoutServer; import cy.agorise.crystalwallet.dao.CrystalDatabase; +import cy.agorise.crystalwallet.enums.CryptoNet; +import cy.agorise.crystalwallet.network.CryptoNetManager; import cy.agorise.crystalwallet.service.CrystalWalletService; /** @@ -15,6 +17,20 @@ import cy.agorise.crystalwallet.service.CrystalWalletService; */ public class CrystalApplication extends Application { + public static String BITSHARES_URL[] = + { + "wss://de.palmpay.io/ws", // Custom node + "wss://bitshares.nu/ws", + "wss://dexnode.net/ws", // Dallas, USA + "wss://bitshares.crypto.fans/ws", // Munich, Germany + "wss://bitshares.openledger.info/ws", // Openledger node + "ws://185.208.208.147:8090" // Custom node + }; + + public static String BITSHARES_TESTNET_URL[] = + { + "http://185.208.208.147:11012", // Openledger node + }; @Override public void onCreate() { @@ -24,6 +40,11 @@ public class CrystalApplication extends Application { CrystalDatabase db = CrystalDatabase.getAppDatabase(this.getApplicationContext()); SqlScoutServer.create(this, getPackageName()); + //Using Bitshares Agorise Testnet + CryptoNetManager.addCryptoNetURL(CryptoNet.BITSHARES,BITSHARES_TESTNET_URL); + //Next line is for use the bitshares main net + //CryptoNetManager.addCryptoNetURL(CryptoNet.BITSHARES,BITSHARES_URL); + Intent intent = new Intent(getApplicationContext(), CrystalWalletService.class); startService(intent); } diff --git a/app/src/main/java/cy/agorise/crystalwallet/manager/BitsharesAccountManager.java b/app/src/main/java/cy/agorise/crystalwallet/manager/BitsharesAccountManager.java index da9b514..5b1a248 100644 --- a/app/src/main/java/cy/agorise/crystalwallet/manager/BitsharesAccountManager.java +++ b/app/src/main/java/cy/agorise/crystalwallet/manager/BitsharesAccountManager.java @@ -36,6 +36,7 @@ import cy.agorise.crystalwallet.models.CryptoCurrency; import cy.agorise.crystalwallet.models.CryptoNetAccount; import cy.agorise.crystalwallet.models.GrapheneAccount; import cy.agorise.crystalwallet.models.GrapheneAccountInfo; +import cy.agorise.crystalwallet.network.CryptoNetManager; import cy.agorise.graphenej.Address; import cy.agorise.graphenej.Asset; import cy.agorise.graphenej.AssetAmount; @@ -56,7 +57,7 @@ import cy.agorise.graphenej.operations.TransferOperationBuilder; */ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetInfoRequestsListener { - private final static String BITSHARES_TESTNET_CHAIN_ID= "9cf6f255a208100d2bb275a3c52f4b1589b7ec9c9bfc2cb2a5fe6411295106d8"; + //private final static String BITSHARES_TESTNET_CHAIN_ID= "9cf6f255a208100d2bb275a3c52f4b1589b7ec9c9bfc2cb2a5fe6411295106d8"; private final static String SIMPLE_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss"; private final static String DEFAULT_TIME_ZONE = "GMT"; @@ -395,7 +396,7 @@ public class BitsharesAccountManager implements CryptoAccountManager, CryptoNetI ECKey privateKey = sendRequest.getSourceAccount().getActiveKey(sendRequest.getContext()); Transaction transaction = new Transaction(privateKey, null, operationList); - transaction.setChainId(BITSHARES_TESTNET_CHAIN_ID); + transaction.setChainId(CryptoNetManager.getChaindId(CryptoNet.BITSHARES)); ApiRequest transactionRequest = new ApiRequest(0, new ApiRequestListener() { @Override diff --git a/app/src/main/java/cy/agorise/crystalwallet/network/BitsharesCryptoNetVerifier.java b/app/src/main/java/cy/agorise/crystalwallet/network/BitsharesCryptoNetVerifier.java new file mode 100644 index 0000000..8a47bce --- /dev/null +++ b/app/src/main/java/cy/agorise/crystalwallet/network/BitsharesCryptoNetVerifier.java @@ -0,0 +1,54 @@ +package cy.agorise.crystalwallet.network; + +import cy.agorise.crystalwallet.enums.CryptoNet; +import cy.agorise.graphenej.interfaces.WitnessResponseListener; +import cy.agorise.graphenej.models.BaseResponse; +import cy.agorise.graphenej.models.WitnessResponse; + +/** + * + * Created by henry on 28/2/2018. + */ + +public class BitsharesCryptoNetVerifier extends CryptoNetVerifier { + + + /** + * TODO We need to change this to a type of subCryptoNet + */ + private final CryptoNet cryptoNet = CryptoNet.BITSHARES; + /** + * Todo info need to be on the SubCryptoNet + */ + private final String CHAIN_ID = "9cf6f255a208100d2bb275a3c52f4b1589b7ec9c9bfc2cb2a5fe6411295106d8";//testnet + //private final String CHAIN_ID = "4018d7844c78f6a6c41c6a552b898022310fc5dec06da467ee7905a8dad512c8";//mainnet + + @Override + public void checkURL(final String url) { + final long startTime = System.currentTimeMillis(); + WebSocketThread thread = new WebSocketThread(new GetChainId(new WitnessResponseListener() { + @Override + public void onSuccess(WitnessResponse response) { + if(response.result instanceof String) { + if(response.result.equals(CHAIN_ID)) { + CryptoNetManager.verifiedCryptoNetURL(cryptoNet, url, System.currentTimeMillis() - startTime); + }else{ + System.out.println(" BitsharesCryptoNetVerifier Error we are not in the net current chain id " + response.result + " excepted " + CHAIN_ID); + //TODO handle error bad chain + } + } + } + + @Override + public void onError(BaseResponse.Error error) { + //TODO handle error + } + }),url); + thread.start(); + } + + @Override + public String getChainId() { + return CHAIN_ID; + } +} diff --git a/app/src/main/java/cy/agorise/crystalwallet/network/CryptoNetManager.java b/app/src/main/java/cy/agorise/crystalwallet/network/CryptoNetManager.java new file mode 100644 index 0000000..c112f9f --- /dev/null +++ b/app/src/main/java/cy/agorise/crystalwallet/network/CryptoNetManager.java @@ -0,0 +1,155 @@ +package cy.agorise.crystalwallet.network; + +import android.support.annotation.NonNull; +import android.util.Log; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; + +import cy.agorise.crystalwallet.enums.CryptoNet; + +/** + * Created by henry on 6/3/2018. + */ + +public abstract class CryptoNetManager { + /** + * This map contains the list of the urls to be tested + */ + private static HashMap> CryptoNetURLs = new HashMap<>(); + + /** + * This map contains the list of urls been tested and ordered by the fastests + */ + private static HashMap> TestedURLs = new HashMap<>(); + + public static String getURL(CryptoNet crypto){ + return CryptoNetManager.getURL(crypto,0); + } + + + public static String getURL(CryptoNet crypto, int index){ + if(TestedURLs.containsKey(crypto) && TestedURLs.get(crypto).size()>index){ + StringBuilder debugString = new StringBuilder("CryptoNetManager urls times: "); + for(TestedURL url : TestedURLs.get(crypto)){ + debugString.append("\r\n ").append(url.getTime()).append(" ").append(url.getUrl()); + } + System.out.println(debugString.toString()); + + return TestedURLs.get(crypto).get(index).getUrl(); + } + + if(CryptoNetURLs.containsKey(crypto) && !CryptoNetURLs.get(crypto).isEmpty()){ + return CryptoNetURLs.get(crypto).iterator().next(); + } + return null; + } + + public static int getURLSize(CryptoNet crypto){ + if(TestedURLs.containsKey(crypto)){ + return TestedURLs.get(crypto).size(); + } + return 0; + } + + public static void addCryptoNetURL(CryptoNet crypto, String url){ + if(!CryptoNetURLs.containsKey(crypto)){ + CryptoNetURLs.put(crypto,new HashSet()); + } + + CryptoNetURLs.get(crypto).add(url); + CryptoNetVerifier verifier = CryptoNetVerifier.getNetworkVerify(crypto); + if(verifier != null) { + verifier.checkURL(url); + } + } + + public static void addCryptoNetURL(CryptoNet crypto, String[] urls){ + if(!CryptoNetURLs.containsKey(crypto)){ + CryptoNetURLs.put(crypto,new HashSet()); + } + CryptoNetVerifier verifier = CryptoNetVerifier.getNetworkVerify(crypto); + + for(String url : urls) { + CryptoNetURLs.get(crypto).add(url); + if(verifier != null) { + verifier.checkURL(url); + } + } + } + + public static void removeCryptoNetURL(CryptoNet crypto, String url){ + if(CryptoNetURLs.containsKey(crypto)){ + CryptoNetURLs.get(crypto).remove(url); + } + } + + public static void verifiedCryptoNetURL(CryptoNet crypto, String url, long time){ + if(CryptoNetURLs.containsKey(crypto) && CryptoNetURLs.get(crypto).contains(url)){ + if(!TestedURLs.containsKey(crypto)){ + TestedURLs.put(crypto,new ArrayList()); + } + TestedURL testedUrl = new TestedURL(time,url); + if(!TestedURLs.get(crypto).contains(testedUrl)){ + TestedURLs.get(crypto).add(testedUrl); + Collections.sort(TestedURLs.get(crypto)); + } + }else{ + //TODO add error handler + } + } + + public static String getChaindId(CryptoNet crypto){ + CryptoNetVerifier verifier = CryptoNetVerifier.getNetworkVerify(crypto); + if(verifier != null) { + return verifier.getChainId(); + } + return null; + } + + private static class TestedURL implements Comparable{ + private long time; + private String url; + + public TestedURL(long time, String url) { + this.time = time; + this.url = url; + } + + public long getTime() { + return time; + } + + String getUrl() { + return url; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof TestedURL)) return false; + + TestedURL testedURL = (TestedURL) o; + + return getUrl().equals(testedURL.getUrl()); + } + + @Override + public int hashCode() { + return getUrl().hashCode(); + } + + @Override + public int compareTo(@NonNull Object o) { + if (this == o) return 0; + if (!(o instanceof TestedURL)) return 0; + + TestedURL testedURL = (TestedURL) o; + return (int) (this.getTime() - testedURL.getTime()); + } + } + +} diff --git a/app/src/main/java/cy/agorise/crystalwallet/network/CryptoNetVerifier.java b/app/src/main/java/cy/agorise/crystalwallet/network/CryptoNetVerifier.java new file mode 100644 index 0000000..7364b79 --- /dev/null +++ b/app/src/main/java/cy/agorise/crystalwallet/network/CryptoNetVerifier.java @@ -0,0 +1,25 @@ +package cy.agorise.crystalwallet.network; + +import cy.agorise.crystalwallet.enums.CryptoNet; + +/** + * This is used to check if the connection is stable and fast. + * + * Also verifies if the connection with the server is valid. + * + * Created by henry on 28/2/2018. + */ + +public abstract class CryptoNetVerifier { + + static CryptoNetVerifier getNetworkVerify(CryptoNet cryptoNet){ + if(cryptoNet.getLabel().equals(CryptoNet.BITSHARES.getLabel())){ + return new BitsharesCryptoNetVerifier(); + } + return null; + } + + public abstract void checkURL(final String url); + + public abstract String getChainId(); +} diff --git a/app/src/main/java/cy/agorise/crystalwallet/network/GetChainId.java b/app/src/main/java/cy/agorise/crystalwallet/network/GetChainId.java new file mode 100644 index 0000000..2863514 --- /dev/null +++ b/app/src/main/java/cy/agorise/crystalwallet/network/GetChainId.java @@ -0,0 +1,61 @@ +package cy.agorise.crystalwallet.network; + +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import com.neovisionaries.ws.client.WebSocket; +import com.neovisionaries.ws.client.WebSocketFrame; + +import java.io.Serializable; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import cy.agorise.graphenej.RPC; +import cy.agorise.graphenej.api.BaseGrapheneHandler; +import cy.agorise.graphenej.interfaces.WitnessResponseListener; +import cy.agorise.graphenej.models.ApiCall; +import cy.agorise.graphenej.models.WitnessResponse; + +/** + * Created by henry on 28/2/2018. + */ + +public class GetChainId extends BaseGrapheneHandler { + + private final WitnessResponseListener mListener; + + public GetChainId(WitnessResponseListener listener) { + super(listener); + this.mListener = listener; + } + + @Override + public void onConnected(WebSocket websocket, Map> headers) throws Exception { + ApiCall getAccountByName = new ApiCall(0, "get_chain_id", new ArrayList(), RPC.VERSION, 1); + websocket.sendText(getAccountByName.toJsonString()); + } + + @Override + public void onTextFrame(WebSocket websocket, WebSocketFrame frame) throws Exception { + System.out.println("<<< "+frame.getPayloadText()); + String response = frame.getPayloadText(); + + Type GetChainIdResponse = new TypeToken>(){}.getType(); + GsonBuilder builder = new GsonBuilder(); + WitnessResponse> witnessResponse = builder.create().fromJson(response, GetChainIdResponse); + if(witnessResponse.error != null){ + this.mListener.onError(witnessResponse.error); + }else{ + this.mListener.onSuccess(witnessResponse); + } + + websocket.disconnect(); + } + + @Override + public void onFrameSent(WebSocket websocket, WebSocketFrame frame) throws Exception { + if(frame.isTextFrame()) + System.out.println(">>> "+frame.getPayloadText()); + } +}