mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2025-01-27 18:41:40 +01:00
Update command #539
This commit is contained in:
parent
23a3fc441b
commit
4e0f1b38f1
@ -4,6 +4,7 @@ import com.djrapitops.plan.PlanBungee;
|
|||||||
import com.djrapitops.plan.command.commands.*;
|
import com.djrapitops.plan.command.commands.*;
|
||||||
import com.djrapitops.plan.command.commands.manage.ManageConDebugCommand;
|
import com.djrapitops.plan.command.commands.manage.ManageConDebugCommand;
|
||||||
import com.djrapitops.plan.system.settings.Permissions;
|
import com.djrapitops.plan.system.settings.Permissions;
|
||||||
|
import com.djrapitops.plan.system.settings.Settings;
|
||||||
import com.djrapitops.plan.system.settings.locale.Locale;
|
import com.djrapitops.plan.system.settings.locale.Locale;
|
||||||
import com.djrapitops.plan.system.settings.locale.Msg;
|
import com.djrapitops.plan.system.settings.locale.Msg;
|
||||||
import com.djrapitops.plugin.command.CommandNode;
|
import com.djrapitops.plugin.command.CommandNode;
|
||||||
@ -49,6 +50,7 @@ public class PlanBungeeCommand extends TreeCmdNode {
|
|||||||
new BungeeSetupToggleCommand(),
|
new BungeeSetupToggleCommand(),
|
||||||
new ReloadCommand(plugin),
|
new ReloadCommand(plugin),
|
||||||
new StatusCommand<>(plugin, Permissions.MANAGE.getPermission(), plugin.getColorScheme()),
|
new StatusCommand<>(plugin, Permissions.MANAGE.getPermission(), plugin.getColorScheme()),
|
||||||
|
(Settings.ALLOW_UPDATE.isTrue() ? new UpdateCommand() : null)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,8 @@ public class PlanCommand extends TreeCmdNode {
|
|||||||
new ReloadCommand(plugin),
|
new ReloadCommand(plugin),
|
||||||
new ManageCommand(plugin, this),
|
new ManageCommand(plugin, this),
|
||||||
new StatusCommand<>(plugin, Permissions.MANAGE.getPermission(), plugin.getColorScheme()),
|
new StatusCommand<>(plugin, Permissions.MANAGE.getPermission(), plugin.getColorScheme()),
|
||||||
(Settings.DEV_MODE.isTrue() ? new DevCommand() : null)
|
(Settings.DEV_MODE.isTrue() ? new DevCommand() : null),
|
||||||
|
(Settings.ALLOW_UPDATE.isTrue() ? new UpdateCommand() : null)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,210 @@
|
|||||||
|
package com.djrapitops.plan.command.commands;
|
||||||
|
|
||||||
|
import com.djrapitops.plan.api.exceptions.connection.*;
|
||||||
|
import com.djrapitops.plan.api.exceptions.database.DBException;
|
||||||
|
import com.djrapitops.plan.command.commands.manage.ManageConDebugCommand;
|
||||||
|
import com.djrapitops.plan.system.database.databases.Database;
|
||||||
|
import com.djrapitops.plan.system.database.databases.operation.FetchOperations;
|
||||||
|
import com.djrapitops.plan.system.info.InfoSystem;
|
||||||
|
import com.djrapitops.plan.system.info.request.CheckConnectionRequest;
|
||||||
|
import com.djrapitops.plan.system.info.request.UpdateCancelRequest;
|
||||||
|
import com.djrapitops.plan.system.info.server.Server;
|
||||||
|
import com.djrapitops.plan.system.settings.Permissions;
|
||||||
|
import com.djrapitops.plan.system.update.VersionCheckSystem;
|
||||||
|
import com.djrapitops.plan.system.update.VersionInfo;
|
||||||
|
import com.djrapitops.plan.system.webserver.WebServerSystem;
|
||||||
|
import com.djrapitops.plugin.api.utility.log.Log;
|
||||||
|
import com.djrapitops.plugin.command.CommandNode;
|
||||||
|
import com.djrapitops.plugin.command.CommandType;
|
||||||
|
import com.djrapitops.plugin.command.ISender;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command that updates all servers in the network
|
||||||
|
*
|
||||||
|
* @author Rsl1122
|
||||||
|
*/
|
||||||
|
public class UpdateCommand extends CommandNode {
|
||||||
|
|
||||||
|
public UpdateCommand() {
|
||||||
|
super("update", Permissions.MANAGE.getPermission(), CommandType.ALL);
|
||||||
|
setArguments("[-update]/[cancel]");
|
||||||
|
setShortHelp("Get change log link or update plugin.");
|
||||||
|
setInDepthHelp(
|
||||||
|
"/plan update",
|
||||||
|
" Used to update the plugin on the next shutdown\n",
|
||||||
|
" /plan update - get change log link",
|
||||||
|
" /plan update -update - Schedule update to happen on all network servers that are online next time they reboot.",
|
||||||
|
" /plan update cancel - Cancel scheduled update on servers that haven't rebooted yet."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCommand(ISender sender, String commandLabel, String[] args) {
|
||||||
|
if (!VersionCheckSystem.isNewVersionAvailable()) {
|
||||||
|
sender.sendMessage("§aYou're running the latest version of Plan.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VersionInfo available = VersionCheckSystem.getInstance().getNewVersionAvailable();
|
||||||
|
String downloadUrl = available.getDownloadUrl();
|
||||||
|
|
||||||
|
if (!available.isTrusted()) {
|
||||||
|
sender.sendMessage("§cVersion download url did not start with " +
|
||||||
|
"https://github.com/Rsl1122/Plan-PlayerAnalytics/releases/ " +
|
||||||
|
"and might not be trusted. You can download this version manually here (Direct download):");
|
||||||
|
sender.sendLink(downloadUrl, downloadUrl);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.length == 0) {
|
||||||
|
sender.sendLink("Change Log v" + available.getVersion().toString() + ": ", "Click me", available.getChangeLogUrl());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String firstArgument = args[0];
|
||||||
|
if ("-update".equals(firstArgument)) {
|
||||||
|
handleUpdate(sender, args);
|
||||||
|
} else if ("cancel".equals(firstArgument)) {
|
||||||
|
cancel(sender);
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Unknown argument, use '-update' or 'cancel'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cancel(ISender sender) {
|
||||||
|
try {
|
||||||
|
cancel(sender, Database.getActive().fetch().getServers());
|
||||||
|
sender.sendMessage("§aUpdate has been cancelled.");
|
||||||
|
} catch (DBException e) {
|
||||||
|
sender.sendMessage("§cDatabase error occurred, cancel could not be performed.");
|
||||||
|
Log.toLog(this.getClass().getName(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleUpdate(ISender sender, String[] args) {
|
||||||
|
sender.sendMessage("§aYou can cancel the update on servers that haven't rebooted yet with /plan update cancel.");
|
||||||
|
sender.sendMessage("Checking that all servers are online..");
|
||||||
|
if (!checkNetworkStatus(sender)) {
|
||||||
|
sender.sendMessage("§cNot all servers were online or accessible, you can still update available servers using -force as a 2nd argument.");
|
||||||
|
if (args.length <= 1 || !"-force".equals(args[1])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
List<Server> servers = Database.getActive().fetch().getServers();
|
||||||
|
update(sender, servers);
|
||||||
|
} catch (DBException e) {
|
||||||
|
Log.toLog(this.getClass().getName(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void update(ISender sender, List<Server> servers) {
|
||||||
|
for (Server server : servers) {
|
||||||
|
if (update(sender, server)) {
|
||||||
|
sender.sendMessage("§a" + server.getName() + " scheduled for update.");
|
||||||
|
} else {
|
||||||
|
sender.sendMessage("§cUpdate failed on a server, cancelling update on all servers..");
|
||||||
|
cancel(sender, servers);
|
||||||
|
sender.sendMessage("§cUpdate cancelled.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cancel(ISender sender, List<Server> servers) {
|
||||||
|
for (Server server : servers) {
|
||||||
|
cancel(sender, server);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cancel(ISender sender, Server server) {
|
||||||
|
try {
|
||||||
|
InfoSystem.getInstance().getConnectionSystem().sendInfoRequest(new UpdateCancelRequest(), server);
|
||||||
|
} catch (ForbiddenException | GatewayException | InternalErrorException e) {
|
||||||
|
sender.sendMessage("§cCancel failed on " + server.getName() + ": Odd Exception: " + e.getClass().getSimpleName());
|
||||||
|
} catch (UnauthorizedServerException e) {
|
||||||
|
sender.sendMessage("§cCancel failed on " + server.getName() + ": Unauthorized. " + server.getName() + " might be using different database.");
|
||||||
|
} catch (ConnectionFailException e) {
|
||||||
|
sender.sendMessage("§cCancel failed on " + server.getName() + ": " + e.getCause().getClass().getSimpleName() + " " + e.getCause().getMessage());
|
||||||
|
String address = server.getWebAddress();
|
||||||
|
boolean local = address.contains("localhost")
|
||||||
|
|| address.startsWith("https://:") // IP empty = Localhost
|
||||||
|
|| address.startsWith("http://:") // IP empty = Localhost
|
||||||
|
|| address.contains("127.0.0.1");
|
||||||
|
if (!local) {
|
||||||
|
sender.sendMessage("§cNon-local address, check that port is open");
|
||||||
|
}
|
||||||
|
} catch (NotFoundException e) {
|
||||||
|
/* Ignored, older version */
|
||||||
|
} catch (WebException e) {
|
||||||
|
sender.sendMessage("§cCancel failed on " + server.getName() + ": Odd Exception:" + e.getClass().getSimpleName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean update(ISender sender, Server server) {
|
||||||
|
try {
|
||||||
|
InfoSystem.getInstance().getConnectionSystem().sendInfoRequest(new CheckConnectionRequest(), server);
|
||||||
|
return true;
|
||||||
|
} catch (BadRequestException e) {
|
||||||
|
sender.sendMessage("§c" + server.getName() + " has Allow-Update set to false, aborting update.");
|
||||||
|
return false;
|
||||||
|
} catch (ForbiddenException | GatewayException | InternalErrorException e) {
|
||||||
|
sender.sendMessage("§c" + server.getName() + ": Odd Exception: " + e.getClass().getSimpleName());
|
||||||
|
return false;
|
||||||
|
} catch (UnauthorizedServerException e) {
|
||||||
|
sender.sendMessage("§cFail reason: Unauthorized. " + server.getName() + " might be using different database.");
|
||||||
|
return false;
|
||||||
|
} catch (ConnectionFailException e) {
|
||||||
|
sender.sendMessage("§cFail reason: " + e.getCause().getClass().getSimpleName() + " " + e.getCause().getMessage());
|
||||||
|
String address = server.getWebAddress();
|
||||||
|
boolean local = address.contains("localhost")
|
||||||
|
|| address.startsWith("https://:") // IP empty = Localhost
|
||||||
|
|| address.startsWith("http://:") // IP empty = Localhost
|
||||||
|
|| address.contains("127.0.0.1");
|
||||||
|
if (!local) {
|
||||||
|
sender.sendMessage("§cNon-local address, check that port is open");
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} catch (NotFoundException e) {
|
||||||
|
sender.sendMessage("§e" + server.getName() + " is using older version and can not be scheduled for update. " +
|
||||||
|
"You can update it manually, update will proceed.");
|
||||||
|
return true;
|
||||||
|
} catch (WebException e) {
|
||||||
|
sender.sendMessage("§eOdd Exception: " + e.getClass().getSimpleName());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkNetworkStatus(ISender sender) {
|
||||||
|
try {
|
||||||
|
FetchOperations fetch = Database.getActive().fetch();
|
||||||
|
Optional<Server> bungeeInformation = fetch.getBungeeInformation();
|
||||||
|
if (!bungeeInformation.isPresent()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Map<UUID, Server> bukkitServers = fetch.getBukkitServers();
|
||||||
|
String accessAddress = WebServerSystem.getInstance().getWebServer().getAccessAddress();
|
||||||
|
boolean success = true;
|
||||||
|
for (Server server : bukkitServers.values()) {
|
||||||
|
if (!ManageConDebugCommand.testServer(sender, accessAddress, server)) {
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Server bungee = bungeeInformation.get();
|
||||||
|
if (!ManageConDebugCommand.testServer(sender, accessAddress, bungee)) {
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
} catch (DBException e) {
|
||||||
|
sender.sendMessage("§cDatabase error occurred, update has been cancelled.");
|
||||||
|
Log.toLog(this.getClass().getName(), e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -28,12 +28,9 @@ import java.util.UUID;
|
|||||||
*/
|
*/
|
||||||
public class ManageConDebugCommand extends CommandNode {
|
public class ManageConDebugCommand extends CommandNode {
|
||||||
|
|
||||||
private final ColorScheme cs;
|
|
||||||
|
|
||||||
public ManageConDebugCommand() {
|
public ManageConDebugCommand() {
|
||||||
super("con", Permissions.MANAGE.getPermission(), CommandType.ALL);
|
super("con", Permissions.MANAGE.getPermission(), CommandType.ALL);
|
||||||
setShortHelp("Debug Bukkit-Bungee Connections");
|
setShortHelp("Debug Bukkit-Bungee Connections");
|
||||||
cs = PlanPlugin.getInstance().getColorScheme();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -68,18 +65,19 @@ public class ManageConDebugCommand extends CommandNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testServer(ISender sender, String accessAddress, Server server) {
|
public static boolean testServer(ISender sender, String accessAddress, Server server) {
|
||||||
String address = server.getWebAddress().toLowerCase();
|
String address = server.getWebAddress().toLowerCase();
|
||||||
boolean usingHttps = address.startsWith("https");
|
boolean usingHttps = address.startsWith("https");
|
||||||
boolean local = address.contains("localhost")
|
boolean local = address.contains("localhost")
|
||||||
|| address.startsWith("https://:")
|
|| address.startsWith("https://:") // IP empty = Localhost
|
||||||
|| address.startsWith("http://:")
|
|| address.startsWith("http://:") // IP empty = Localhost
|
||||||
|| address.contains("127.0.0.1");
|
|| address.contains("127.0.0.1");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
InfoSystem.getInstance().getConnectionSystem().sendInfoRequest(new CheckConnectionRequest(accessAddress), server);
|
InfoSystem.getInstance().getConnectionSystem().sendInfoRequest(new CheckConnectionRequest(accessAddress), server);
|
||||||
sender.sendMessage(getMsgFor(address, usingHttps, local, true, true));
|
sender.sendMessage(getMsgFor(address, usingHttps, local, true, true));
|
||||||
|
return true;
|
||||||
|
|
||||||
} catch (ForbiddenException | BadRequestException | InternalErrorException e) {
|
} catch (ForbiddenException | BadRequestException | InternalErrorException e) {
|
||||||
sender.sendMessage(getMsgFor(address, usingHttps, local, false, false));
|
sender.sendMessage(getMsgFor(address, usingHttps, local, false, false));
|
||||||
@ -102,9 +100,11 @@ public class ManageConDebugCommand extends CommandNode {
|
|||||||
sender.sendMessage(getMsgFor(address, usingHttps, local, false, false));
|
sender.sendMessage(getMsgFor(address, usingHttps, local, false, false));
|
||||||
sender.sendMessage("§eOdd Exception: " + e.getClass().getSimpleName());
|
sender.sendMessage("§eOdd Exception: " + e.getClass().getSimpleName());
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getMsgFor(String address, boolean usingHttps, boolean local, boolean successTo, boolean successFrom) {
|
private static String getMsgFor(String address, boolean usingHttps, boolean local, boolean successTo, boolean successFrom) {
|
||||||
|
ColorScheme cs = PlanPlugin.getInstance().getColorScheme();
|
||||||
String tCol = cs.getTertiaryColor();
|
String tCol = cs.getTertiaryColor();
|
||||||
String sCol = cs.getSecondaryColor();
|
String sCol = cs.getSecondaryColor();
|
||||||
return tCol + address + sCol + ": "
|
return tCol + address + sCol + ": "
|
||||||
|
@ -125,6 +125,9 @@ public abstract class ConnectionSystem implements SubSystem {
|
|||||||
putRequest(requests, SaveDBSettingsRequest.createHandler());
|
putRequest(requests, SaveDBSettingsRequest.createHandler());
|
||||||
putRequest(requests, SendDBSettingsRequest.createHandler());
|
putRequest(requests, SendDBSettingsRequest.createHandler());
|
||||||
putRequest(requests, CheckConnectionRequest.createHandler());
|
putRequest(requests, CheckConnectionRequest.createHandler());
|
||||||
|
|
||||||
|
putRequest(requests, UpdateRequest.createHandler());
|
||||||
|
putRequest(requests, UpdateCancelRequest.createHandler());
|
||||||
return requests;
|
return requests;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Licence is provided in the jar as license.yml also here:
|
||||||
|
* https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml
|
||||||
|
*/
|
||||||
|
package com.djrapitops.plan.system.info.request;
|
||||||
|
|
||||||
|
import com.djrapitops.plan.system.update.ShutdownUpdateHook;
|
||||||
|
import com.djrapitops.plan.system.webserver.response.DefaultResponses;
|
||||||
|
import com.djrapitops.plan.system.webserver.response.Response;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* InfoRequest used for Updating the plugin on a network.
|
||||||
|
*
|
||||||
|
* @author Rsl1122
|
||||||
|
*/
|
||||||
|
public class UpdateCancelRequest implements InfoRequest {
|
||||||
|
|
||||||
|
public UpdateCancelRequest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UpdateCancelRequest createHandler() {
|
||||||
|
return new UpdateCancelRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void runLocally() {
|
||||||
|
ShutdownUpdateHook.deActivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response handleRequest(Map<String, String> variables) {
|
||||||
|
ShutdownUpdateHook.deActivate();
|
||||||
|
return DefaultResponses.SUCCESS.get();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Licence is provided in the jar as license.yml also here:
|
||||||
|
* https://github.com/Rsl1122/Plan-PlayerAnalytics/blob/master/Plan/src/main/resources/license.yml
|
||||||
|
*/
|
||||||
|
package com.djrapitops.plan.system.info.request;
|
||||||
|
|
||||||
|
import com.djrapitops.plan.system.settings.Settings;
|
||||||
|
import com.djrapitops.plan.system.update.ShutdownUpdateHook;
|
||||||
|
import com.djrapitops.plan.system.webserver.response.DefaultResponses;
|
||||||
|
import com.djrapitops.plan.system.webserver.response.Response;
|
||||||
|
import com.djrapitops.plan.system.webserver.response.api.BadRequestResponse;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* InfoRequest used for Updating the plugin on a network.
|
||||||
|
*
|
||||||
|
* @author Rsl1122
|
||||||
|
*/
|
||||||
|
public class UpdateRequest implements InfoRequest {
|
||||||
|
|
||||||
|
public UpdateRequest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UpdateRequest createHandler() {
|
||||||
|
return new UpdateRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void runLocally() {
|
||||||
|
new ShutdownUpdateHook().register();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response handleRequest(Map<String, String> variables) {
|
||||||
|
if (Settings.ALLOW_UPDATE.isTrue()) {
|
||||||
|
new ShutdownUpdateHook().register();
|
||||||
|
return DefaultResponses.SUCCESS.get();
|
||||||
|
} else {
|
||||||
|
return new BadRequestResponse("Update not allowed on this server");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -37,6 +37,8 @@ public enum Settings {
|
|||||||
DISPLAY_PLAYER_IPS("Customization.Display.PlayerIPs"),
|
DISPLAY_PLAYER_IPS("Customization.Display.PlayerIPs"),
|
||||||
DISPLAY_GAPS_IN_GRAPH_DATA("Customization.Display.GapsInGraphData"),
|
DISPLAY_GAPS_IN_GRAPH_DATA("Customization.Display.GapsInGraphData"),
|
||||||
DATA_GEOLOCATIONS("Data.Geolocations"),
|
DATA_GEOLOCATIONS("Data.Geolocations"),
|
||||||
|
ALLOW_UPDATE("Plugin.Allow-Update-Command"),
|
||||||
|
NOTIFY_ABOUT_DEV_RELEASES("Plugin.Notify-About-DEV-Releases"),
|
||||||
|
|
||||||
// Integer
|
// Integer
|
||||||
WEBSERVER_PORT("WebServer.Port"),
|
WEBSERVER_PORT("WebServer.Port"),
|
||||||
|
@ -0,0 +1,104 @@
|
|||||||
|
package com.djrapitops.plan.system.update;
|
||||||
|
|
||||||
|
import com.djrapitops.plan.PlanPlugin;
|
||||||
|
import com.djrapitops.plugin.api.Check;
|
||||||
|
import com.djrapitops.plugin.api.utility.Version;
|
||||||
|
import com.djrapitops.plugin.api.utility.log.Log;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.nio.channels.Channels;
|
||||||
|
import java.nio.channels.ReadableByteChannel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shutdown hook that updates the plugin on server shutdown.
|
||||||
|
* <p>
|
||||||
|
* Does not perform update on force close.
|
||||||
|
*
|
||||||
|
* @author Rsl1122
|
||||||
|
*/
|
||||||
|
public class ShutdownUpdateHook extends Thread {
|
||||||
|
|
||||||
|
private static boolean activated = false;
|
||||||
|
|
||||||
|
private static boolean isActivated() {
|
||||||
|
return activated;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void activate(ShutdownUpdateHook hook) {
|
||||||
|
activated = true;
|
||||||
|
Runtime.getRuntime().addShutdownHook(hook);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void deActivate() {
|
||||||
|
activated = false;
|
||||||
|
Log.infoColor("§aUpdate has been cancelled.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void register() {
|
||||||
|
if (isActivated()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Log.infoColor("§aUpdate has been scheduled, The new jar will be downloaded on server shutdown.");
|
||||||
|
activate(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (!activated) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
activated = false;
|
||||||
|
VersionInfo available = VersionCheckSystem.getInstance().getNewVersionAvailable();
|
||||||
|
|
||||||
|
if (!Version.isNewVersionAvailable(new Version(VersionCheckSystem.getCurrentVersion()), available.getVersion())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
File dataFolder = PlanPlugin.getInstance().getDataFolder();
|
||||||
|
File pluginsFolder = Check.isSpongeAvailable()
|
||||||
|
? dataFolder.getParentFile()
|
||||||
|
: new File(dataFolder.getParentFile().getParentFile(), "mods");
|
||||||
|
if (pluginsFolder == null || !pluginsFolder.isDirectory()) {
|
||||||
|
System.out.println("Could not get plugin folder for Plan.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
File newFileLocation = new File(pluginsFolder, "Plan-" + available.getVersion() + ".jar");
|
||||||
|
|
||||||
|
try {
|
||||||
|
downloadNewJar(available, newFileLocation);
|
||||||
|
deleteOldJar(pluginsFolder, newFileLocation);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.toLog(this.getClass().getName(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteOldJar(File pluginsFolder, File newFileLocation) {
|
||||||
|
File[] files = pluginsFolder.listFiles();
|
||||||
|
if (files == null) {
|
||||||
|
System.out.println("Could not delete old jar.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (File file : files) {
|
||||||
|
String fileName = file.getName();
|
||||||
|
boolean isPlanJar = (fileName.startsWith("Plan-")
|
||||||
|
&& fileName.endsWith(".jar"))
|
||||||
|
|| fileName.equals("Plan.jar");
|
||||||
|
boolean isNewJar = fileName.equals(newFileLocation.getName());
|
||||||
|
if (isPlanJar && !isNewJar) {
|
||||||
|
file.deleteOnExit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void downloadNewJar(VersionInfo available, File newFileLocation) throws IOException {
|
||||||
|
URL downloadFrom = new URL(available.getDownloadUrl());
|
||||||
|
|
||||||
|
ReadableByteChannel rbc = Channels.newChannel(downloadFrom.openStream());
|
||||||
|
FileOutputStream fos = new FileOutputStream(newFileLocation);
|
||||||
|
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -6,6 +6,7 @@ package com.djrapitops.plan.system.update;
|
|||||||
|
|
||||||
import com.djrapitops.plan.system.PlanSystem;
|
import com.djrapitops.plan.system.PlanSystem;
|
||||||
import com.djrapitops.plan.system.SubSystem;
|
import com.djrapitops.plan.system.SubSystem;
|
||||||
|
import com.djrapitops.plan.system.settings.Settings;
|
||||||
import com.djrapitops.plugin.api.Priority;
|
import com.djrapitops.plugin.api.Priority;
|
||||||
import com.djrapitops.plugin.api.systems.NotificationCenter;
|
import com.djrapitops.plugin.api.systems.NotificationCenter;
|
||||||
import com.djrapitops.plugin.api.utility.Version;
|
import com.djrapitops.plugin.api.utility.Version;
|
||||||
@ -13,6 +14,8 @@ import com.djrapitops.plugin.api.utility.log.Log;
|
|||||||
import com.djrapitops.plugin.utilities.Verify;
|
import com.djrapitops.plugin.utilities.Verify;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* System for checking if new Version is available when the System initializes.
|
* System for checking if new Version is available when the System initializes.
|
||||||
@ -22,7 +25,7 @@ import java.io.IOException;
|
|||||||
public class VersionCheckSystem implements SubSystem {
|
public class VersionCheckSystem implements SubSystem {
|
||||||
|
|
||||||
private final String currentVersion;
|
private final String currentVersion;
|
||||||
private boolean newVersionAvailable = false;
|
private VersionInfo newVersionAvailable;
|
||||||
|
|
||||||
public VersionCheckSystem(String currentVersion) {
|
public VersionCheckSystem(String currentVersion) {
|
||||||
this.currentVersion = currentVersion;
|
this.currentVersion = currentVersion;
|
||||||
@ -35,7 +38,7 @@ public class VersionCheckSystem implements SubSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isNewVersionAvailable() {
|
public static boolean isNewVersionAvailable() {
|
||||||
return getInstance().newVersionAvailable;
|
return getInstance().newVersionAvailable != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getCurrentVersion() {
|
public static String getCurrentVersion() {
|
||||||
@ -44,14 +47,35 @@ public class VersionCheckSystem implements SubSystem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void enable() {
|
public void enable() {
|
||||||
checkForNewVersion();
|
if (Settings.ALLOW_UPDATE.isTrue()) {
|
||||||
|
try {
|
||||||
|
List<VersionInfo> versions = VersionInfoLoader.load();
|
||||||
|
if (Settings.NOTIFY_ABOUT_DEV_RELEASES.isFalse()) {
|
||||||
|
versions = versions.stream().filter(VersionInfo::isRelease).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
VersionInfo newestVersion = versions.get(0);
|
||||||
|
if (Version.isNewVersionAvailable(new Version(currentVersion), newestVersion.getVersion())) {
|
||||||
|
String notification =
|
||||||
|
"New Release (" + newestVersion.getVersion().toString() + ") is available and can be updated " +
|
||||||
|
"to using update subcommand." + (newestVersion.isRelease() ? "" : " This is a DEV release.");
|
||||||
|
Log.info(notification);
|
||||||
|
NotificationCenter.addNotification(newestVersion.isRelease() ? Priority.HIGH : Priority.MEDIUM, notification);
|
||||||
|
} else {
|
||||||
|
Log.info("You're using the latest version.");
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.error("Version information could not be loaded from Github/versions.txt");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
checkForNewVersion();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkForNewVersion() {
|
private void checkForNewVersion() {
|
||||||
String githubVersionUrl = "https://raw.githubusercontent.com/Rsl1122/Plan-PlayerAnalytics/master/Plan/src/main/resources/plugin.yml";
|
String githubVersionUrl = "https://raw.githubusercontent.com/Rsl1122/Plan-PlayerAnalytics/master/Plan/src/main/resources/plugin.yml";
|
||||||
String spigotUrl = "https://www.spigotmc.org/resources/plan-player-analytics.32536/";
|
String spigotUrl = "https://www.spigotmc.org/resources/plan-player-analytics.32536/";
|
||||||
try {
|
try {
|
||||||
newVersionAvailable = Version.checkVersion(currentVersion, githubVersionUrl);
|
boolean newVersionAvailable = Version.checkVersion(currentVersion, githubVersionUrl);
|
||||||
if (!newVersionAvailable) {
|
if (!newVersionAvailable) {
|
||||||
try {
|
try {
|
||||||
newVersionAvailable = Version.checkVersion(currentVersion, spigotUrl);
|
newVersionAvailable = Version.checkVersion(currentVersion, spigotUrl);
|
||||||
@ -77,4 +101,8 @@ public class VersionCheckSystem implements SubSystem {
|
|||||||
public void disable() {
|
public void disable() {
|
||||||
/* Does not need to be closed */
|
/* Does not need to be closed */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public VersionInfo getNewVersionAvailable() {
|
||||||
|
return newVersionAvailable;
|
||||||
|
}
|
||||||
}
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
package com.djrapitops.plan.system.update;
|
||||||
|
|
||||||
|
import com.djrapitops.plugin.api.utility.Version;
|
||||||
|
import com.google.common.base.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data class for reading version.txt in https://github.com/Rsl1122/Plan-PlayerAnalytics.
|
||||||
|
*
|
||||||
|
* @author Rsl1122
|
||||||
|
*/
|
||||||
|
public class VersionInfo implements Comparable<VersionInfo> {
|
||||||
|
|
||||||
|
private final boolean release;
|
||||||
|
private final Version version;
|
||||||
|
private final String downloadUrl;
|
||||||
|
private final String changeLogUrl;
|
||||||
|
|
||||||
|
public VersionInfo(boolean release, Version version, String downloadUrl, String changeLogUrl) {
|
||||||
|
this.release = release;
|
||||||
|
this.version = version;
|
||||||
|
this.downloadUrl = downloadUrl;
|
||||||
|
this.changeLogUrl = changeLogUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRelease() {
|
||||||
|
return release;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Version getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDownloadUrl() {
|
||||||
|
return downloadUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getChangeLogUrl() {
|
||||||
|
return changeLogUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isTrusted() {
|
||||||
|
return downloadUrl.startsWith("https://github.com/Rsl1122/Plan-PlayerAnalytics/releases/download/");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
VersionInfo that = (VersionInfo) o;
|
||||||
|
return release == that.release &&
|
||||||
|
Objects.equal(version, that.version);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hashCode(release, version);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(VersionInfo o) {
|
||||||
|
return -this.version.compareTo(o.version);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
package com.djrapitops.plan.system.update;
|
||||||
|
|
||||||
|
import com.djrapitops.plugin.api.utility.Version;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Scanner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility for loading version information from github.
|
||||||
|
*
|
||||||
|
* @author Rsl1122
|
||||||
|
*/
|
||||||
|
public class VersionInfoLoader {
|
||||||
|
|
||||||
|
private static final String VERSION_TXT_URL =
|
||||||
|
"https://raw.githubusercontent.com/Rsl1122/Plan-PlayerAnalytics/master/versions.txt";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads version information from github.
|
||||||
|
*
|
||||||
|
* @return List of VersionInfo, newest version first.
|
||||||
|
* @throws IOException If site can not be accessed.
|
||||||
|
* @throws java.net.MalformedURLException If VERSION_TXT_URL is not valid.
|
||||||
|
*/
|
||||||
|
public static List<VersionInfo> load() throws IOException {
|
||||||
|
URL url = new URL(VERSION_TXT_URL);
|
||||||
|
|
||||||
|
List<VersionInfo> versionInfo = new ArrayList<>();
|
||||||
|
|
||||||
|
try (Scanner websiteScanner = new Scanner(url.openStream())) {
|
||||||
|
while (websiteScanner.hasNextLine()) {
|
||||||
|
String line = websiteScanner.nextLine();
|
||||||
|
if (!line.startsWith("REL") && !line.startsWith("DEV")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String[] parts = line.split("\\|");
|
||||||
|
if (parts.length < 4) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
boolean release = parts[0].equals("REL");
|
||||||
|
Version version = new Version(parts[1]);
|
||||||
|
String downloadUrl = parts[2];
|
||||||
|
String changeLogUrl = parts[3];
|
||||||
|
|
||||||
|
versionInfo.add(new VersionInfo(release, version, downloadUrl, changeLogUrl));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Collections.sort(versionInfo);
|
||||||
|
return versionInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
name: Plan
|
name: Plan
|
||||||
author: Rsl1122
|
author: Rsl1122
|
||||||
main: com.djrapitops.plan.PlanBungee
|
main: com.djrapitops.plan.PlanBungee
|
||||||
version: 4.2.0
|
version: 4.2.0-b1
|
@ -12,6 +12,8 @@ Network:
|
|||||||
Plugin:
|
Plugin:
|
||||||
Debug: 'false'
|
Debug: 'false'
|
||||||
Locale: default
|
Locale: default
|
||||||
|
Allow-Update-Command: true
|
||||||
|
Notify-About-DEV-Releases: false
|
||||||
|
|
||||||
# -----------------------------------------------------
|
# -----------------------------------------------------
|
||||||
# More information about SSL Certificate Settings:
|
# More information about SSL Certificate Settings:
|
||||||
|
@ -17,6 +17,8 @@ Plugin:
|
|||||||
Bungee-Override:
|
Bungee-Override:
|
||||||
StandaloneMode: false
|
StandaloneMode: false
|
||||||
CopyBungeeConfig: true
|
CopyBungeeConfig: true
|
||||||
|
Allow-Update-Command: true
|
||||||
|
Notify-About-DEV-Releases: false
|
||||||
|
|
||||||
# -----------------------------------------------------
|
# -----------------------------------------------------
|
||||||
# More information about SSL Certificate Settings:
|
# More information about SSL Certificate Settings:
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
name: Plan
|
name: Plan
|
||||||
author: Rsl1122
|
author: Rsl1122
|
||||||
main: com.djrapitops.plan.Plan
|
main: com.djrapitops.plan.Plan
|
||||||
version: 4.2.0
|
version: 4.2.0-b1
|
||||||
softdepend:
|
softdepend:
|
||||||
- EssentialsX
|
- EssentialsX
|
||||||
- Towny
|
- Towny
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
package com.djrapitops.plan.system.update;
|
||||||
|
|
||||||
|
import com.djrapitops.plugin.api.utility.Version;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
public class VersionInfoLoaderTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void versionLoaderTest() throws IOException {
|
||||||
|
List<VersionInfo> versions = VersionInfoLoader.load();
|
||||||
|
|
||||||
|
VersionInfo oldest = versions.get(versions.size() - 1);
|
||||||
|
assertEquals(new Version("4.1.7"), oldest.getVersion());
|
||||||
|
assertTrue(oldest.isRelease());
|
||||||
|
assertTrue(oldest.isTrusted());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user