Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions eternalcode-commons-updater-example/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
plugins {
`commons-java-17`
}

dependencies {
implementation(project(":eternalcode-commons-updater"))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.eternalcode.commons.updater.example;

import com.eternalcode.commons.updater.UpdateResult;

public class ExampleChecker {
public static void main(String[] args) {
ExampleUpdateService service = new ExampleUpdateService();

UpdateResult modrinthResult = service.checkModrinth("EternalCombat", "2.2.0");
System.out.println("Modrinth update available: " + modrinthResult.isUpdateAvailable());
if (modrinthResult.isUpdateAvailable()) {
System.out.println("Latest: " + modrinthResult.latestVersion());
System.out.println("Download: " + modrinthResult.downloadUrl());
System.out.println("Release page: " + modrinthResult.releaseUrl());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.eternalcode.commons.updater.example;

import com.eternalcode.commons.updater.UpdateResult;
import com.eternalcode.commons.updater.Version;
import com.eternalcode.commons.updater.impl.ModrinthUpdateChecker;

public final class ExampleUpdateService {
private final ModrinthUpdateChecker modrinthChecker = new ModrinthUpdateChecker();

public UpdateResult checkModrinth(String projectId, String currentVersion) {
return modrinthChecker.check(projectId, new Version(currentVersion));
}
}
10 changes: 10 additions & 0 deletions eternalcode-commons-updater/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
plugins {
`commons-java-17`
`commons-publish`
`commons-repositories`
`commons-java-unit-test`
}

tasks.test {
useJUnitPlatform()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.eternalcode.commons.updater;

public interface UpdateChecker {

UpdateResult check(String projectId, Version currentVersion);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.eternalcode.commons.updater;

public record UpdateResult(Version currentVersion, Version latestVersion, String downloadUrl, String releaseUrl) {

public boolean isUpdateAvailable() {
return this.latestVersion.isNewerThan(this.currentVersion);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.eternalcode.commons.updater;

public class Version implements Comparable<Version> {

private final String value;

public Version(String version) {
this.value = version.trim();
}

@Override
public int compareTo(Version version) {
return this.value.compareTo(version.value);
}

public boolean isNewerThan(Version version) {
return this.value.compareTo(version.value) > 0;
}

@Override
public boolean equals(Object object) {
return object instanceof Version other && value.equals(other.value);
}

@Override
public int hashCode() {
return value.hashCode();
}

@Override
public String toString() {
return this.value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package com.eternalcode.commons.updater.impl;

import com.eternalcode.commons.updater.UpdateChecker;
import com.eternalcode.commons.updater.UpdateResult;
import com.eternalcode.commons.updater.Version;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.Optional;

public final class ModrinthUpdateChecker implements UpdateChecker {

private static final String API_BASE_URL = "https://api.modrinth.com/v2";
private static final String MODRINTH_BASE_URL = "https://modrinth.com/mod";
private static final String USER_AGENT = "UpdateChecker/1.0";
private static final Duration TIMEOUT = Duration.ofSeconds(10);

private final HttpClient client;

public ModrinthUpdateChecker() {
this.client = HttpClient.newBuilder().connectTimeout(TIMEOUT).build();
}

@Override
public UpdateResult check(String projectId, Version currentVersion) {
if (projectId == null || projectId.trim().isEmpty()) {
throw new IllegalArgumentException("Project ID cannot be null or empty");
}

try {
String url = API_BASE_URL + "/project/" + projectId + "/version";

HttpRequest request =
HttpRequest.newBuilder().uri(URI.create(url)).header("User-Agent", USER_AGENT).timeout(TIMEOUT).build();

HttpResponse<String> response = this.client.send(request, HttpResponse.BodyHandlers.ofString());

if (response.statusCode() != 200) {
return createEmptyResult(currentVersion);
}

String json = response.body();
if (json == null || json.trim().isEmpty()) {
return createEmptyResult(currentVersion);
}

Optional<String> versionNumber = extractJsonValue(json, "version_number");
Optional<String> downloadUrl = extractJsonValue(json, "url");

if (versionNumber.isEmpty()) {
return createEmptyResult(currentVersion);
}

String releaseUrl = MODRINTH_BASE_URL + "/" + projectId + "/version/" + versionNumber.get();
Version latestVersion = new Version(versionNumber.get());

return new UpdateResult(currentVersion, latestVersion, downloadUrl.orElse(null), releaseUrl);
}
catch (Exception exception) {
throw new RuntimeException("Failed to check Modrinth updates for project: " + projectId, exception);
}
}

private UpdateResult createEmptyResult(Version currentVersion) {
return new UpdateResult(currentVersion, currentVersion, null, null);
}

private Optional<String> extractJsonValue(String json, String key) {
if (json == null || key == null) {
return Optional.empty();
}

String pattern = "\"" + key + "\":\"";
int start = json.indexOf(pattern);

if (start == -1) {
return Optional.empty();
}

start += pattern.length();
int end = json.indexOf("\"", start);

if (end == -1) {
return Optional.empty();
}

String value = json.substring(start, end);
return value.isEmpty() ? Optional.empty() : Optional.of(value);
}
}
2 changes: 2 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ include(":eternalcode-commons-bukkit")
include(":eternalcode-commons-adventure")
include(":eternalcode-commons-shared")
include("eternalcode-commons-folia")
include("eternalcode-commons-updater")
include("eternalcode-commons-updater-example")