commit
Some checks failed
/ deploy (push) Failing after 53s

This commit is contained in:
Minecon724 2024-11-26 20:25:13 +01:00
parent 6f28250a10
commit a7506bd3c6
Signed by: Minecon724
GPG key ID: 3CCC4D267742C8E8
12 changed files with 394 additions and 2 deletions

View file

@ -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;

View file

@ -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);
}
}
}
}

View 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;
}
}

View 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();
}
}

View 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);
}
}

View 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;
}
}
}

View 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());
}
}

View 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
) { }

View file

@ -0,0 +1,9 @@
package eu.m724.tweaks.updater.cache;
import org.bukkit.plugin.Plugin;
public record SpigotResource(
Plugin plugin,
int resourceId
) {
}

View 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);
}
}

View file

@ -0,0 +1,3 @@
# Here go installed plugins and their SpigotMC resource IDs
# To ignore a plugin, set it to -1

View file

@ -1,4 +1,5 @@
name: Tweaks724
author: Minecon724
version: ${project.version}
main: eu.m724.tweaks.TweaksPlugin