Skip to content

Commit

Permalink
Merge pull request #185 from RedstoneTools/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
Matthias1590 authored May 20, 2023
2 parents 1bec5a5 + 0060ad8 commit 21cc6b0
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 99 deletions.
6 changes: 1 addition & 5 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,20 @@ repositories {
}
}


shadowJar {
archiveClassifier = "unmapped"

configurations = [project.configurations.shadow]

from("LICENSE")

relocate "com.squareup.okhttp3", "tools.redstone.shadow.com.squareup.okhttp3"
}

remapJar {
inputFile = shadowJar.archiveFile
}

dependencies {
// OkHttp
shadow implementation('com.squareup.okhttp3:okhttp:4.11.0')

// jUnit 5
include implementation('org.junit.jupiter:junit-jupiter:5.8.1')

Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ org.gradle.jvmargs=-Xmx4G
loader_version=0.14.6

# Mod Properties
mod_version = 1.18.2-1.0.2
mod_version = 1.18.2-1.0.3
maven_group = tools.redstone
archives_base_name = redstonetools

Expand Down
25 changes: 0 additions & 25 deletions gradle/libs.versions.toml

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ public T deserialize(String input) {
.filter(elem -> serialize(elem).toLowerCase().startsWith(inputLowerCase))
.toList();

var exactMatch = matches.stream().filter(elem -> serialize(elem).toLowerCase().equals(input)).findFirst();
if (exactMatch.isPresent()) {
return exactMatch.get();
}

if (matches.isEmpty()) {
throw new IllegalArgumentException("No such option '" + input + "'");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ public MacroManager() {
JsonArray macrosJson = null;
try {
Files.createDirectories(macrosFilePath.getParent());
var reader = Json.createReader(new FileReader(macrosFilePath.toFile()));
macrosJson = reader.readArray();
reader.close();
if (Files.exists(macrosFilePath)) {
var reader = Json.createReader(new FileReader(macrosFilePath.toFile()));
macrosJson = reader.readArray();
reader.close();
}
} catch (Exception e) {
e.printStackTrace();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,29 @@

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.TitleScreen;
import net.minecraft.text.Text;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import tools.redstone.redstonetools.RedstoneToolsClient;
import tools.redstone.redstonetools.gui.UpdatePopupScreen;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.concurrent.TimeUnit;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.time.temporal.ChronoUnit;

import static tools.redstone.redstonetools.RedstoneToolsClient.LOGGER;

@Mixin(TitleScreen.class)

public class UpdatePopupMixin extends Screen {
private static long timeout = 250;

public boolean updateChecked = false;

public UpdatePopupMixin(Text title) {
Expand All @@ -39,29 +37,40 @@ public void init(CallbackInfo ci) {
return;

try {
OkHttpClient client = new OkHttpClient.Builder()
.readTimeout(timeout, TimeUnit.MILLISECONDS)
.writeTimeout(timeout, TimeUnit.MILLISECONDS)
.connectTimeout(timeout, TimeUnit.MILLISECONDS)
LOGGER.info("Checking for updates...");

// timeout before aborting connection
// gh took quite long to respond on some machines
// so i think the timeout should be 1s
final long timeout = 1000;

HttpClient client = HttpClient.newBuilder()
.connectTimeout(Duration.of(timeout, ChronoUnit.MILLIS))
.build();
Request request = new Request.Builder()
.url("https://api.github.com/repos/RedstoneTools/redstonetools/releases/latest")
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.github.com/repos/RedstoneTools/redstonetools/releases/latest"))
.GET()
.build();
Response response = client.newCall(request).execute();
String responseBody = response.body().string();
if (response.code() != 200)
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
String responseBody = response.body();
if (response.statusCode() != 200)
return;

Gson gson = new Gson();
JsonObject release = gson.fromJson(responseBody, JsonObject.class);
URI uri = new URI(release.get("html_url").getAsString());
String newVersion = release.get("tag_name").getAsString();

if (RedstoneToolsClient.MOD_VERSION.equals(newVersion) || newVersion.contains("alpha") || newVersion.contains("beta"))
LOGGER.info("Found latest version: " + newVersion);
if (RedstoneToolsClient.MOD_VERSION.equals(newVersion) || newVersion.contains("alpha") || newVersion.contains("beta")) {
LOGGER.info("Already up to date, current version: " + RedstoneToolsClient.MOD_VERSION + ", new version: " + newVersion);
return;
}

LOGGER.info("Found newer version, current version: " + RedstoneToolsClient.MOD_VERSION + ", new version: " + newVersion);
MinecraftClient.getInstance().setScreen(new UpdatePopupScreen(this, uri, newVersion));
} catch (JsonSyntaxException | IOException | URISyntaxException e) {
} catch (Exception e) {
LOGGER.warn("Failed to check for RedstoneTools updates");
e.printStackTrace();
} finally {
updateChecked = true;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
package tools.redstone.redstonetools.telemetry;

import com.google.gson.Gson;
import kotlin.Pair;
import it.unimi.dsi.fastutil.Pair;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.client.MinecraftClient;
import okhttp3.*;
import org.jetbrains.annotations.NotNull;
import tools.redstone.redstonetools.telemetry.dto.TelemetryAuth;
import tools.redstone.redstonetools.telemetry.dto.TelemetryCommand;
import tools.redstone.redstonetools.telemetry.dto.TelemetryException;

import java.io.IOException;
import java.net.ConnectException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Instant;
import java.util.Objects;
import java.util.Queue;
Expand All @@ -31,17 +33,22 @@ public class TelemetryClient {
private static final int REQUEST_SEND_TIME_MILLISECONDS = 50;
private static final int REQUEST_VALID_FOR_SECONDS = 30;

private final TelemetryManager manager = INJECTOR.getInstance(TelemetryManager.class);

private static volatile Instant lastAuthorization = Instant.MIN;

private final Gson gson = new Gson();
private final OkHttpClient httpClient = new OkHttpClient();
private final Queue<Pair<Request.Builder, Instant>> requestQueue = new ConcurrentLinkedQueue<>();
private final HttpClient httpClient;
private final Queue<Pair<HttpRequest.Builder, Instant>> requestQueue = new ConcurrentLinkedQueue<>();

private volatile String token;

public TelemetryClient() {
LOGGER.info("Initializing telemetry client");

httpClient = HttpClient.newBuilder()
.build();

Executors.newSingleThreadExecutor()
.execute(this::refreshSessionThread);

Expand All @@ -50,19 +57,19 @@ public TelemetryClient() {
}

public void sendCommand(TelemetryCommand command) {
if (INJECTOR.getInstance(TelemetryManager.class).telemetryEnabled) {
if (manager.telemetryEnabled) {
addRequest(createRequest("/command", command));
}
}

public void sendException(TelemetryException exception) {
if (INJECTOR.getInstance(TelemetryManager.class).telemetryEnabled) {
if (manager.telemetryEnabled) {
addRequest(createRequest("/exception", exception));
}
}

private void addRequest(Request.Builder request) {
requestQueue.add(new Pair<>(request, Instant.now()));
private void addRequest(HttpRequest.Builder request) {
requestQueue.add(Pair.of(request, Instant.now()));
}

public synchronized void waitForQueueToEmpty() {
Expand All @@ -74,10 +81,17 @@ public synchronized void waitForQueueToEmpty() {
}
}

private Request.Builder createRequest(String path, Object body) {
return new Request.Builder()
.url(BASE_URL + path)
.post(RequestBody.create(body == null ? "" : gson.toJson(body), MediaType.parse("application/json")));
private HttpRequest.Builder createRequest(String path, Object body) {
final String bodyData = body == null ? "" : gson.toJson(body);
return HttpRequest.newBuilder()
.header("Content-Type", "application/json")
.uri(URI.create(BASE_URL + path))
.POST(HttpRequest.BodyPublishers.ofString(bodyData));
}

private boolean isSuccessful(HttpResponse<?> response) {
if (response == null) return false;
return response.statusCode() >= 200 && response.statusCode() < 300;
}

private synchronized CompletableFuture<Void> sendQueuedRequestsAsync() {
Expand All @@ -90,8 +104,8 @@ private synchronized CompletableFuture<Void> sendQueuedRequestsAsync() {
}

var pair = Objects.requireNonNull(requestQueue.peek());
var request = pair.component1();
var queuedAt = pair.component2();
var request = pair.first();
var queuedAt = pair.second();

if (queuedAt.plusSeconds(REQUEST_VALID_FOR_SECONDS).isBefore(Instant.now())) {
requestQueue.remove();
Expand All @@ -100,12 +114,12 @@ private synchronized CompletableFuture<Void> sendQueuedRequestsAsync() {
}

if (token != null) {
request.addHeader("Authorization", token);
request.header("Authorization", token);
}

var response = sendPostRequestAsync(request).join();
var response = sendPostRequest(request);

if (response == null || !response.isSuccessful()) {
if (response == null || !isSuccessful(response)) {
if (response != null && responseIsUnauthorized(response)) {
lastAuthorization = Instant.MIN;
}
Expand All @@ -129,21 +143,26 @@ private synchronized CompletableFuture<Void> sendQueuedRequestsAsync() {
});
}

private synchronized @NotNull CompletableFuture<Response> sendPostRequestAsync(Request.Builder request) {
LOGGER.trace("Sending telemetry request to " + request.build().url());
private synchronized HttpResponse<String> sendPostRequest(HttpRequest.Builder request) {
LOGGER.trace("Sending telemetry request to " + request.build().uri());

return CompletableFuture.supplyAsync(() -> {
// this doesnt have to be async as the only place this is
// ever called is from another thread

// return CompletableFuture.supplyAsync(() -> {
try {
return httpClient.newCall(request.build()).execute();
return httpClient.send(request.build()
/* the json as a string */,
HttpResponse.BodyHandlers.ofString());
} catch (ConnectException e) {
// Either the server is down or the user isn't connected to the internet
LOGGER.debug("Failed to send telemetry request: " + e.getMessage());
} catch (IOException e) {
} catch (InterruptedException | IOException e) {
LOGGER.error("Failed to send telemetry request", e);
}

return null;
});
// });
}

private void refreshSessionThread() {
Expand All @@ -165,27 +184,25 @@ private synchronized CompletableFuture<Boolean> refreshSessionAsync() {
var request = createRequest(token == null ? "/session/create" : "/session/refresh", getAuth());

if (token != null) {
request.addHeader("Authorization", token);
request.header("Authorization", token);
}

var response = sendPostRequestAsync(request).join();
var response = sendPostRequest(request);

if (response == null || !response.isSuccessful()) {
if (response != null && responseIsUnauthorized(response)) {
if (response == null)
return false;
if (!isSuccessful(response)) {
LOGGER.warn("Failed to refresh telemetry session, response code: " + response.statusCode() + ", message: " + response.body());
if (responseIsUnauthorized(response)) {
token = null;
}

return false;
}

try (var body = response.body()) {
token = body.string();
} catch (IOException e) {
LOGGER.error("Failed to read telemetry session response", e);
return false;
}
token = response.body();

LOGGER.debug("Refreshed telemetry session");
LOGGER.info("Refreshed telemetry session");
lastAuthorization = Instant.now();
return true;
});
Expand All @@ -201,8 +218,8 @@ private TelemetryAuth getAuth() {
);
}

private static boolean responseIsUnauthorized(Response response) {
return response.code() == 401
|| response.code() == 403;
private static boolean responseIsUnauthorized(HttpResponse<?> response) {
return response.statusCode() == 401
|| response.statusCode() == 403;
}
}
Loading

0 comments on commit 21cc6b0

Please sign in to comment.