Created
March 16, 2025 01:43
-
-
Save palexdev/775f3824efd9a20a9ed35cdc80386fb4 to your computer and use it in GitHub Desktop.
A very simple API to check for updates
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import javax.net.ssl.HttpsURLConnection; | |
import java.io.BufferedReader; | |
import java.io.IOException; | |
import java.io.InputStreamReader; | |
import java.net.URI; | |
import java.util.regex.Matcher; | |
import java.util.regex.Pattern; | |
public class GitHubUpdateChecker implements UpdateChecker { | |
private final String currentVersion; | |
private final String url; | |
public GitHubUpdateChecker(String currentVersion, String owner, String repo) { | |
this.currentVersion = currentVersion; | |
this.url = "https://api.github.com/repos/%s/%s/releases/latest" | |
.formatted(owner, repo); | |
} | |
@Override | |
public String getCurrentVersion() { | |
return currentVersion; | |
} | |
@Override | |
public String getLatestVersion() throws UpdateCheckException { | |
try { | |
HttpsURLConnection connection = (HttpsURLConnection) URI.create(url).toURL().openConnection(); | |
connection.setRequestProperty("Accept", "application/vnd.github+json"); | |
connection.setRequestProperty("X-GitHub-Api-Version", "2022-11-28"); | |
connection.setRequestMethod("GET"); | |
String response = read(connection); | |
if (response.isBlank()) return null; | |
Pattern tagPattern = Pattern.compile("\"tag_name\"\\s*:\\s*\"([^,]*)\","); | |
Matcher tagMatcher = tagPattern.matcher(response); | |
if (tagMatcher.find()) return tagMatcher.group(1); | |
} catch (Exception ex) { | |
throw new UpdateCheckException(ex); | |
} | |
return null; | |
} | |
@Override | |
public int compare(String current, String latest) { | |
if (latest == null) return -2; | |
long currL = Long.parseLong(current.replace(".", "")); | |
long latestL = Long.parseLong(latest.replace(".", "")); | |
return Long.compare(latestL, currL); | |
} | |
protected String read(HttpsURLConnection connection) throws IOException { | |
StringBuilder sb = new StringBuilder(); | |
try (BufferedReader reader = new BufferedReader( | |
new InputStreamReader(connection.getInputStream()) | |
)) { | |
String line; | |
while ((line = reader.readLine()) != null) { | |
sb.append(line); | |
} | |
} | |
return sb.toString(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.Comparator; | |
import java.util.concurrent.CompletableFuture; | |
import java.util.concurrent.Executor; | |
import java.util.concurrent.Executors; | |
import java.util.function.Consumer; | |
public interface UpdateChecker { | |
String getCurrentVersion(); | |
String getLatestVersion() throws UpdateCheckException; | |
/// Similar to [Comparator#compare(Object,Object)] but inverted: | |
/// | |
/// - negative number: current version is newer than latest | |
/// - positive number: current version is older than latest | |
/// - zero: same version | |
int compare(String current, String latest); | |
default boolean isBeta(String version) { | |
return false; | |
} | |
default boolean allowBeta() { | |
return false; | |
} | |
default boolean isUpdateAvailable() { | |
try { | |
String curr = getCurrentVersion(); | |
String latest = getLatestVersion(); | |
return compare(curr, latest) > 0 | |
&& (!isBeta(latest) || allowBeta()); | |
} catch (UpdateCheckException ex) { | |
/* TODO add logging here */ | |
return false; | |
} | |
} | |
default void isUpdateAvailableAsync(Consumer<Boolean> callback) { | |
CompletableFuture.supplyAsync(this::isUpdateAvailable, Helper.executor) | |
.thenAccept(callback); | |
} | |
/* Helper */ | |
class Helper { | |
protected static final Executor executor = Executors.newVirtualThreadPerTaskExecutor(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class UpdateCheckException extends RuntimeException { | |
public UpdateCheckException(String message) { | |
super(message); | |
} | |
public UpdateCheckException(String message, Throwable cause) { | |
super(message, cause); | |
} | |
public UpdateCheckException(Throwable cause) { | |
super(cause); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment