Compare commits

..

2 commits

14 changed files with 347 additions and 97 deletions

15
pom.xml
View file

@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>eu.m724</groupId>
<artifactId>realweather</artifactId>
<version>0.9-SNAPSHOT</version>
<version>0.9-alpha.2</version>
<properties>
<maven.compiler.source>21</maven.compiler.source>
@ -12,6 +12,11 @@
<jarsigner.storepass>123456</jarsigner.storepass>
</properties>
<scm>
<developerConnection>scm:git:git@git.724.rocks:Minecon724/realweather.git</developerConnection>
<tag>realweather-0.9a2</tag>
</scm>
<repositories>
<repository>
<id>spigot-repo</id>
@ -45,6 +50,14 @@
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>3.0.1</version>
<configuration>
<allowTimestampedSnapshots>true</allowTimestampedSnapshots>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>

21
release.properties Normal file
View file

@ -0,0 +1,21 @@
#release configuration
#Tue Jun 18 13:22:44 CEST 2024
completedPhase=check-poms
exec.pomFileName=pom.xml
exec.snapshotReleasePluginAllowed=false
pinExternals=false
preparationGoals=clean verify
project.scm.eu.m724\:realweather.developerConnection=scm\:git\:git@git.724.rocks\:Minecon724/realweather.git
project.scm.eu.m724\:realweather.tag=HEAD
projectVersionPolicyConfig=<projectVersionPolicyConfig>${projectVersionPolicyConfig}</projectVersionPolicyConfig>\n
projectVersionPolicyId=default
pushChanges=true
releaseStrategyId=default
remoteTagging=true
scm.branchCommitComment=@{prefix} prepare branch @{releaseLabel}
scm.commentPrefix=[maven-release-plugin]
scm.developmentCommitComment=@{prefix} prepare for next development iteration
scm.releaseCommitComment=@{prefix} prepare release @{releaseLabel}
scm.rollbackCommitComment=@{prefix} rollback the release of @{releaseLabel}
scm.tagNameFormat=@{project.artifactId}-@{project.version}
scm.url=scm\:git\:git@git.724.rocks\:Minecon724/realweather.git

View file

@ -13,6 +13,6 @@ public class DebugLogger {
public static void info(String message, int minDebugLevel, Object... format) {
if (debugLevel >= minDebugLevel)
baseLogger.info(String.format(message, format));
baseLogger.info(message.formatted(format));
}
}

View file

