parent
6f28250a10
commit
a7506bd3c6
12 changed files with 394 additions and 2 deletions
|
@ -29,7 +29,9 @@ public record TweaksConfig(
|
|||
int compassPrecision,
|
||||
|
||||
boolean pomodoroEnabled,
|
||||
boolean pomodoroForce
|
||||
boolean pomodoroForce,
|
||||
|
||||
boolean updaterEnabled
|
||||
) {
|
||||
public static final int CONFIG_VERSION = 1;
|
||||
private static TweaksConfig config;
|
||||
|
@ -87,7 +89,8 @@ public record TweaksConfig(
|
|||
motdEnabled, motdSet,
|
||||
chatEnabled, chatLocalEvents, chatDefaultName,
|
||||
compassEnabled, compassWidth, compassPrecision,
|
||||
pomodoroEnabled, pomodoroForce
|
||||
pomodoroEnabled, pomodoroForce,
|
||||
true // TODO
|
||||
);
|
||||
|
||||
return TweaksConfig.config;
|
||||
|
|
|
@ -10,6 +10,7 @@ import eu.m724.tweaks.ping.PingChecker;
|
|||
import eu.m724.tweaks.ping.PingCommands;
|
||||
import eu.m724.tweaks.pomodoro.PomodoroCommands;
|
||||
import eu.m724.tweaks.pomodoro.PomodoroManager;
|
||||
import eu.m724.tweaks.updater.UpdaterManager;
|
||||
import eu.m724.tweaks.worldborder.WorldBorderManager;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
|
@ -66,5 +67,12 @@ public class TweaksPlugin extends JavaPlugin {
|
|||
getCommand("pomodoro").setExecutor(new PomodoroCommands());
|
||||
}
|
||||
|
||||
if (config.updaterEnabled()) {
|
||||
try {
|
||||
new UpdaterManager(this).init();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
58
src/main/java/eu/m724/tweaks/updater/PluginScanner.java
Normal file
58
src/main/java/eu/m724/tweaks/updater/PluginScanner.java
Normal file
|
@ -0,0 +1,58 @@
|
|||
package eu.m724.tweaks.updater;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.annotations.JsonAdapter;
|
||||
import eu.m724.tweaks.updater.cache.SpigotResource;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
public class PluginScanner {
|
||||
private final Plugin thisPlugin;
|
||||
|
||||
PluginScanner(Plugin thisPlugin) {
|
||||
this.thisPlugin = thisPlugin;
|
||||
}
|
||||
|
||||
public Set<SpigotResource> load() throws IOException {
|
||||
File installedPluginsYml = new File(thisPlugin.getDataFolder(), "installed_plugins.yml");
|
||||
|
||||
if (!installedPluginsYml.exists()) {
|
||||
thisPlugin.saveResource("installed_plugins.yml", false);
|
||||
}
|
||||
|
||||
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(installedPluginsYml);
|
||||
|
||||
|
||||
Plugin[] plugins = thisPlugin.getServer().getPluginManager().getPlugins();
|
||||
Set<SpigotResource> spigotResources = new HashSet<>();
|
||||
|
||||
for (Plugin plugin : plugins) {
|
||||
System.out.println("Found " + plugin.getName());
|
||||
String pluginName = plugin.getName();
|
||||
|
||||
if (!configuration.isSet(pluginName)) {
|
||||
configuration.set(pluginName, -1);
|
||||
continue;
|
||||
}
|
||||
|
||||
int pluginId = configuration.getInt(pluginName);
|
||||
if (pluginId != -1) {
|
||||
spigotResources.add(
|
||||
new SpigotResource(plugin, pluginId)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
configuration.save(installedPluginsYml);
|
||||
|
||||
return spigotResources;
|
||||
|
||||
}
|
||||
}
|
59
src/main/java/eu/m724/tweaks/updater/UpdateChecker.java
Normal file
59
src/main/java/eu/m724/tweaks/updater/UpdateChecker.java
Normal file
|
@ -0,0 +1,59 @@
|
|||
package eu.m724.tweaks.updater;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import eu.m724.tweaks.updater.cache.ResourceVersion;
|
||||
import eu.m724.tweaks.updater.cache.SpigotResource;
|
||||
import eu.m724.tweaks.updater.cache.VersionedResource;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.eclipse.aether.impl.UpdateCheck;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class UpdateChecker extends BukkitRunnable {
|
||||
private final Set<VersionedResource> resources;
|
||||
private final Logger logger;
|
||||
|
||||
UpdateChecker(Plugin plugin, Set<VersionedResource> resources) {
|
||||
this.logger = Logger.getLogger(plugin.getLogger().getName() + "." + getClass().getSimpleName());
|
||||
this.resources = resources; // TODO make a copy?
|
||||
}
|
||||
|
||||
private void checkAll() {
|
||||
logger.info("Now checking all plugins");
|
||||
for (VersionedResource versionedResource : Set.copyOf(resources)) {
|
||||
logger.info(versionedResource.resource().resourceId() + " " + versionedResource.resource().plugin().getName());
|
||||
int page = versionedResource.running() != null ? versionedResource.running().page() : 1;
|
||||
|
||||
try {
|
||||
VersionedResource newResource = new VersionFinder(versionedResource.resource(), page).join(); // this runs async so it's ok
|
||||
if (!versionedResource.equals(newResource)) {
|
||||
resources.remove(versionedResource);
|
||||
resources.add(newResource);
|
||||
// TODO
|
||||
}
|
||||
} catch (CompletionException e) {
|
||||
logger.severe("Unable to refresh %s: %s".formatted(versionedResource.resource().plugin().getName(), e.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
checkAll();
|
||||
}
|
||||
}
|
44
src/main/java/eu/m724/tweaks/updater/UpdaterManager.java
Normal file
44
src/main/java/eu/m724/tweaks/updater/UpdaterManager.java
Normal file
|
@ -0,0 +1,44 @@
|
|||
package eu.m724.tweaks.updater;
|
||||
|
||||
import eu.m724.tweaks.updater.cache.ResourceVersion;
|
||||
import eu.m724.tweaks.updater.cache.SpigotResource;
|
||||
import eu.m724.tweaks.updater.cache.VersionedResource;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class UpdaterManager {
|
||||
private final Plugin plugin;
|
||||
|
||||
public UpdaterManager(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public void init() throws IOException {
|
||||
// scan installed plugins
|
||||
Set<SpigotResource> resources = new PluginScanner(plugin).load();
|
||||
|
||||
// load installed versions from cache
|
||||
File cacheFile = new File(plugin.getDataFolder(), "version cache");
|
||||
Set<ResourceVersion> installedVersions;
|
||||
try (FileInputStream inputStream = new FileInputStream(cacheFile)) {
|
||||
installedVersions = VersionCheckCache.loadAll(inputStream);
|
||||
}
|
||||
|
||||
Set<VersionedResource> versionedResources = installedVersions.stream()
|
||||
.map(rv -> new VersionedResource(
|
||||
resources.stream().filter(r -> r.resourceId() == rv.resourceId()).findFirst().get(),
|
||||
rv,
|
||||
null
|
||||
)).collect(Collectors.toSet());
|
||||
|
||||
|
||||
new UpdateChecker(plugin, versionedResources)
|
||||
.runTaskTimerAsynchronously(plugin, 600, 12 * 3600 * 20);
|
||||
}
|
||||
}
|
75
src/main/java/eu/m724/tweaks/updater/VersionCheckCache.java
Normal file
75
src/main/java/eu/m724/tweaks/updater/VersionCheckCache.java
Normal file
|
@ -0,0 +1,75 @@
|
|||
package eu.m724.tweaks.updater;
|
||||
|
||||
import eu.m724.tweaks.updater.cache.ResourceVersion;
|
||||
import eu.m724.tweaks.updater.cache.VersionedResource;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class VersionCheckCache {
|
||||
private static final byte FILE_VERSION = 1;
|
||||
|
||||
public static Set<ResourceVersion> loadAll(FileInputStream inputStream) throws IOException {
|
||||
byte fileVersion = (byte) inputStream.read();
|
||||
if (fileVersion != FILE_VERSION) throw new FileVersionMismatchException(fileVersion, FILE_VERSION);
|
||||
|
||||
Set<ResourceVersion> versions = new HashSet<>();
|
||||
int i = 0;
|
||||
|
||||
byte[] buffer = new byte[8]; // 3 + 2 + 3
|
||||
while (inputStream.available() > 0) {
|
||||
int read = inputStream.read(buffer);
|
||||
if (read < 8) break; // end of file
|
||||
if (++i > 10000) throw new RuntimeException("File is too large");
|
||||
|
||||
ResourceVersion resourceVersion = getResourceVersion(buffer);
|
||||
versions.add(resourceVersion);
|
||||
}
|
||||
|
||||
return versions;
|
||||
}
|
||||
|
||||
private static ResourceVersion getResourceVersion(byte[] bytes) {
|
||||
int resourceId = ((bytes[0] & 0xFF) << 16) | ((bytes[1] & 0xFF) << 8) | (bytes[2] & 0xFF);
|
||||
int page = ((bytes[3] & 0xFF) << 8) | (bytes[4] & 0xFF);
|
||||
int versionId = ((bytes[5] & 0xFF) << 16) | ((bytes[6] & 0xFF) << 8) | (bytes[7] & 0xFF);
|
||||
|
||||
return new ResourceVersion(resourceId, page, versionId);
|
||||
}
|
||||
|
||||
private static void writeResourceVersion(ResourceVersion resourceVersion, OutputStream outputStream) throws IOException {
|
||||
int resourceId = resourceVersion.resourceId();
|
||||
outputStream.write((resourceId >> 16) & 0xFF);
|
||||
outputStream.write((resourceId >> 8) & 0xFF);
|
||||
outputStream.write(resourceId & 0xFF);
|
||||
|
||||
int page = resourceVersion.page();
|
||||
outputStream.write((page >> 8) & 0xFF);
|
||||
outputStream.write(page & 0xFF);
|
||||
|
||||
int versionId = resourceVersion.updateId();
|
||||
outputStream.write((versionId >> 16) & 0xFF);
|
||||
outputStream.write((versionId >> 8) & 0xFF);
|
||||
outputStream.write(versionId & 0xFF);
|
||||
}
|
||||
|
||||
public static void writeAll(FileOutputStream outputStream, Set<ResourceVersion> versions) throws IOException {
|
||||
outputStream.write(FILE_VERSION);
|
||||
for (ResourceVersion version : versions) {
|
||||
writeResourceVersion(version, outputStream);
|
||||
}
|
||||
}
|
||||
|
||||
public static class FileVersionMismatchException extends RuntimeException {
|
||||
public final byte fileVersion, expectedVersion;
|
||||
|
||||
public FileVersionMismatchException(byte fileVersion, byte expectedVersion) {
|
||||
this.fileVersion = fileVersion;
|
||||
this.expectedVersion = expectedVersion;
|
||||
}
|
||||
}
|
||||
}
|
109
src/main/java/eu/m724/tweaks/updater/VersionFinder.java
Normal file
109
src/main/java/eu/m724/tweaks/updater/VersionFinder.java
Normal file
|
@ -0,0 +1,109 @@
|
|||
package eu.m724.tweaks.updater;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import eu.m724.tweaks.updater.cache.SpigotResource;
|
||||
import eu.m724.tweaks.updater.cache.ResourceVersion;
|
||||
import eu.m724.tweaks.updater.cache.VersionedResource;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
// TODO optimize
|
||||
|
||||
public class VersionFinder extends CompletableFuture<VersionedResource> {
|
||||
private final SpigotResource resource;
|
||||
private final int fromPage;
|
||||
|
||||
VersionFinder(SpigotResource resource, int fromPage) {
|
||||
this.resource = resource;
|
||||
this.fromPage = fromPage;
|
||||
|
||||
start();
|
||||
}
|
||||
|
||||
VersionFinder(SpigotResource resource) {
|
||||
this(resource, 1);
|
||||
}
|
||||
|
||||
private void start() {
|
||||
System.out.printf("STarting for %d %s\n", resource.resourceId(), resource.plugin().getName());
|
||||
try (ExecutorService executor = Executors.newSingleThreadExecutor()) {
|
||||
executor.execute(() -> {
|
||||
try {
|
||||
ResourceVersion runningVersion = null;
|
||||
ResourceVersion latestVersion = null;
|
||||
|
||||
int page;
|
||||
for (page = fromPage; page < 1000; page++) {
|
||||
System.out.println("Page " + page);
|
||||
String url = "https://api.spigotmc.org/simple/0.2/index.php?action=getResourceUpdates&page=%d&id=%d".formatted(page, resource.resourceId());
|
||||
|
||||
HttpRequest request;
|
||||
try {
|
||||
request = HttpRequest.newBuilder(new URI(url))
|
||||
.header("User-Agent", "twu/1")
|
||||
.build();
|
||||
} catch (URISyntaxException e) {
|
||||
throw new RuntimeException(e);
|
||||
} // this will never happen
|
||||
|
||||
try (HttpClient client = HttpClient.newHttpClient()) {
|
||||
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
|
||||
String body = response.body();
|
||||
if (body.isBlank()) {
|
||||
page--;
|
||||
break;
|
||||
}
|
||||
|
||||
JsonArray jsonArray = JsonParser.parseString(body).getAsJsonArray();
|
||||
for (JsonElement ele : jsonArray) {
|
||||
JsonObject versionJson = ele.getAsJsonObject();
|
||||
if (isRunningVersion(versionJson)) {
|
||||
runningVersion = new ResourceVersion(
|
||||
resource.resourceId(),
|
||||
page,
|
||||
versionJson.get("id").getAsInt()
|
||||
);
|
||||
}
|
||||
latestVersion = new ResourceVersion(
|
||||
resource.resourceId(),
|
||||
page,
|
||||
versionJson.get("id").getAsInt()
|
||||
);
|
||||
System.out.printf("%d %d %s\n", page, versionJson.get("id").getAsInt(), versionJson.get("resource_version").getAsString());
|
||||
}
|
||||
|
||||
if (jsonArray.size() < 10) break;
|
||||
}
|
||||
|
||||
}
|
||||
System.out.println("Done");
|
||||
|
||||
if (page > 999) {
|
||||
throw new Exception("Too many pages");
|
||||
} else {
|
||||
this.complete(new VersionedResource(resource, runningVersion, latestVersion));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
this.completeExceptionally(e);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isRunningVersion(JsonObject versionJson) {
|
||||
// TODO
|
||||
return versionJson.get("resource_version").getAsString().equals(resource.plugin().getDescription().getVersion());
|
||||
}
|
||||
}
|
12
src/main/java/eu/m724/tweaks/updater/cache/ResourceVersion.java
vendored
Normal file
12
src/main/java/eu/m724/tweaks/updater/cache/ResourceVersion.java
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
package eu.m724.tweaks.updater.cache;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
public record ResourceVersion(
|
||||
int resourceId,
|
||||
int page,
|
||||
int updateId
|
||||
) { }
|
9
src/main/java/eu/m724/tweaks/updater/cache/SpigotResource.java
vendored
Normal file
9
src/main/java/eu/m724/tweaks/updater/cache/SpigotResource.java
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
package eu.m724.tweaks.updater.cache;
|
||||
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
public record SpigotResource(
|
||||
Plugin plugin,
|
||||
int resourceId
|
||||
) {
|
||||
}
|
11
src/main/java/eu/m724/tweaks/updater/cache/VersionedResource.java
vendored
Normal file
11
src/main/java/eu/m724/tweaks/updater/cache/VersionedResource.java
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
package eu.m724.tweaks.updater.cache;
|
||||
|
||||
public record VersionedResource(
|
||||
SpigotResource resource,
|
||||
ResourceVersion running,
|
||||
ResourceVersion latest
|
||||
) {
|
||||
public VersionedResource update(ResourceVersion latest) {
|
||||
return new VersionedResource(resource, running, latest);
|
||||
}
|
||||
}
|
3
src/main/resources/installed_plugins.yml
Normal file
3
src/main/resources/installed_plugins.yml
Normal file
|
@ -0,0 +1,3 @@
|
|||
# Here go installed plugins and their SpigotMC resource IDs
|
||||
# To ignore a plugin, set it to -1
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
name: Tweaks724
|
||||
author: Minecon724
|
||||
version: ${project.version}
|
||||
|
||||
main: eu.m724.tweaks.TweaksPlugin
|
||||
|
|
Loading…
Reference in a new issue