OSDN Git Service

refactor
[bytom/bytom-java-sdk.git] / tx-signer / src / main / java / io / bytom / http / Client.java
diff --git a/tx-signer/src/main/java/io/bytom/http/Client.java b/tx-signer/src/main/java/io/bytom/http/Client.java
deleted file mode 100755 (executable)
index ec0028c..0000000
+++ /dev/null
@@ -1,723 +0,0 @@
-package io.bytom.http;\r
-\r
-import com.google.gson.Gson;\r
-import com.google.gson.JsonElement;\r
-import com.google.gson.JsonParser;\r
-import com.squareup.okhttp.*;\r
-import io.bytom.common.Configuration;\r
-import io.bytom.common.Utils;\r
-import io.bytom.exception.APIException;\r
-import io.bytom.exception.BytomException;\r
-import io.bytom.exception.ConfigurationException;\r
-import io.bytom.exception.JSONException;\r
-import org.apache.log4j.Logger;\r
-import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;\r
-\r
-import javax.net.ssl.*;\r
-import java.io.*;\r
-import java.lang.reflect.Type;\r
-import java.net.MalformedURLException;\r
-import java.net.Proxy;\r
-import java.net.URL;\r
-import java.nio.file.Files;\r
-import java.nio.file.Paths;\r
-import java.security.GeneralSecurityException;\r
-import java.security.KeyFactory;\r
-import java.security.KeyStore;\r
-import java.security.cert.Certificate;\r
-import java.security.cert.CertificateFactory;\r
-import java.security.cert.X509Certificate;\r
-import java.security.spec.KeySpec;\r
-import java.security.spec.PKCS8EncodedKeySpec;\r
-import java.util.Arrays;\r
-import java.util.Collection;\r
-import java.util.Objects;\r
-import java.util.Random;\r
-import java.util.concurrent.TimeUnit;\r
-\r
-/**\r
- * The Client object contains all information necessary to\r
- * perform an HTTP request against a remote API. Typically,\r
- * an application will have a client that makes requests to\r
- * a Chain Core, and a separate Client that makes requests\r
- * to an HSM server.\r
- */\r
-public class Client {\r
-    private String url;\r
-    private String accessToken;\r
-    private OkHttpClient httpClient;\r
-\r
-    // Used to create empty, in-memory key stores.\r
-    private static final char[] DEFAULT_KEYSTORE_PASSWORD = "123456".toCharArray();\r
-    private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");\r
-    private static String version = "dev"; // updated in the static initializer\r
-\r
-    public static Logger logger = Logger.getLogger(Client.class);\r
-\r
-    private static class BuildProperties {\r
-        public String version;\r
-    }\r
-\r
-    static {\r
-        InputStream in = Client.class.getClassLoader().getResourceAsStream("properties.json");\r
-        if (in != null) {\r
-            InputStreamReader inr = new InputStreamReader(in);\r
-            version = Utils.serializer.fromJson(inr, BuildProperties.class).version;\r
-        }\r
-    }\r
-\r
-    public static Client generateClient() throws BytomException {\r
-\r
-        String coreURL = Configuration.getValue("bytom.api.url");\r
-        String accessToken = Configuration.getValue("client.access.token");\r
-\r
-        if (coreURL == null || coreURL.isEmpty()) {\r
-            coreURL = "http://47.91.254.104:8888";\r
-        }\r
-\r
-        if (coreURL.endsWith("/")) {\r
-            //split the last char "/"\r
-            coreURL = coreURL.substring(0, coreURL.length() - 1);\r
-            logger.info("check the coreURL is right.");\r
-        }\r
-\r
-        return new Client(coreURL, accessToken);\r
-    }\r
-\r
-    public Client(Builder builder) throws ConfigurationException {\r
-        if (builder.url.endsWith("/")) {\r
-            //split the last char "/"\r
-            builder.url = builder.url.substring(0, builder.url.length() - 1);\r
-        }\r
-        this.url = builder.url;\r
-        this.accessToken = builder.accessToken;\r
-        this.httpClient = buildHttpClient(builder);\r
-    }\r
-\r
-    /**\r
-     * Create a new http Client object using the default development host URL.\r
-     */\r
-    public Client() throws BytomException {\r
-        this(new Builder());\r
-    }\r
-\r
-    /**\r
-     * Create a new http Client object\r
-     *\r
-     * @param url the URL of the Chain Core or HSM\r
-     */\r
-    public Client(String url) throws BytomException {\r
-        this(new Builder().setUrl(url));\r
-    }\r
-\r
-    /**\r
-     * Create a new http Client object\r
-     *\r
-     * @param url         the URL of the Chain Core or HSM\r
-     * @param accessToken a Client API access token\r
-     */\r
-    public Client(String url, String accessToken) throws BytomException {\r
-        this(new Builder().setUrl(url).setAccessToken(accessToken));\r
-    }\r
-\r
-    /**\r
-     * Perform a single HTTP POST request against the API for a specific action.\r
-     *\r
-     * @param action The requested API action\r
-     * @param body   Body payload sent to the API as JSON\r
-     * @param tClass Type of object to be deserialized from the response JSON\r
-     * @return the result of the post request\r
-     * @throws BytomException\r
-     */\r
-    public <T> T request(String action, Object body, final Type tClass) throws BytomException {\r
-        ResponseCreator<T> rc =\r
-                new ResponseCreator<T>() {\r
-                    public T create(Response response, Gson deserializer) throws IOException, BytomException {\r
-                        JsonElement root = new JsonParser().parse(response.body().charStream());\r
-                        JsonElement status = root.getAsJsonObject().get("status");\r
-                        JsonElement data = root.getAsJsonObject().get("data");\r
-                        if (status != null && status.toString().contains("fail")) {\r
-                            throw new BytomException(root.getAsJsonObject().get("msg").toString());\r
-                        } else if (data != null) {\r
-                            return deserializer.fromJson(data, tClass);\r
-                        } else {\r
-                            return deserializer.fromJson(response.body().charStream(), tClass);\r
-                        }\r
-                    }\r
-                };\r
-        return post(action, body, rc);\r
-    }\r
-\r
-    /**\r
-     * Perform a single HTTP POST request against the API for a specific action,\r
-     * ignoring the body of the response.\r
-     *\r
-     * @param action The requested API action\r
-     * @param body   Body payload sent to the API as JSON\r
-     * @throws BytomException\r
-     */\r
-    public void request(String action, Object body) throws BytomException {\r
-        ResponseCreator<Object> rc =\r
-                new ResponseCreator<Object>() {\r
-                    public Object create(Response response, Gson deserializer) throws IOException, BytomException {\r
-                        JsonElement root = new JsonParser().parse(response.body().charStream());\r
-                        JsonElement status = root.getAsJsonObject().get("status");\r
-                        JsonElement data = root.getAsJsonObject().get("data");\r
-                        if (status != null && status.toString().contains("fail")) {\r
-                            throw new BytomException(root.getAsJsonObject().get("msg").toString());\r
-                        }\r
-                        return null;\r
-                    }\r
-                };\r
-        post(action, body, rc);\r
-    }\r
-\r
-    /**\r
-     * return the value of named as key from json\r
-     *\r
-     * @param action\r
-     * @param body\r
-     * @param key\r
-     * @param tClass\r
-     * @param <T>\r
-     * @return\r
-     * @throws BytomException\r
-     */\r
-    public <T> T requestGet(String action, Object body, final String key, final Type tClass)\r
-            throws BytomException {\r
-        ResponseCreator<T> rc = new ResponseCreator<T>() {\r
-            public T create(Response response, Gson deserializer) throws IOException,\r
-                    BytomException {\r
-                JsonElement root = new JsonParser().parse(response.body().charStream());\r
-                JsonElement status = root.getAsJsonObject().get("status");\r
-                JsonElement data = root.getAsJsonObject().get("data");\r
-\r
-                if (status != null && status.toString().contains("fail"))\r
-                    throw new BytomException(root.getAsJsonObject().get("msg").toString());\r
-                else if (data != null)\r
-                    return deserializer.fromJson(data.getAsJsonObject().get(key), tClass);\r
-                else\r
-                    return deserializer.fromJson(response.body().charStream(), tClass);\r
-            }\r
-        };\r
-        return post(action, body, rc);\r
-    }\r
-\r
-    /**\r
-     * Perform a single HTTP POST request against the API for a specific action.\r
-     * Use this method if you want batch semantics, i.e., the endpoint response\r
-     * is an array of valid objects interleaved with arrays, once corresponding to\r
-     * each input object.\r
-     *\r
-     * @param action The requested API action\r
-     * @param body   Body payload sent to the API as JSON\r
-     * @param tClass Type of object to be deserialized from the response JSON\r
-     * @return the result of the post request\r
-     * @throws BytomException\r
-     */\r
-    /*\r
-    public <T> T requestBatch(String action, Object body, final Type tClass) throws BytomException {\r
-        ResponseCreator<T> rc =\r
-                new ResponseCreator<T>() {\r
-                    public T create(Response response, Gson deserializer) throws IOException, BytomException {\r
-                        JsonElement root = new JsonParser().parse(response.body().charStream());\r
-                        JsonElement status = root.getAsJsonObject().get("status");\r
-                        JsonElement data = root.getAsJsonObject().get("data");\r
-                        if (status != null && status.toString().contains("fail")) {\r
-                            throw new BytomException(root.getAsJsonObject().get("msg").toString());\r
-                        } else if (data != null) {\r
-                            return deserializer.fromJson(data, tClass);\r
-                        } else {\r
-                            return deserializer.fromJson(response.body().charStream(), tClass);\r
-                        }\r
-                    }\r
-                };\r
-        //把object转换为json对象数组(有点难)\r
-\r
-        //根据数组的大小循环调用post()方法\r
-\r
-        //重写create()接口方法,对成功和失败做不同的处理\r
-\r
-        //调用BatchResponse(Map<Integer, T> successes, Map<Integer, APIException> errors)\r
-        //构造方法,最后返回BatchResponse实例对象\r
-\r
-        return post(action, body, rc);\r
-    }\r
-    */\r
-\r
-\r
-    /**\r
-     * Returns true if a client access token stored in the client.\r
-     *\r
-     * @return a boolean\r
-     */\r
-    public boolean hasAccessToken() {\r
-        return this.accessToken != null && !this.accessToken.isEmpty();\r
-    }\r
-\r
-    /**\r
-     * Returns the client access token (possibly null).\r
-     *\r
-     * @return the client access token\r
-     */\r
-    public String accessToken() {\r
-        return accessToken;\r
-    }\r
-\r
-    public String getUrl() {\r
-        return url;\r
-    }\r
-\r
-    /**\r
-     * Pins a public key to the HTTP client.\r
-     *\r
-     * @param provider           certificate provider\r
-     * @param subjPubKeyInfoHash public key hash\r
-     */\r
-    public void pinCertificate(String provider, String subjPubKeyInfoHash) {\r
-        CertificatePinner cp =\r
-                new CertificatePinner.Builder().add(provider, subjPubKeyInfoHash).build();\r
-        this.httpClient.setCertificatePinner(cp);\r
-    }\r
-\r
-    /**\r
-     * Sets the default connect timeout for new connections. A value of 0 means no timeout.\r
-     *\r
-     * @param timeout the number of time units for the default timeout\r
-     * @param unit    the unit of time\r
-     */\r
-    public void setConnectTimeout(long timeout, TimeUnit unit) {\r
-        this.httpClient.setConnectTimeout(timeout, unit);\r
-    }\r
-\r
-    /**\r
-     * Sets the default read timeout for new connections. A value of 0 means no timeout.\r
-     *\r
-     * @param timeout the number of time units for the default timeout\r
-     * @param unit    the unit of time\r
-     */\r
-    public void setReadTimeout(long timeout, TimeUnit unit) {\r
-        this.httpClient.setReadTimeout(timeout, unit);\r
-    }\r
-\r
-    /**\r
-     * Sets the default write timeout for new connections. A value of 0 means no timeout.\r
-     *\r
-     * @param timeout the number of time units for the default timeout\r
-     * @param unit    the unit of time\r
-     */\r
-    public void setWriteTimeout(long timeout, TimeUnit unit) {\r
-        this.httpClient.setWriteTimeout(timeout, unit);\r
-    }\r
-\r
-    /**\r
-     * Sets the proxy information for the HTTP client.\r
-     *\r
-     * @param proxy proxy object\r
-     */\r
-    public void setProxy(Proxy proxy) {\r
-        this.httpClient.setProxy(proxy);\r
-    }\r
-\r
-    /**\r
-     * Defines an interface for deserializing HTTP responses into objects.\r
-     *\r
-     * @param <T> the type of object to return\r
-     */\r
-    public interface ResponseCreator<T> {\r
-        /**\r
-         * Deserializes an HTTP response into a Java object of type T.\r
-         *\r
-         * @param response     HTTP response object\r
-         * @param deserializer json deserializer\r
-         * @return an object of type T\r
-         * @throws BytomException\r
-         * @throws IOException\r
-         */\r
-        T create(Response response, Gson deserializer) throws BytomException, IOException;\r
-    }\r
-\r
-    /**\r
-     * Builds and executes an HTTP Post request.\r
-     *\r
-     * @param path        the path to the endpoint\r
-     * @param body        the request body\r
-     * @param respCreator object specifying the response structure\r
-     * @return a response deserialized into type T\r
-     * @throws BytomException\r
-     */\r
-    private <T> T post(String path, Object body, ResponseCreator<T> respCreator)\r
-            throws BytomException {\r
-\r
-        RequestBody requestBody = RequestBody.create(this.JSON, Utils.serializer.toJson(body));\r
-        Request req;\r
-\r
-        BytomException exception = null;\r
-        URL endpointURL = null;\r
-\r
-        try {\r
-            endpointURL = new URL(url + "/" + path);\r
-        } catch (MalformedURLException e) {\r
-            e.printStackTrace();\r
-        }\r
-\r
-        Request.Builder builder =\r
-                new Request.Builder()\r
-                        .header("User-Agent", "bytom-sdk-java/" + version)\r
-                        .url(endpointURL)\r
-                        .method("POST", requestBody);\r
-        if (hasAccessToken()) {\r
-            builder = builder.header("Authorization", buildCredentials());\r
-        }\r
-        req = builder.build();\r
-\r
-        Response resp = null;\r
-\r
-        T object = null;\r
-\r
-        try {\r
-            resp = this.checkError(this.httpClient.newCall(req).execute());\r
-            object = respCreator.create(resp, Utils.serializer);\r
-        } catch (IOException e) {\r
-            e.printStackTrace();\r
-        }\r
-\r
-        return object;\r
-    }\r
-\r
-    private OkHttpClient buildHttpClient(Builder builder) throws ConfigurationException {\r
-        OkHttpClient httpClient = builder.baseHttpClient.clone();\r
-\r
-        try {\r
-            if (builder.trustManagers != null) {\r
-                SSLContext sslContext = SSLContext.getInstance("TLS");\r
-                sslContext.init(builder.keyManagers, builder.trustManagers, null);\r
-                httpClient.setSslSocketFactory(sslContext.getSocketFactory());\r
-            }\r
-        } catch (GeneralSecurityException ex) {\r
-            throw new ConfigurationException("Unable to configure TLS", ex);\r
-        }\r
-        if (builder.readTimeoutUnit != null) {\r
-            httpClient.setReadTimeout(builder.readTimeout, builder.readTimeoutUnit);\r
-        }\r
-        if (builder.writeTimeoutUnit != null) {\r
-            httpClient.setWriteTimeout(builder.writeTimeout, builder.writeTimeoutUnit);\r
-        }\r
-        if (builder.connectTimeoutUnit != null) {\r
-            httpClient.setConnectTimeout(builder.connectTimeout, builder.connectTimeoutUnit);\r
-        }\r
-        if (builder.pool != null) {\r
-            httpClient.setConnectionPool(builder.pool);\r
-        }\r
-        if (builder.proxy != null) {\r
-            httpClient.setProxy(builder.proxy);\r
-        }\r
-        if (builder.cp != null) {\r
-            httpClient.setCertificatePinner(builder.cp);\r
-        }\r
-\r
-        return httpClient;\r
-    }\r
-\r
-    private static final Random randomGenerator = new Random();\r
-    private static final int MAX_RETRIES = 10;\r
-    private static final int RETRY_BASE_DELAY_MILLIS = 40;\r
-\r
-    // the max amount of time cored leader election could take\r
-    private static final int RETRY_MAX_DELAY_MILLIS = 15000;\r
-\r
-    private static int retryDelayMillis(int retryAttempt) {\r
-        // Calculate the max delay as base * 2 ^ (retryAttempt - 1).\r
-        int max = RETRY_BASE_DELAY_MILLIS * (1 << (retryAttempt - 1));\r
-        max = Math.min(max, RETRY_MAX_DELAY_MILLIS);\r
-\r
-        // To incorporate jitter, use a pseudo random delay between [max/2, max] millis.\r
-        return randomGenerator.nextInt(max / 2) + max / 2 + 1;\r
-    }\r
-\r
-    private static final int[] RETRIABLE_STATUS_CODES = {\r
-            408, // Request Timeout\r
-            429, // Too Many Requests\r
-            500, // Internal Server Error\r
-            502, // Bad Gateway\r
-            503, // Service Unavailable\r
-            504, // Gateway Timeout\r
-            509, // Bandwidth Limit Exceeded\r
-    };\r
-\r
-    private static boolean isRetriableStatusCode(int statusCode) {\r
-        for (int i = 0; i < RETRIABLE_STATUS_CODES.length; i++) {\r
-            if (RETRIABLE_STATUS_CODES[i] == statusCode) {\r
-                return true;\r
-            }\r
-        }\r
-        return false;\r
-    }\r
-\r
-    private Response checkError(Response response) throws BytomException {\r
-        /*\r
-        String rid = response.headers().get("Bytom-Request-ID");\r
-        if (rid == null || rid.length() == 0) {\r
-            // Header field Bytom-Request-ID is set by the backend\r
-            // API server. If this field is set, then we can expect\r
-            // the body to be well-formed JSON. If it's not set,\r
-            // then we are probably talking to a gateway or proxy.\r
-            throw new ConnectivityException(response);\r
-        } */\r
-\r
-        if ((response.code() / 100) != 2) {\r
-            try {\r
-                APIException err =\r
-                        Utils.serializer.fromJson(response.body().charStream(), APIException.class);\r
-                if (err.code != null) {\r
-                    //err.requestId = rid;\r
-                    err.statusCode = response.code();\r
-                    throw err;\r
-                }\r
-            } catch (IOException ex) {\r
-                //throw new JSONException("Unable to read body. " + ex.getMessage(), rid);\r
-                throw new JSONException("Unable to read body. ");\r
-            }\r
-        }\r
-        return response;\r
-    }\r
-\r
-    private String buildCredentials() {\r
-        String user = "";\r
-        String pass = "";\r
-        if (hasAccessToken()) {\r
-            String[] parts = accessToken.split(":");\r
-            if (parts.length >= 1) {\r
-                user = parts[0];\r
-            }\r
-            if (parts.length >= 2) {\r
-                pass = parts[1];\r
-            }\r
-        }\r
-        return Credentials.basic(user, pass);\r
-    }\r
-\r
-    /**\r
-     * Overrides {@link Object#hashCode()}\r
-     *\r
-     * @return the hash code\r
-     */\r
-    @Override\r
-    public int hashCode() {\r
-        int code = this.url.hashCode();\r
-        if (this.hasAccessToken()) {\r
-            code = code * 31 + this.accessToken.hashCode();\r
-        }\r
-        return code;\r
-    }\r
-\r
-    /**\r
-     * Overrides {@link Object#equals(Object)}\r
-     *\r
-     * @param o the object to compare\r
-     * @return a boolean specifying equality\r
-     */\r
-    @Override\r
-    public boolean equals(Object o) {\r
-        if (o == null) return false;\r
-        if (!(o instanceof Client)) return false;\r
-\r
-        Client other = (Client) o;\r
-        if (!this.url.equalsIgnoreCase(other.url)) {\r
-            return false;\r
-        }\r
-        return Objects.equals(this.accessToken, other.accessToken);\r
-    }\r
-\r
-    /**\r
-     * A builder class for creating client objects\r
-     */\r
-    public static class Builder {\r
-\r
-        private String url;\r
-\r
-        private OkHttpClient baseHttpClient;\r
-        private String accessToken;\r
-        private CertificatePinner cp;\r
-        private KeyManager[] keyManagers;\r
-        private TrustManager[] trustManagers;\r
-        private long connectTimeout;\r
-        private TimeUnit connectTimeoutUnit;\r
-        private long readTimeout;\r
-        private TimeUnit readTimeoutUnit;\r
-        private long writeTimeout;\r
-        private TimeUnit writeTimeoutUnit;\r
-        private Proxy proxy;\r
-        private ConnectionPool pool;\r
-\r
-        public Builder() {\r
-            this.baseHttpClient = new OkHttpClient();\r
-            this.baseHttpClient.setFollowRedirects(false);\r
-            this.setDefaults();\r
-        }\r
-\r
-        public Builder(Client client) {\r
-            this.baseHttpClient = client.httpClient.clone();\r
-            this.url = client.url;\r
-            this.accessToken = client.accessToken;\r
-        }\r
-\r
-        private void setDefaults() {\r
-            this.setReadTimeout(30, TimeUnit.SECONDS);\r
-            this.setWriteTimeout(30, TimeUnit.SECONDS);\r
-            this.setConnectTimeout(30, TimeUnit.SECONDS);\r
-            this.setConnectionPool(50, 2, TimeUnit.MINUTES);\r
-        }\r
-\r
-        public Builder setUrl(String url) {\r
-            this.url = url;\r
-            return this;\r
-        }\r
-\r
-        /**\r
-         * Sets the access token for the client\r
-         *\r
-         * @param accessToken The access token for the Chain Core or HSM\r
-         */\r
-        public Builder setAccessToken(String accessToken) {\r
-            this.accessToken = accessToken;\r
-            return this;\r
-        }\r
-\r
-\r
-        /**\r
-         * Trusts the given CA certs, and no others. Use this if you are running\r
-         * your own CA, or are using a self-signed server certificate.\r
-         *\r
-         * @param is input stream of the certificates to trust, in PEM format.\r
-         */\r
-        public Builder setTrustedCerts(InputStream is) throws ConfigurationException {\r
-            try {\r
-                // Extract certs from PEM-encoded input.\r
-                CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");\r
-                Collection<? extends Certificate> certificates =\r
-                        certificateFactory.generateCertificates(is);\r
-                if (certificates.isEmpty()) {\r
-                    throw new IllegalArgumentException("expected non-empty set of trusted certificates");\r
-                }\r
-\r
-                // Create a new key store and input the cert.\r
-                KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());\r
-                keyStore.load(null, DEFAULT_KEYSTORE_PASSWORD);\r
-                int index = 0;\r
-                for (Certificate certificate : certificates) {\r
-                    String certificateAlias = Integer.toString(index++);\r
-                    keyStore.setCertificateEntry(certificateAlias, certificate);\r
-                }\r
-\r
-                // Use key store to build an X509 trust manager.\r
-                KeyManagerFactory keyManagerFactory =\r
-                        KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());\r
-                keyManagerFactory.init(keyStore, DEFAULT_KEYSTORE_PASSWORD);\r
-                TrustManagerFactory trustManagerFactory =\r
-                        TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());\r
-                trustManagerFactory.init(keyStore);\r
-                TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();\r
-                if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {\r
-                    throw new IllegalStateException(\r
-                            "Unexpected default trust managers:" + Arrays.toString(trustManagers));\r
-                }\r
-\r
-                this.trustManagers = trustManagers;\r
-                return this;\r
-            } catch (GeneralSecurityException | IOException ex) {\r
-                throw new ConfigurationException("Unable to configure trusted CA certs", ex);\r
-            }\r
-        }\r
-\r
-        /**\r
-         * Trusts the given CA certs, and no others. Use this if you are running\r
-         * your own CA, or are using a self-signed server certificate.\r
-         *\r
-         * @param path The path of a file containing certificates to trust, in PEM format.\r
-         */\r
-        public Builder setTrustedCerts(String path) throws ConfigurationException {\r
-            try (InputStream is = new FileInputStream(path)) {\r
-                return setTrustedCerts(is);\r
-            } catch (IOException ex) {\r
-                throw new ConfigurationException("Unable to configure trusted CA certs", ex);\r
-            }\r
-        }\r
-\r
-        /**\r
-         * Sets the certificate pinner for the client\r
-         *\r
-         * @param provider           certificate provider\r
-         * @param subjPubKeyInfoHash public key hash\r
-         */\r
-        public Builder pinCertificate(String provider, String subjPubKeyInfoHash) {\r
-            this.cp = new CertificatePinner.Builder().add(provider, subjPubKeyInfoHash).build();\r
-            return this;\r
-        }\r
-\r
-        /**\r
-         * Sets the connect timeout for the client\r
-         *\r
-         * @param timeout the number of time units for the default timeout\r
-         * @param unit    the unit of time\r
-         */\r
-        public Builder setConnectTimeout(long timeout, TimeUnit unit) {\r
-            this.connectTimeout = timeout;\r
-            this.connectTimeoutUnit = unit;\r
-            return this;\r
-        }\r
-\r
-        /**\r
-         * Sets the read timeout for the client\r
-         *\r
-         * @param timeout the number of time units for the default timeout\r
-         * @param unit    the unit of time\r
-         */\r
-        public Builder setReadTimeout(long timeout, TimeUnit unit) {\r
-            this.readTimeout = timeout;\r
-            this.readTimeoutUnit = unit;\r
-            return this;\r
-        }\r
-\r
-        /**\r
-         * Sets the write timeout for the client\r
-         *\r
-         * @param timeout the number of time units for the default timeout\r
-         * @param unit    the unit of time\r
-         */\r
-        public Builder setWriteTimeout(long timeout, TimeUnit unit) {\r
-            this.writeTimeout = timeout;\r
-            this.writeTimeoutUnit = unit;\r
-            return this;\r
-        }\r
-\r
-        /**\r
-         * Sets the proxy for the client\r
-         *\r
-         * @param proxy\r
-         */\r
-        public Builder setProxy(Proxy proxy) {\r
-            this.proxy = proxy;\r
-            return this;\r
-        }\r
-\r
-        /**\r
-         * Sets the connection pool for the client\r
-         *\r
-         * @param maxIdle the maximum number of idle http connections in the pool\r
-         * @param timeout the number of time units until an idle http connection in the pool is closed\r
-         * @param unit    the unit of time\r
-         */\r
-        public Builder setConnectionPool(int maxIdle, long timeout, TimeUnit unit) {\r
-            this.pool = new ConnectionPool(maxIdle, unit.toMillis(timeout));\r
-            return this;\r
-        }\r
-\r
-        /**\r
-         * Builds a client with all of the provided parameters.\r
-         */\r
-        public Client build() throws ConfigurationException {\r
-            return new Client(this);\r
-        }\r
-    }\r
-}\r