package net.buycraft.plugin.client;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import net.buycraft.plugin.data.Coupon;
import net.buycraft.plugin.data.RecentPayment;
import net.buycraft.plugin.data.responses.*;
import okhttp3.*;
import java.io.IOException;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Objects;
public class ProductionApiClient implements ApiClient {
private static final String API_URL = "https://plugin.buycraft.net";
private static final String API_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ssX";
private final Gson gson = new GsonBuilder()
.setDateFormat(API_DATE_FORMAT)
.create();
private final OkHttpClient httpClient;
private final String secret;
public ProductionApiClient(String secret) {
this(secret, new OkHttpClient());
}
public ProductionApiClient(String secret, OkHttpClient client) {
this.secret = Objects.requireNonNull(secret, "secret");
this.httpClient = Objects.requireNonNull(client, "client");
}
private Request.Builder getBuilder(String endpoint) {
return new Request.Builder()
.url(API_URL + endpoint)
.addHeader("X-Buycraft-Secret", secret)
.addHeader("Accept", "application/json")
.addHeader("User-Agent", "BuycraftX");
}
private ApiException handleError(Response response, ResponseBody body) throws IOException {
String in = body.string();
if (!Objects.equals(response.header("Content-Type"), "application/json")) {
return new ApiException("Unexpected content-type " + response.header("Content-Type"), response.request(), response, in);
}
BuycraftError error = gson.fromJson(in, BuycraftError.class);
if (error != null) {
return new ApiException(error.getErrorMessage(), response.request(), response, in);
} else {
return new ApiException("Unknown error occurred whilst deserializing error object.", response.request(), response, in);
}
}
private <T> T get(String endpoint, Type type) throws IOException, ApiException {
return get(endpoint, null, type);
}
private <T> T get(String endpoint, CacheControl control, Type type) throws IOException, ApiException {
Request.Builder requestBuilder = getBuilder(endpoint).get();
if (control != null) requestBuilder.cacheControl(control);
Request request = requestBuilder.build();
Response response = httpClient.newCall(request).execute();
try (ResponseBody body = response.body()) {
if (response.isSuccessful()) {
return gson.fromJson(body.charStream(), type);
} else {
throw handleError(response, body);
}
}
}
@Override
public ServerInformation getServerInformation() throws IOException, ApiException {
return get("/information", CacheControl.FORCE_NETWORK, ServerInformation.class);
}
@Override
public Listing retrieveListing() throws IOException, ApiException {
Listing listing = get("/listing", CacheControl.FORCE_NETWORK, Listing.class);
listing.order();
return listing;
}
@Override
public QueueInformation retrieveOfflineQueue() throws IOException, ApiException {
return get("/queue/offline-commands", CacheControl.FORCE_NETWORK, QueueInformation.class);
}
@Override
public DueQueueInformation retrieveDueQueue(int limit, int page) throws IOException, ApiException {
return get("/queue?limit=" + limit + "&page=" + page, CacheControl.FORCE_NETWORK, DueQueueInformation.class);
}
@Override
public QueueInformation getPlayerQueue(int id) throws IOException, ApiException {
return get("/queue/online-commands/" + id, CacheControl.FORCE_NETWORK, QueueInformation.class);
}
@Override
public void deleteCommand(List<Integer> ids) throws IOException, ApiException {
FormBody.Builder builder = new FormBody.Builder();
for (Integer id : ids) {
builder.add("ids[]", id.toString());
}
Request request = getBuilder("/queue")
.method("DELETE", builder.build())
.build();
Response response = httpClient.newCall(request).execute();
try (ResponseBody body = response.body()) {
if (!response.isSuccessful()) {
throw handleError(response, body);
}
}
}
@Override
public CheckoutUrlResponse getCheckoutUri(String username, int packageId) throws IOException, ApiException {
RequestBody body = new FormBody.Builder()
.add("username", username)
.add("package_id", Integer.toString(packageId))
.build();
Request request = getBuilder("/checkout")
.post(body)
.build();
Response response = httpClient.newCall(request).execute();
try (ResponseBody rspBody = response.body()) {
if (!response.isSuccessful()) {
throw handleError(response, rspBody);
} else {
return gson.fromJson(rspBody.charStream(), CheckoutUrlResponse.class);
}
}
}
@Override
public List<RecentPayment> getRecentPayments(int limit) throws IOException, ApiException {
return get("/payments?limit=" + limit, CacheControl.FORCE_NETWORK, new TypeToken<List<RecentPayment>>() {
}.getType());
}
@Override
public List<Coupon> getAllCoupons() throws IOException, ApiException {
CouponListing listing = get("/coupons", CouponListing.class);
return listing.getData();
}
@Override
public Coupon getCoupon(int id) throws IOException, ApiException {
CouponSingleListing listing = get("/coupons/" + id, CouponSingleListing.class);
return listing.getData();
}
@Override
public void deleteCoupon(int id) throws IOException, ApiException {
Request request = getBuilder("/coupons/" + id)
.delete()
.build();
Response response = httpClient.newCall(request).execute();
try (ResponseBody rspBody = response.body()) {
if (!response.isSuccessful()) {
throw handleError(response, rspBody);
}
}
}
@Override
public Coupon createCoupon(Coupon coupon) throws IOException, ApiException {
FormBody.Builder build = new FormBody.Builder()
.add("code", coupon.getCode())
.add("effective_on", coupon.getEffective().getType());
switch (coupon.getEffective().getType()) {
case "packages":
for (Integer id1 : coupon.getEffective().getPackages()) {
build.add("packages[]", Integer.toString(id1));
}
break;
case "categories":
for (Integer id2 : coupon.getEffective().getCategories()) {
build.add("categories[]", Integer.toString(id2));
}
break;
}
RequestBody body = build.add("discount_type", coupon.getDiscount().getType())
.add("discount_amount", coupon.getDiscount().getValue().toPlainString())
.add("discount_percentage", coupon.getDiscount().getPercentage().toPlainString())
.add("expire_type", coupon.getExpire().getType())
.add("expire_limit", Integer.toString(coupon.getExpire().getLimit()))
.add("expire_date", new SimpleDateFormat(API_DATE_FORMAT).format(coupon.getExpire().getDate()))
.add("start_date", new SimpleDateFormat(API_DATE_FORMAT).format(coupon.getStartDate()))
.add("basket_type", coupon.getBasketType())
.add("minimum", coupon.getMinimum().toPlainString())
.add("redeem_limit", Integer.toString(coupon.getUserLimit()))
.build();
Request request = getBuilder("/coupons")
.post(body)
.build();
Response response = httpClient.newCall(request).execute();
try (ResponseBody rspBody = response.body()) {
if (!response.isSuccessful()) {
throw handleError(response, rspBody);
} else {
return gson.fromJson(rspBody.charStream(), CouponSingleListing.class).getData();
}
}
}
}