dev.sixpack.client.Sixpack Maven / Gradle / Ivy
package dev.sixpack.client;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import dev.sixpack.api.data.Configuration;
import dev.sixpack.api.data.Dataset;
import dev.sixpack.api.data.SixpackError;
import dev.sixpack.api.exception.SixpackClientException;
import dev.sixpack.api.exception.SixpackException;
import dev.sixpack.api.exception.SixpackServerException;
import lombok.Getter;
import okhttp3.*;
import javax.crypto.Mac;
import java.io.IOException;
import java.util.UUID;
import static dev.sixpack.client.HmacHelper.bytesToHex;
import static dev.sixpack.client.HmacHelper.macFactory;
import static dev.sixpack.utils.FormatUtils.mFormat;
import static java.lang.System.getenv;
import static java.nio.charset.StandardCharsets.UTF_8;
public class Sixpack {
public static final String SX_ACCOUNT = "SX-Account";
public static final String SX_USER = "SX-User";
public static final String SX_TIMESTAMP = "SX-Timestamp";
public static final String SX_NONCE = "SX-Nonce";
public static final String SX_SIGNATURE = "SX-Signature";
public static final String SIXPACK_URL = "SIXPACK_URL";
public static final String SIXPACK_ACCOUNT = "SIXPACK_ACCOUNT";
public static final String SIXPACK_USER_ID = "SIXPACK_USER_ID";
public static final String SIXPACK_API_KEY = "SIXPACK_API_KEY";
@Getter
protected static final Sixpack instance;
static {
instance = new Sixpack();
}
/**
* Creates a new dataset request builder chain.
*
* @return A builder chain to construct a new dataset request.
*/
public static EnvironmentSetter newDataset() {
return new EnvironmentSetter();
}
public static void refreshDataset(Dataset dataset, long waitUntil) {
Dataset freshDataset = Sixpack.instance.getDataset(dataset.getId(), waitUntil);
dataset.updateFrom(freshDataset);
}
public static class Utils {
public static T mapConfigurationToObject(Configuration output, Class clazz) {
return objectMapper.convertValue(output, clazz);
}
}
private static final MediaType JSON = MediaType.get("application/json; charset=utf-8");
private static OkHttpClient client = new OkHttpClient();
private static final ObjectMapper objectMapper = new ObjectMapper().registerModule(new JavaTimeModule());
static void setClient(OkHttpClient client) {
Sixpack.client = client;
}
private String url;
private String account;
private String userId;
private String apiKey;
Sixpack() {
url = getenv(SIXPACK_URL);
account = getenv(SIXPACK_ACCOUNT);
userId = getenv(SIXPACK_USER_ID);
apiKey = getenv(SIXPACK_API_KEY);
}
/**
* Sets the URL of the Sixpack instance to communicate with. Before calling that method, the url is loaded from the environment variable SIXPACK_URL.
*
* @param url The URL of the Sixpack instance.
* @return The same instance of the Sixpack client.
*/
@SuppressWarnings("UnusedReturnValue")
public Sixpack setUrl(String url) {
instance.url = url;
return instance;
}
/**
* Sets the account to use for the requests. Before calling that method, the account is loaded from the environment variable SIXPACK_ACCOUNT.
*
* @param account The account to use for the requests.
* @return The same instance of the Sixpack client.
*/
@SuppressWarnings("UnusedReturnValue")
public Sixpack setAccount(String account) {
instance.account = account;
return instance;
}
/**
* Sets the user ID to use for the requests. Before calling that method, the user ID is loaded from the environment variable SIXPACK_USER.
*
* @param userId The user ID to use for the requests.
* @return The same instance of the Sixpack client.
*/
@SuppressWarnings("UnusedReturnValue")
public Sixpack setUserId(String userId) {
instance.userId = userId;
return instance;
}
/**
* Sets the API key to use for the requests. Before calling that method, the API key is loaded from the environment variable SIXPACK_API_KEY.
*
* @param apiKey The API key to use for the requests.
* @return The same instance of the Sixpack client.
*/
@SuppressWarnings("UnusedReturnValue")
public Sixpack setApiKey(String apiKey) {
instance.apiKey = apiKey;
return instance;
}
private void validateSettings() {
validateParameter(url, SIXPACK_URL, "withUrl");
validateParameter(account, SIXPACK_ACCOUNT, "withAccount");
validateParameter(userId, SIXPACK_USER_ID, "withUserId");
validateParameter(apiKey, SIXPACK_API_KEY, "withApiKey");
}
private void validateParameter(String parameter,
String parameterName,
String parameterSetter) {
if (parameter == null) {
throw new SixpackClientException(mFormat(
"Parameter {} is not set, either set it as environment variable or initialise it with the respective setter Sixpack::{}",
parameterName, parameterSetter));
}
}
public Dataset requestDataset(Dataset requestedDataset) {
validateSettings();
String requestBodyString;
try {
requestBodyString = objectMapper.writeValueAsString(requestedDataset);
} catch (JsonProcessingException e) {
throw new SixpackClientException("Failed to serialize the requested dataset", e);
}
RequestBody body = RequestBody.create(requestBodyString, JSON);
Request.Builder httpRequestBuilder = new Request.Builder()
.url(mFormat("{}/1/datasets",
url))
.header(SX_ACCOUNT, account)
.header(SX_USER, userId)
.post(body);
sign(httpRequestBuilder);
Request httpRequest = httpRequestBuilder.build();
return getDataset(httpRequest);
}
public Dataset getDataset(String datasetId, long waitUntil) {
Request.Builder httpRequestBuilder = new Request.Builder()
.url(mFormat("{}/1/datasets/{}?waitUntil={}",
url,
datasetId,
waitUntil))
.header(SX_ACCOUNT, account)
.header(SX_USER, userId);
sign(httpRequestBuilder);
Request httpRequest = httpRequestBuilder.build();
return getDataset(httpRequest);
}
private Dataset getDataset(Request httpRequest) {
try (Response response = client.newCall(httpRequest).execute()) {
String responseBody;
try {
responseBody = response.body().string();
} catch (IOException e) {
throw new SixpackClientException("Failed to read the response body from Sixpack", e);
}
try {
return objectMapper.readValue(responseBody, Dataset.class);
} catch (JsonProcessingException e) {
try {
SixpackError error = objectMapper.readValue(responseBody, SixpackError.class);
throw new SixpackServerException(error.getMessage(), error.getHttpCode());
} catch (JsonProcessingException e2) {
throw new SixpackClientException(mFormat("Failed to deserialize the response body from Sixpack: {}",
responseBody),
e);
}
}
} catch (IOException e) {
throw new SixpackClientException("Failed to communicate with Sixpack", e);
}
}
private void sign(Request.Builder requestBuilder) {
assert requestBuilder.getUrl$okhttp() != null;
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
String nonce = UUID.randomUUID().toString();
String toSign = timestamp + "|" + nonce;
Mac mac = macFactory(apiKey);
String signature = bytesToHex(mac.doFinal(toSign.getBytes(UTF_8)));
requestBuilder.addHeader(SX_TIMESTAMP, timestamp);
requestBuilder.addHeader(SX_NONCE, nonce);
requestBuilder.addHeader(SX_SIGNATURE, signature);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy