package jstellarapi.connection; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.URI; import java.util.Arrays; import javax.xml.bind.DatatypeConverter; import jstellarapi.core.StellarAddress; import jstellarapi.core.StellarEngineException; import jstellarapi.core.StellarPaymentTransaction; import jstellarapi.core.StellarSeedAddress; import jstellarapi.ds.account.tx.AccountTx; import jstellarapi.ds.account.tx.Balance; import jstellarapi.ds.account.tx.BalanceAdapter; import jstellarapi.ds.tx.Amount; import jstellarapi.ds.tx.AmountAdapter; import jstellarapi.ds.tx.Tx; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import com.google.gson.GsonBuilder; /** * This class should use only http POST/GET, not the websocket. For small * operations, (submit a TX), this could be faster than setting up a websocket * connection. * * @author pmarches */ @SuppressWarnings("unchecked") public class StellarDaemonRPCConnection extends StellarDaemonConnection { protected URI stellarDaemonURI; public static URI STELLAR_RPC_URI = URI.create("http://test.stellar.org:9002"); public StellarDaemonRPCConnection(URI StellarDaemonURI){ this.stellarDaemonURI = StellarDaemonURI; } public StellarDaemonRPCConnection(){ this(StellarDaemonRPCConnection.STELLAR_RPC_URI); } public StellarPaymentTransaction submitTransaction(byte[] signedTransactionBytes) throws Exception { return submitTransaction(DatatypeConverter.printHexBinary(signedTransactionBytes)); } public StellarPaymentTransaction submitTransaction(String tx_blob) throws Exception { JSONObject txBlob = new JSONObject(); txBlob.put("tx_blob", tx_blob); JSONObject command = createJSONCommand("submit", txBlob); JSONObject response = executeJSONCommand(command); JSONObject result = (JSONObject) response.get("result"); if ((Long) result.get("engine_result_code") != 0) { throw new StellarEngineException((String) result.get("engine_result"), (Long) result.get("engine_result_code"), (String) result.get("engine_result_message")); } StellarPaymentTransaction txToSign = new StellarPaymentTransaction(null, null, null, 0); txToSign.copyFrom(result); return txToSign; } protected JSONObject createJSONCommand(String commandName, JSONObject... parameterObjects) { JSONObject command = new JSONObject(); command.put("method", commandName); JSONArray parameterArray = new JSONArray(); command.put("params", parameterArray); parameterArray.addAll(Arrays.asList(parameterObjects)); return command; } protected JSONObject executeJSONCommand(JSONObject command) throws Exception { String jsonString = command.toJSONString(); HttpURLConnection connection = (HttpURLConnection) stellarDaemonURI.toURL().openConnection(); connection.setUseCaches(false); connection.setRequestProperty("Content-Length", "" + jsonString.length()); connection.setRequestMethod("POST"); connection.setDoOutput(true); OutputStream os = connection.getOutputStream(); os.write(jsonString.getBytes()); os.close(); try { // TODO The response handling is probably common between the // websocket and the RPC InputStream is = connection.getInputStream(); BufferedReader rd = new BufferedReader(new InputStreamReader(is)); JSONObject response = (JSONObject) new JSONParser().parse(rd); rd.close(); return response; } catch (Exception e) { throw new RuntimeException(e); } } public StellarAddressPublicInformation getPublicInformation(StellarAddress StellarAddress) throws Exception { JSONObject account = new JSONObject(); account.put("account", StellarAddress.toString()); JSONObject command = createJSONCommand("account_info", account); JSONObject response = executeJSONCommand(command); StellarAddressPublicInformation info = new StellarAddressPublicInformation(); info.copyFrom((JSONObject) response.get("result")); return info; } public TrustLines getTrustLines(StellarAddress StellarAddress) throws Exception { JSONObject account = new JSONObject(); account.put("account", StellarAddress.toString()); JSONObject command = createJSONCommand("account_lines", account); JSONObject response = executeJSONCommand(command); TrustLines info = new TrustLines(); info.copyFrom((JSONObject) response.get("result")); return info; } public AccountTx getAccountTx(StellarAddress StellarAddress) throws Exception { return getAccountTx(StellarAddress, null, null, null, false); } public AccountTx getAccountTx(StellarAddress StellarAddress, Integer ledger_index_min, Integer ledger_index_max, Integer limit, boolean forward) throws Exception { JSONObject account = new JSONObject(); account.put("account", StellarAddress.toString()); if (ledger_index_min != null) { account.put("ledger_index_min", ledger_index_min); } if (ledger_index_max != null) { account.put("ledger_index_max", ledger_index_max); } if (limit != null) { account.put("limit", limit); } if (forward) { account.put("forward", true); } JSONObject command = createJSONCommand("account_tx", account); String jsonString = command.toJSONString(); HttpURLConnection connection = (HttpURLConnection) stellarDaemonURI.toURL().openConnection(); connection.setUseCaches(false); connection.setRequestProperty("Content-Length", "" + jsonString.length()); connection.setRequestMethod("POST"); connection.setDoOutput(true); OutputStream os = connection.getOutputStream(); os.write(jsonString.getBytes()); os.close(); InputStream is = connection.getInputStream(); BufferedReader rd = new BufferedReader(new InputStreamReader(is)); AccountTx atx = new GsonBuilder().registerTypeAdapter(Balance.class, new BalanceAdapter()).create().fromJson(rd, AccountTx.class); rd.close(); is.close(); return atx; } public StellarPaymentTransaction signTransaction(StellarSeedAddress secret, StellarPaymentTransaction txToSign) throws Exception { JSONObject param = new JSONObject(); param.put("secret", secret.toString()); param.put("tx_json", txToSign.toTxJSON()); JSONObject command = createJSONCommand("sign", param); String jsonString = command.toJSONString(); HttpURLConnection connection = (HttpURLConnection) stellarDaemonURI.toURL().openConnection(); connection.setUseCaches(false); connection.setRequestProperty("Content-Length", "" + jsonString.length()); connection.setRequestMethod("POST"); connection.setDoOutput(true); OutputStream os = connection.getOutputStream(); os.write(jsonString.getBytes()); os.close(); InputStream is = connection.getInputStream(); BufferedReader rd = new BufferedReader(new InputStreamReader(is)); JSONObject result = (JSONObject) new JSONParser().parse(rd); result = (JSONObject) result.get("result"); String status = (String) result.get("status"); if (!status.equals("success")) { throw new IllegalStateException(result.get("error_message").toString()); } txToSign.copyFrom(result); rd.close(); is.close(); return txToSign; } public Tx getTranscation(String txHash) throws Exception { JSONObject param = new JSONObject(); param.put("transaction", txHash); JSONObject command = createJSONCommand("tx", param); String jsonString = command.toJSONString(); HttpURLConnection connection = (HttpURLConnection) stellarDaemonURI.toURL().openConnection(); connection.setUseCaches(false); connection.setRequestProperty("Content-Length", "" + jsonString.length()); connection.setRequestMethod("POST"); connection.setDoOutput(true); OutputStream os = connection.getOutputStream(); os.write(jsonString.getBytes()); os.close(); InputStream is = connection.getInputStream(); BufferedReader rd = new BufferedReader(new InputStreamReader(is)); Tx tx = new GsonBuilder().registerTypeAdapter(Amount.class, new AmountAdapter()).create().fromJson(rd, Tx.class); rd.close(); is.close(); return tx; } }