Skip to content

Commit

Permalink
MineSkin Client v2 (#17)
Browse files Browse the repository at this point in the history
* start on v2 client

* implement get

* implement other generate endpoints

* client builder

* use builder in tests

* move things

* implement upload tests & abstract skin types

* move client to interface

* next request getter

* fix apache client

* use revision for version

* add example

* fix skin file

* track next requests by api key

* common test executor

* compute delay & set delay on error

* null info

* use max delay

* update httpclient
  • Loading branch information
InventivetalentDev authored Jul 31, 2024
1 parent 5c4e527 commit 67eb450
Show file tree
Hide file tree
Showing 44 changed files with 1,730 additions and 958 deletions.
69 changes: 60 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,70 @@ If you own a Minecraft account you don't actively use and want to contibute to t
please [add your account here](https://mineskin.org/account)!

```java
MineSkinClient client = new MineSkinClient("MyUserAgent");
client.generateUrl("https://image.url", SkinOptions.name("some cool skin")).thenAccept(skin -> {
...
})
public class Example {

private static final MineSkinClient CLIENT = MineSkinClient.builder()
.requestHandler(JsoupRequestHandler::new)
.userAgent("MyMineSkinApp/v1.0")
.apiKey("your-api-key")
.build();

public static void main(String[] args) throws FileNotFoundException {
GenerateOptions options = GenerateOptions.create()
.name("My Skin")
.visibility(Visibility.PUBLIC);
File file = new File("skin.jpg");
CLIENT.generateUpload(file, options)
.thenAccept(response -> {
// get generated skin
Skin skin = response.getSkin();
System.out.println(skin);
})
.exceptionally(throwable -> {
throwable.printStackTrace();
if (throwable instanceof CompletionException completionException) {
throwable = completionException.getCause();
}

if (throwable instanceof MineSkinRequestException requestException) {
// get error details
MineSkinResponse response = requestException.getResponse();
System.out.println(response.getMessageOrError());
}
return null;
});

CLIENT.getSkinByUuid("skinuuid")
.thenAccept(response -> {
// get existing skin
Skin skin = response.getSkin();
System.out.println(skin);
});
}

}
```


```xml
<dependency>
<groupId>org.mineskin</groupId>
<artifactId>java-client</artifactId>
<version>1.2.3-SNAPSHOT</version>
</dependency>
<depencies>
<dependency>
<groupId>org.mineskin</groupId>
<artifactId>java-client</artifactId>
<version>2.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.mineskin</groupId>
<artifactId>java-client-jsoup</artifactId>
<version>2.0.0-SNAPSHOT</version>
</dependency>
<!-- alternatively use apache httpcommons -->
<!-- <dependency>-->
<!-- <groupId>org.mineskin</groupId>-->
<!-- <artifactId>java-client-apache</artifactId>-->
<!-- <version>2.0.0-SNAPSHOT</version>-->
<!-- </dependency>-->
</depencies>
```
```xml
<repositories>
Expand Down
41 changes: 41 additions & 0 deletions apache/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.mineskin</groupId>
<artifactId>client-parent</artifactId>
<version>PARENT</version>
</parent>

<artifactId>java-client-apache</artifactId>
<version>${revision}</version>

<properties>
<maven.compiler.source>22</maven.compiler.source>
<maven.compiler.target>22</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>org.mineskin</groupId>
<artifactId>java-client</artifactId>
<version>${revision}</version>
</dependency>

<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.14</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5.5</version>
</dependency>
</dependencies>


</project>
130 changes: 130 additions & 0 deletions apache/src/main/java/org/mineskin/ApacheRequestHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package org.mineskin;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicHeader;
import org.mineskin.exception.MineSkinRequestException;
import org.mineskin.exception.MineskinException;
import org.mineskin.request.RequestHandler;
import org.mineskin.response.MineSkinResponse;
import org.mineskin.response.ResponseConstructor;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class ApacheRequestHandler extends RequestHandler {

private final Gson gson;

private final HttpClient httpClient;

public ApacheRequestHandler(
String userAgent, String apiKey,
int timeout,
Gson gson) {
super(userAgent, apiKey, timeout, gson);
this.gson = gson;

List<Header> defaultHeaders = new ArrayList<>();
if (apiKey != null) {
defaultHeaders.add(new BasicHeader("Authorization", "Bearer " + apiKey));
defaultHeaders.add(new BasicHeader("Accept", "application/json"));
}
this.httpClient = HttpClientBuilder.create()
.setDefaultRequestConfig(RequestConfig.copy(RequestConfig.DEFAULT)
.setSocketTimeout(timeout)
.setConnectTimeout(timeout)
.setConnectionRequestTimeout(timeout)
.build())
.setUserAgent(userAgent)
.setDefaultHeaders(defaultHeaders)
.build();
}

private <T, R extends MineSkinResponse<T>> R wrapResponse(HttpResponse response, Class<T> clazz, ResponseConstructor<T, R> constructor) throws IOException {
String rawBody = null;
try {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()))) {
rawBody = reader.lines().collect(Collectors.joining("\n"));
}

JsonObject jsonBody = gson.fromJson(rawBody, JsonObject.class);
R wrapped = constructor.construct(
response.getStatusLine().getStatusCode(),
lowercaseHeaders(response.getAllHeaders()),
jsonBody,
gson, clazz
);
if (!wrapped.isSuccess()) {
throw new MineSkinRequestException(wrapped.getError().orElse("Request Failed"), wrapped);
}
return wrapped;
} catch (JsonParseException e) {
MineSkinClientImpl.LOGGER.log(Level.WARNING, "Failed to parse response body: " + rawBody, e);
throw new MineskinException("Failed to parse response", e);
}
}

private Map<String, String> lowercaseHeaders(Header[] headers) {
return Stream.of(headers)
.collect(Collectors.toMap(
header -> header.getName().toLowerCase(),
Header::getValue
));
}

@Override
public <T, R extends MineSkinResponse<T>> R getJson(String url, Class<T> clazz, ResponseConstructor<T, R> constructor) throws IOException {
MineSkinClientImpl.LOGGER.fine("GET " + url);
HttpResponse response = this.httpClient.execute(new HttpGet(url));
return wrapResponse(response, clazz, constructor);
}

@Override
public <T, R extends MineSkinResponse<T>> R postJson(String url, JsonObject data, Class<T> clazz, ResponseConstructor<T, R> constructor) throws IOException {
MineSkinClientImpl.LOGGER.fine("POST " + url);
HttpPost post = new HttpPost(url);
post.setHeader("Content-Type", ContentType.APPLICATION_JSON.getMimeType());
StringEntity entity = new StringEntity(gson.toJson(data), ContentType.APPLICATION_JSON);
post.setEntity(entity);
HttpResponse response = this.httpClient.execute(post);
return wrapResponse(response, clazz, constructor);
}

@Override
public <T, R extends MineSkinResponse<T>> R postFormDataFile(String url, String key, String filename, InputStream in, Map<String, String> data, Class<T> clazz, ResponseConstructor<T, R> constructor) throws IOException {
MineSkinClientImpl.LOGGER.fine("POST " + url);
HttpPost post = new HttpPost(url);
MultipartEntityBuilder multipart = MultipartEntityBuilder.create()
.setBoundary("mineskin-" + System.currentTimeMillis())
.addBinaryBody(key, in, ContentType.IMAGE_PNG, filename);
for (Map.Entry<String, String> entry : data.entrySet()) {
multipart.addTextBody(entry.getKey(), entry.getValue());
}
HttpEntity entity = multipart.build();
post.setEntity(entity);
HttpResponse response = this.httpClient.execute(post);
return wrapResponse(response, clazz, constructor);
}

}
6 changes: 6 additions & 0 deletions core/java-client (1).iml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="CheckStyle-IDEA-Module" serialisationVersion="2">
<option name="activeLocationsIds" />
</component>
</module>
28 changes: 28 additions & 0 deletions core/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.mineskin</groupId>
<artifactId>client-parent</artifactId>
<version>PARENT</version>
</parent>

<artifactId>java-client</artifactId>
<version>${revision}</version>

<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>32.1.2-jre</version>
</dependency>
</dependencies>

</project>
Loading

0 comments on commit 67eb450

Please sign in to comment.