@ -7,6 +7,7 @@ import eu.m724.realweather.mapper.MapperConfig;
import eu.m724.realweather.thunder.ThunderConfig;
import eu.m724.realweather.thunder.ThunderMaster;
import eu.m724.realweather.time.TimeConfig;
import eu.m724.realweather.updater.UpdaterConfig;
import eu.m724.realweather.weather.PlayerWeatherDirectory;
import eu.m724.realweather.weather.WeatherConfig;
@ -15,6 +16,7 @@ public class GlobalConstants {
static TimeConfig timeConfig;
static ThunderConfig thunderConfig;
static MapperConfig mapperConfig;
static UpdaterConfig updaterConfig;
static ThunderMaster thunderMaster;
@ -34,6 +36,9 @@ public class GlobalConstants {
public static MapperConfig getMapperConfig() {
return mapperConfig;
}
public static UpdaterConfig getUpdaterConfig() {
return updaterConfig;
}
public static ThunderMaster getThunderMaster() {
return thunderMaster;
}

View file

@ -14,6 +14,7 @@ import com.google.common.base.Charsets;
import eu.m724.realweather.commands.AdminCommand;
import eu.m724.realweather.commands.GeoCommand;
import eu.m724.realweather.commands.LocalTimeCommand;
import eu.m724.realweather.commands.UpdateCommand;
import eu.m724.realweather.mapper.Mapper;
import eu.m724.realweather.mapper.MapperConfig;
import eu.m724.realweather.object.UserException;
@ -23,6 +24,7 @@ import eu.m724.realweather.time.TimeConfig;
import eu.m724.realweather.time.TimeMaster;
import eu.m724.realweather.updater.SignatureValidator;
import eu.m724.realweather.updater.Updater;
import eu.m724.realweather.updater.UpdaterConfig;
import eu.m724.realweather.weather.WeatherConfig;
import eu.m724.realweather.weather.WeatherMaster;
import eu.m724.wtapi.provider.exception.ProviderException;
@ -31,6 +33,7 @@ public class RealWeatherPlugin extends JavaPlugin {
private WeatherMaster weatherMaster;
private ThunderMaster thunderMaster;
private TimeMaster timeMaster;
private Updater updater;
private Logger logger;
@ -112,6 +115,10 @@ public class RealWeatherPlugin extends JavaPlugin {
GlobalConstants.timeConfig = TimeConfig.fromConfiguration(timeConfiguration);
timeMaster = new TimeMaster(GlobalConstants.timeConfig);
timeMaster.init();
GlobalConstants.updaterConfig = UpdaterConfig.fromConfiguration(configuration.getConfigurationSection("updater"));
updater = new Updater(GlobalConstants.updaterConfig);
updater.init();
} catch (UserException e) {
logger.severe("There are errors in your config:");
logger.severe(e.getMessage());
@ -132,13 +139,12 @@ public class RealWeatherPlugin extends JavaPlugin {
GlobalConstants.thunderMaster = thunderMaster;
getCommand("rwadmin").setExecutor(new AdminCommand());
getCommand("rwadmin update").setExecutor(new UpdateCommand(updater));
getCommand("geo").setExecutor(new GeoCommand());
if (GlobalConstants.timeConfig.enabled)
getCommand("localtime").setExecutor(new LocalTimeCommand());
new Updater().init();
DebugLogger.info("ended loading", 1);
}

View file

@ -0,0 +1,37 @@
package eu.m724.realweather.commands;
import java.util.concurrent.CompletableFuture;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import eu.m724.realweather.updater.Updater;
import eu.m724.realweather.updater.metadata.VersionMetadata;
public class UpdateCommand implements CommandExecutor {
private Updater updater;
public UpdateCommand(Updater updater) {
this.updater = updater;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
sender.sendMessage("Please wait");
CompletableFuture<VersionMetadata> latestFuture = updater.getLatestVersion();
latestFuture.thenAccept(metadata -> {
if (metadata != null) {
sender.sendMessage("An update is available!");
sender.sendMessage("RealWeather %s released %s".formatted(metadata.label, metadata.getFormattedDate()));
sender.sendMessage("To download: /rwadmin update download");
} else {
sender.sendMessage("No new updates"); // TODO color
}
});
return true;
}
}

View file

@ -1,62 +0,0 @@
package eu.m724.realweather.updater;
import java.net.ProxySelector;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpClient.Redirect;
import java.net.http.HttpResponse.BodyHandlers;
import java.util.concurrent.CompletableFuture;
import org.bukkit.plugin.Plugin;
import com.google.gson.Gson;
public class MetadataRetriever {
private String version;
private CompletableFuture<VersionMetadata> currentMetadataCached = null;
public MetadataRetriever(Plugin plugin) {
this.version = plugin.getDescription().getVersion();
}
private CompletableFuture<VersionMetadata> getMetadataFromUrl(String url) {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("User-Agent", "rwu/1")
.build();
CompletableFuture<HttpResponse<String>> responseFuture =
HttpClient.newBuilder()
.followRedirects(Redirect.NORMAL)
.proxy(ProxySelector.getDefault()).build().
sendAsync(request, BodyHandlers.ofString());
CompletableFuture<VersionMetadata> metadataFuture =
responseFuture.thenApply(response -> {
if (response.statusCode() != 200)
return null;
VersionMetadata versionMetadata = new Gson().fromJson(response.body(), VersionMetadata.class);
return versionMetadata;
});
return metadataFuture;
}
public CompletableFuture<VersionMetadata> getLatestVersionMetadata() {
return getMetadataFromUrl("https://git.724.rocks/Minecon724/realweather-metadata/raw/branch/master/latest/latest-v1.json");
}
public CompletableFuture<VersionMetadata> getCurrentVersionMetadata() {
if (currentMetadataCached != null)
currentMetadataCached = getVersionMetadata(version);
return currentMetadataCached;
}
public CompletableFuture<VersionMetadata> getVersionMetadata(String version) {
return getMetadataFromUrl("https://git.724.rocks/Minecon724/realweather-metadata/raw/branch/master/releases/" + version + "/meta-v1.json");
}
}

View file

@ -1,8 +1,8 @@
package eu.m724.realweather.updater;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@ -10,18 +10,25 @@ import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitRunnable;
import eu.m724.realweather.DebugLogger;
import eu.m724.realweather.GlobalConstants;
import eu.m724.realweather.object.UserException;
import eu.m724.realweather.updater.metadata.MetadataRetriever;
import eu.m724.realweather.updater.metadata.MetadataServerException;
import eu.m724.realweather.updater.metadata.VersionMetadata;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.ComponentBuilder;
public class Updater extends BukkitRunnable implements Listener {
private Plugin plugin = GlobalConstants.getPlugin();
private MetadataRetriever metadataRetriever = new MetadataRetriever(plugin);
private UpdaterConfig updaterConfig;
private MetadataRetriever metadataRetriever;
private VersionMetadata availableUpdate = null;
private Plugin plugin = GlobalConstants.getPlugin();
private VersionMetadata currentMetadata;
private VersionMetadata latestMetadata;
private long checkCacheExpires;
private BaseComponent updateMessage = null;
private BaseComponent updateActionMessage =
@ -29,19 +36,91 @@ public class Updater extends BukkitRunnable implements Listener {
.append("/rwadmin update").color(ChatColor.AQUA)
.build();
public void init() {
this.runTaskTimerAsynchronously(plugin, 0, 216000); // 3h
plugin.getServer().getPluginManager().registerEvents(this, plugin);
public Updater(UpdaterConfig updaterConfig) {
this.updaterConfig = updaterConfig;
this.metadataRetriever = new MetadataRetriever(plugin, updaterConfig.channel);
}
public void init() throws UserException {
try {
DebugLogger.info("probing for channels...", 1);
List<String> channels = metadataRetriever.getChannels().join();
if (!channels.contains(updaterConfig.channel)) {
throw new UserException(
"Invalid channel: %s. Valid ones are: %s"
.formatted(updaterConfig.channel, String.join(", ", channels))); // WHY DID NOBODY TELL ME ABOUT .formatted
}
currentMetadata = metadataRetriever.getCurrentVersionMetadata().join();
DebugLogger.info("current: %d", 1, currentMetadata.id);
} catch (CompletionException e) {
int statusCode = ((MetadataServerException) e.getCause()).getStatusCode();
if (statusCode >= 500) {
DebugLogger.info("Unable to contact the update server! %d", 0, statusCode);
DebugLogger.info("As it's a server error, it's probably temporary and not a configuration issue, so proceeding.", 0);
} else {
DebugLogger.info("Update server returned unexpected status code! %d", 0, statusCode);
if (plugin.getDescription().getVersion().endsWith("SNAPSHOT")) {
DebugLogger.info("It looks like this is a development snapshot, possibly built from source. So actually this is expected.", 0);
} else {
DebugLogger.info("This is probably critical. RealWeather will continue without updater.", 0);
DebugLogger.info("Try restarting the server. If that doesn't help, contact support.", 0);
}
return;
}
}
if (updaterConfig.notify) {
this.runTaskTimerAsynchronously(plugin, 0, 216000); // 3h
plugin.getServer().getPluginManager().registerEvents(this, plugin);
DebugLogger.info("updater will notify", 1);
}
DebugLogger.info("updater loaded", 1);
}
public boolean installUpdate() {
if (availableUpdate == null)
if (latestMetadata == null)
return false;
// TODO dont forget about verifictaion
return true;
}
public CompletableFuture<VersionMetadata> getLatestVersion() {
if (System.currentTimeMillis() < checkCacheExpires)
return CompletableFuture.completedFuture(latestMetadata);
else
return checkForNewVersion().handle((result, ex) -> null);
}
/**
* this can throw completionexception
* @return
*/
private CompletableFuture<VersionMetadata> checkForNewVersion() {
CompletableFuture<VersionMetadata> latestMetadataFuture =
metadataRetriever.getLatestVersionMetadata();
CompletableFuture<VersionMetadata> newMetadataFuture =
latestMetadataFuture.thenApply(latestMetadata -> {
DebugLogger.info("Current version: %s (%d)", 2, currentMetadata.label, currentMetadata.id);
DebugLogger.info("Latest version: %s (%d)", 2, latestMetadata.label, latestMetadata.id);
if (currentMetadata.id < latestMetadata.id) {
this.latestMetadata = latestMetadata;
this.checkCacheExpires = System.currentTimeMillis() + 10800000;
return latestMetadata;
}
this.checkCacheExpires = System.currentTimeMillis() + 3600000;
return null;
});
return newMetadataFuture;
}
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
Player player = event.getPlayer();
@ -57,30 +136,22 @@ public class Updater extends BukkitRunnable implements Listener {
@Override
public void run() {
DebugLogger.info("Checking for update...", 2);
CompletableFuture<VersionMetadata> currentMetadataFuture =
metadataRetriever.getCurrentVersionMetadata();
CompletableFuture<VersionMetadata> latestMetadataFuture =
metadataRetriever.getLatestVersionMetadata();
CompletableFuture<VersionMetadata> newVersionFuture = checkForNewVersion();
VersionMetadata currentMetadata = currentMetadataFuture.join();
VersionMetadata latestMetadata = latestMetadataFuture.join();
DebugLogger.info("Current version: %s (%d)", 2, currentMetadata.label, currentMetadata.id);
DebugLogger.info("Latest version: %s (%d)", 2, latestMetadata.label, latestMetadata.id);
if (currentMetadata.id >= latestMetadata.id) return;
availableUpdate = latestMetadata;
String formattedDate = new SimpleDateFormat("dd.MM").format(new Date(latestMetadata.timestamp));
try {
newVersionFuture.join();
} catch (CompletionException e) {
int statusCode = ((MetadataServerException) e.getCause()).getStatusCode();
DebugLogger.info("Couldn't check for updates: %d", 0, statusCode);
}
updateMessage = new ComponentBuilder("An update is available!\n")
.color(ChatColor.YELLOW)
.append("RealWeather ").color(ChatColor.GOLD)
.append(latestMetadata.label).color(ChatColor.AQUA).bold(true)
.append(" released ").color(ChatColor.GOLD)
.append(formattedDate).color(ChatColor.AQUA)
.append(latestMetadata.getFormattedDate()).color(ChatColor.AQUA)
.append("\nCurrent: ").color(ChatColor.GRAY)
.append(currentMetadata.label).color(ChatColor.DARK_AQUA)
.build();

View file

@ -0,0 +1,17 @@
package eu.m724.realweather.updater;
import org.bukkit.configuration.ConfigurationSection;
public class UpdaterConfig {
public boolean notify;
public String channel;
public static UpdaterConfig fromConfiguration(ConfigurationSection configuration) {
UpdaterConfig updaterConfig = new UpdaterConfig();
updaterConfig.notify = configuration.getBoolean("notify");
updaterConfig.channel = configuration.getString("channel");
return updaterConfig;
}
}

View file

@ -0,0 +1,107 @@
package eu.m724.realweather.updater.metadata;
import java.net.ProxySelector;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpClient.Redirect;
import java.net.http.HttpResponse.BodyHandlers;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import org.bukkit.plugin.Plugin;
import com.google.gson.Gson;
public class MetadataRetriever {
private String version;
private String channel;
private CompletableFuture<VersionMetadata> currentMetadataCached = null;
public MetadataRetriever(Plugin plugin, String channel) {
this.version = plugin.getDescription().getVersion();
this.channel = channel;
}
/**
* the completablefuture can throw a completionexception with {@link eu.m724.realweather.updater.metadata.MetadataServerException}
*/
private CompletableFuture<VersionMetadata> getMetadataOf(String version) {
String url = String.format(
"https://git.724.rocks/Minecon724/realweather-metadata/raw/branch/master/data/%s/%s/%s",
channel, version, "meta-v1.json");
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("User-Agent", "rwu/1") // real weather updater v1
.build();
CompletableFuture<HttpResponse<String>> responseFuture =
HttpClient.newBuilder()
.followRedirects(Redirect.NORMAL)
.proxy(ProxySelector.getDefault()).build().
sendAsync(request, BodyHandlers.ofString());
CompletableFuture<VersionMetadata> metadataFuture =
responseFuture.thenApply(response -> {
if (response.statusCode() != 200)
throw new CompletionException(new MetadataServerException(response.statusCode()));
VersionMetadata versionMetadata = new Gson().fromJson(response.body(), VersionMetadata.class);
return versionMetadata;
});
return metadataFuture;
}
public CompletableFuture<List<String>> getChannels() {
String url = "https://git.724.rocks/Minecon724/realweather-metadata/raw/branch/master/data/channels.txt";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("User-Agent", "rwu/1") // real weather updater v1
.build();
CompletableFuture<HttpResponse<String>> responseFuture =
HttpClient.newBuilder()
.followRedirects(Redirect.NORMAL)
.proxy(ProxySelector.getDefault()).build().
sendAsync(request, BodyHandlers.ofString());
CompletableFuture<List<String>> channelsFuture =
responseFuture.thenApply(response -> {
if (response.statusCode() != 200)
throw new CompletionException(new MetadataServerException(response.statusCode()));
return response.body().lines().toList();
});
return channelsFuture; // TODO remove repeated code?
}
/**
* the {@link CompletableFuture} can throw a {@link CompletionException} with {@link MetadataServerException}
*/
public CompletableFuture<VersionMetadata> getLatestVersionMetadata() {
return getVersionMetadata("latest");
}
/**
* the completablefuture can throw a completionexception with {@link MetadataServerException}
*/
public CompletableFuture<VersionMetadata> getCurrentVersionMetadata() {
if (currentMetadataCached == null)
currentMetadataCached = getVersionMetadata(version);
return currentMetadataCached; // TODO reconsider this
}
/**
* the completablefuture can throw a completionexception with {@link MetadataServerException}
*/
public CompletableFuture<VersionMetadata> getVersionMetadata(String version) {
return getMetadataOf(version); // TODO remove this and rename that function?
}
}

View file

@ -0,0 +1,16 @@
package eu.m724.realweather.updater.metadata;
public class MetadataServerException extends Exception {
private int statusCode;
private static final long serialVersionUID = -782470406494196579L;
public MetadataServerException(int statusCode) {
this.statusCode = statusCode;
}
public int getStatusCode() {
return statusCode;
}
}

View file

@ -1,4 +1,7 @@
package eu.m724.realweather.updater;
package eu.m724.realweather.updater.metadata;
import java.text.SimpleDateFormat;
import java.util.Date;
public class VersionMetadata {
/**
@ -26,4 +29,10 @@ public class VersionMetadata {
* filename of the jar file in the version directory
*/
public String file;
public String sha256;
public String getFormattedDate() {
return new SimpleDateFormat("dd.MM").format(new Date(timestamp));
}
}

View file

@ -6,9 +6,14 @@
enabled: true
updater:
# notify players about plugin updates
# revelant permission node: realweather.update.notify
# Notify players and console about plugin updates
# This also controls automatic checking
# You can still update with /rwadmin update
# Revelant permission node: realweather.update.notify
notify: true
# stable for stable releases
# testing for latest builds (untested hence the name)
channel: testing
# 0 - no debug
# 1 - debug loading modules

View file

@ -16,12 +16,15 @@ commands:
description: RealWeather admin command
permission: realweather.admin
permission-message: You do not have permission to use this command.
# usage is processed in code
rwadmin update:
description: Update RealWeather
permission: realweather.admin.update
permission-message: You do not have permission to use this command.
geo:
description: Convert lat,lon to x,y,z and vice versa
permission: realweather.command.geo
permission-message: You do not have permission to use this command.
# usage is processed in code
localtime:
description: Get real time in current location
permission: realweather.command.localtime
@ -32,6 +35,8 @@ permissions:
realweather.admin:
description: Allows admin management with /rwadmin
realweather.admin.update:
description: Allows installing updates with /rwadmin update
realweather.command.geo:
description: Allows /geo