package com.coinbase.exchange.api.exchange; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.RestTemplate; import java.time.Instant; import java.util.Arrays; import java.util.List; import static org.springframework.http.HttpMethod.GET; /** * Created by irufus on 2/25/15. */ @Component public class GdaxExchangeImpl implements GdaxExchange { static Logger log = LoggerFactory.getLogger(GdaxExchangeImpl.class.getName()); String publicKey; String passphrase; String baseUrl; Signature signature; RestTemplate restTemplate; @Autowired public GdaxExchangeImpl(@Value("${gdax.key}") String publicKey, @Value("${gdax.passphrase}") String passphrase, @Value("${gdax.api.baseUrl}") String baseUrl, Signature signature, RestTemplate restTemplate) { this.publicKey = publicKey; this.passphrase = passphrase; this.baseUrl = baseUrl; this.signature = signature; this.restTemplate = restTemplate; } @Override public <T> T get(String resourcePath, ParameterizedTypeReference<T> responseType) { try { ResponseEntity<T> responseEntity = restTemplate.exchange(getBaseUrl() + resourcePath, GET, securityHeaders(resourcePath, "GET", ""), responseType); return responseEntity.getBody(); } catch (HttpClientErrorException ex) { log.error("GET request Failed for '" + resourcePath + "': " + ex.getResponseBodyAsString()); } return null; } @Override public <T> List<T> getAsList(String resourcePath, ParameterizedTypeReference<T[]> responseType) { T[] result = get(resourcePath, responseType); return result == null ? Arrays.asList() : Arrays.asList(result); } @Override public <T> T pagedGet(String resourcePath, ParameterizedTypeReference<T> responseType, String beforeOrAfter, Integer pageNumber, Integer limit) { resourcePath += "?" + beforeOrAfter + "=" + pageNumber + "&limit=" + limit; return get(resourcePath, responseType); } @Override public <T> List<T> pagedGetAsList(String resourcePath, ParameterizedTypeReference<T[]> responseType, String beforeOrAfter, Integer pageNumber, Integer limit) { T[] result = pagedGet(resourcePath, responseType, beforeOrAfter, pageNumber, limit ); return result == null ? Arrays.asList() : Arrays.asList(result); } @Override public <T> T delete(String resourcePath, ParameterizedTypeReference<T> responseType) { try { ResponseEntity<T> response = restTemplate.exchange(getBaseUrl() + resourcePath, HttpMethod.DELETE, securityHeaders(resourcePath, "DELETE", ""), responseType); return response.getBody(); } catch (HttpClientErrorException ex) { log.error("DELETE request Failed for '" + resourcePath + "': " + ex.getResponseBodyAsString()); } return null; } @Override public <T, R> T post(String resourcePath, ParameterizedTypeReference<T> responseType, R jsonObj) { String jsonBody = toJson(jsonObj); try { ResponseEntity<T> response = restTemplate.exchange(getBaseUrl() + resourcePath, HttpMethod.POST, securityHeaders(resourcePath, "POST", jsonBody), responseType); return response.getBody(); } catch (HttpClientErrorException ex) { log.error("POST request Failed for '" + resourcePath + "': " + ex.getResponseBodyAsString()); } return null; } @Override public String getBaseUrl() { return baseUrl; } @Override public HttpEntity<String> securityHeaders(String endpoint, String method, String jsonBody) { HttpHeaders headers = new HttpHeaders(); String timestamp = Instant.now().getEpochSecond() + ""; String resource = endpoint.replace(getBaseUrl(), ""); headers.add("accept", "application/json"); headers.add("content-type", "application/json"); headers.add("User-Agent", "gdax-java unofficial coinbase pro api library"); headers.add("CB-ACCESS-KEY", publicKey); headers.add("CB-ACCESS-SIGN", signature.generate(resource, method, jsonBody, timestamp)); headers.add("CB-ACCESS-TIMESTAMP", timestamp); headers.add("CB-ACCESS-PASSPHRASE", passphrase); curlRequest(method, jsonBody, headers, resource); return new HttpEntity<>(jsonBody, headers); } private void curlRequest(String method, String jsonBody, HttpHeaders headers, String resource) { String curlTest = "curl "; for (String key : headers.keySet()){ curlTest += "-H '" + key + ":" + headers.get(key).get(0) + "' "; } if (!jsonBody.equals("")) curlTest += "-d '" + jsonBody + "' "; curlTest += "-X " + method + " " + getBaseUrl() + resource; log.debug(curlTest); } private String toJson(Object object) { try { ObjectMapper objectMapper = new ObjectMapper(); String json = objectMapper.writeValueAsString(object); return json; } catch (JsonProcessingException e) { log.error("Unable to serialize", e); throw new RuntimeException("Unable to serialize"); } } }