package com.yoghurt.crypto.transactions.server.servlets.providers; import java.io.IOException; import java.io.InputStream; import java.net.URISyntaxException; import java.text.ParseException; import java.util.ArrayList; import org.apache.commons.codec.DecoderException; import org.apache.http.HttpException; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import com.yoghurt.crypto.transactions.server.util.HttpClientProxy; import com.yoghurt.crypto.transactions.server.util.json.BlockrApiParser; import com.yoghurt.crypto.transactions.shared.domain.AddressInformation; import com.yoghurt.crypto.transactions.shared.domain.BlockInformation; import com.yoghurt.crypto.transactions.shared.domain.JSONRPCMethod; import com.yoghurt.crypto.transactions.shared.domain.TransactionInformation; import com.yoghurt.crypto.transactions.shared.domain.exception.ApplicationException; import com.yoghurt.crypto.transactions.shared.domain.exception.ApplicationException.Reason; import com.yoghurt.crypto.transactions.shared.service.BlockchainRetrievalService; public class BlockrAPIRetriever implements BlockchainRetrievalService { private static final String BLOCKR_API_LATEST_BLOCK = "http://btc.blockr.io/api/v1/block/info/last"; private static final String LAST_BLOCK_KEYWORD = "last"; private static final String ERROR_TX_FORMAT = "Could not retrieve transaction information: %s"; private static final String BLOCKR_API_TX_RAW_FORMAT = "http://btc.blockr.io/api/v1/tx/raw/%s"; private static final String BLOCKR_API_TX_INFO_FORMAT = "http://btc.blockr.io/api/v1/tx/info/%s"; private static final String BLOCKR_API_BLOCK_RAW_FORMAT = "http://btc.blockr.io/api/v1/block/raw/%s"; private static final String BLOCKR_API_BLOCK_INFO_FORMAT = "http://btc.blockr.io/api/v1/block/info/%s"; @Override public String getLatestBlockHash() { try (CloseableHttpClient client = HttpClientBuilder.create().build(); InputStream jsonData = HttpClientProxy.getRemoteContent(client, BLOCKR_API_LATEST_BLOCK).getContent()) { return BlockrApiParser.getBlockHash(jsonData); } catch (URISyntaxException | IOException | HttpException e) { e.printStackTrace(); } return null; } public String getRawTransactionHex(final String txid) throws ApplicationException { try (final CloseableHttpClient client = HttpClientProxy.buildProxyClient(); InputStream stream = HttpClientProxy.getRemoteContent(client, String.format(BLOCKR_API_TX_RAW_FORMAT, txid)).getContent()) { return BlockrApiParser.getRawTransactionHex(stream); } catch (URISyntaxException | IOException | HttpException e) { e.printStackTrace(); throw new ApplicationException(String.format(ERROR_TX_FORMAT, txid)); } } @Override public TransactionInformation getTransactionInformation(final String txid) throws ApplicationException { try (final CloseableHttpClient client = HttpClientProxy.buildProxyClient(); final InputStream jsonDataInfo = HttpClientProxy.getRemoteContent(client, String.format(BLOCKR_API_TX_INFO_FORMAT, txid)).getContent(); final InputStream jsonDataRaw = HttpClientProxy.getRemoteContent(client, String.format(BLOCKR_API_TX_RAW_FORMAT, txid)).getContent()) { final TransactionInformation transactionInformation = BlockrApiParser.getTransactionInformation(jsonDataInfo); // We need to do another call just for the block hash final String hash = BlockrApiParser.getBlockHashFromTransaction(jsonDataRaw); transactionInformation.setBlockHash(hash); transactionInformation.setRawHex(getRawTransactionHex(txid)); return transactionInformation; } catch (ParseException | URISyntaxException | IOException | HttpException e) { e.printStackTrace(); return null; } } public BlockInformation getBlockInformation(final String identifier) throws ApplicationException { try (CloseableHttpClient client = HttpClientProxy.buildProxyClient(); InputStream jsonDataInfo = HttpClientProxy.getRemoteContent(client, String.format(BLOCKR_API_BLOCK_INFO_FORMAT, identifier)).getContent(); InputStream jsonDataRaw = HttpClientProxy.getRemoteContent(client, String.format(BLOCKR_API_BLOCK_RAW_FORMAT, identifier)).getContent()) { final BlockInformation blockInformation = BlockrApiParser.getBlockInformation(jsonDataInfo); blockInformation.setRawBlockHeaders(getRawBlock(identifier)); final String coinbaseTransactionHash = BlockrApiParser.getCoinbaseTransaction(jsonDataRaw); final TransactionInformation coinbaseInformation = getTransactionInformation(coinbaseTransactionHash); blockInformation.setCoinbaseInformation(coinbaseInformation); return blockInformation; } catch (ParseException | URISyntaxException | IOException | HttpException | DecoderException e) { e.printStackTrace(); return null; } } public String getLastRawBlock() { return getRawBlock(LAST_BLOCK_KEYWORD); } public String getRawBlockFromHash(final String hash) { return getRawBlock(String.valueOf(hash)); } public String getRawBlockFromHeight(final int height) { return getRawBlock(String.valueOf(height)); } private String getRawBlock(final String identifier) { try (CloseableHttpClient client = HttpClientProxy.buildProxyClient(); InputStream jsonData = HttpClientProxy.getRemoteContent(client, String.format(BLOCKR_API_BLOCK_RAW_FORMAT, identifier)).getContent()) { return BlockrApiParser.getRawBlockHex(jsonData); } catch (ParseException | URISyntaxException | IOException | HttpException | DecoderException e) { e.printStackTrace(); return null; } } @Override public BlockInformation getBlockInformationFromHash(final String identifier) throws ApplicationException { return getBlockInformation(identifier); } @Override public BlockInformation getBlockInformationFromHeight(final int height) throws ApplicationException { return getBlockInformation(String.valueOf(height)); } @Override public BlockInformation getBlockInformationLast() throws ApplicationException { return getBlockInformationFromHash(LAST_BLOCK_KEYWORD); } @Override public String getJSONRPCResponse(final JSONRPCMethod method, final String[] arguments) throws ApplicationException { throw new ApplicationException(Reason.UNSUPPORTED_OPERATION); } @Override public AddressInformation getAddressInformation(final String address) throws ApplicationException { throw new ApplicationException(Reason.UNSUPPORTED_OPERATION); } @Override public ArrayList<String> getTransactionList(final int height) throws ApplicationException { throw new ApplicationException(Reason.UNSUPPORTED_OPERATION); } }