8 changed files with 318 additions and 11 deletions
@ -0,0 +1,27 @@ |
|||||||
|
package ru.simsonic.rscPermissions.Bukkit.Commands; |
||||||
|
|
||||||
|
import org.bukkit.command.CommandSender; |
||||||
|
import org.bukkit.entity.Player; |
||||||
|
import ru.simsonic.rscMinecraftLibrary.Bukkit.CommandAnswerException; |
||||||
|
import ru.simsonic.rscPermissions.BukkitPluginMain; |
||||||
|
|
||||||
|
public class CommandUpdate |
||||||
|
{ |
||||||
|
private final BukkitPluginMain rscp; |
||||||
|
CommandUpdate(BukkitPluginMain plugin) |
||||||
|
{ |
||||||
|
this.rscp = plugin; |
||||||
|
} |
||||||
|
public void execute(CommandSender sender, String args[]) throws CommandAnswerException |
||||||
|
{ |
||||||
|
if(sender.hasPermission("rscp.admin")) |
||||||
|
{ |
||||||
|
if(args.length > 0 && "do".equals(args[0])) |
||||||
|
{ |
||||||
|
rscp.updating.doUpdate(sender instanceof Player ? (Player)sender : null); |
||||||
|
} else { |
||||||
|
rscp.updating.checkUpdate(sender instanceof Player ? (Player)sender : null); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,247 @@ |
|||||||
|
package ru.simsonic.rscPermissions.Updater; |
||||||
|
|
||||||
|
import com.google.gson.Gson; |
||||||
|
import com.google.gson.JsonParseException; |
||||||
|
import java.io.ByteArrayOutputStream; |
||||||
|
import java.io.File; |
||||||
|
import java.io.FileOutputStream; |
||||||
|
import java.io.IOException; |
||||||
|
import java.io.InputStream; |
||||||
|
import java.net.HttpURLConnection; |
||||||
|
import java.net.MalformedURLException; |
||||||
|
import java.net.URISyntaxException; |
||||||
|
import java.net.URL; |
||||||
|
import java.nio.channels.Channels; |
||||||
|
import java.nio.channels.ReadableByteChannel; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.HashSet; |
||||||
|
import org.bukkit.command.ConsoleCommandSender; |
||||||
|
import org.bukkit.entity.Player; |
||||||
|
import org.bukkit.event.EventHandler; |
||||||
|
import org.bukkit.event.Listener; |
||||||
|
import org.bukkit.event.player.PlayerKickEvent; |
||||||
|
import org.bukkit.event.player.PlayerQuitEvent; |
||||||
|
import org.bukkit.plugin.java.JavaPlugin; |
||||||
|
import ru.simsonic.rscCommonsLibrary.RestartableThread; |
||||||
|
import ru.simsonic.rscMinecraftLibrary.Bukkit.GenericChatCodes; |
||||||
|
|
||||||
|
public final class BukkitUpdater implements Listener |
||||||
|
{ |
||||||
|
private final JavaPlugin plugin; |
||||||
|
private final String latestURL; |
||||||
|
private final HashSet<Player> staff = new HashSet<>(); |
||||||
|
private final String chatPrefix; |
||||||
|
public BukkitUpdater(JavaPlugin plugin, String latestURL, String chatPrefix) |
||||||
|
{ |
||||||
|
this.plugin = plugin; |
||||||
|
this.latestURL = latestURL; |
||||||
|
this.chatPrefix = chatPrefix; |
||||||
|
} |
||||||
|
public void onEnable() |
||||||
|
{ |
||||||
|
plugin.getServer().getPluginManager().registerEvents(BukkitUpdater.this, plugin); |
||||||
|
checkUpdate(null); |
||||||
|
} |
||||||
|
public void checkUpdate(Player sender) |
||||||
|
{ |
||||||
|
if(sender != null) |
||||||
|
staff.add(sender); |
||||||
|
threadCheck.start(); |
||||||
|
} |
||||||
|
public void doUpdate(Player sender) |
||||||
|
{ |
||||||
|
if(sender != null) |
||||||
|
staff.add(sender); |
||||||
|
threadUpdate.start(); |
||||||
|
} |
||||||
|
private final RestartableThread threadCheck = new RestartableThread() |
||||||
|
{ |
||||||
|
@Override |
||||||
|
public void run() |
||||||
|
{ |
||||||
|
checkForUpdate(); |
||||||
|
final ArrayList<String> lines = latestToLines(); |
||||||
|
if(lines != null) |
||||||
|
runLines(lines.toArray(new String[lines.size()])); |
||||||
|
else |
||||||
|
runLine("You are using the latest version."); |
||||||
|
} |
||||||
|
}; |
||||||
|
private final RestartableThread threadUpdate = new RestartableThread() |
||||||
|
{ |
||||||
|
@Override |
||||||
|
public void run() |
||||||
|
{ |
||||||
|
runLine("Downloading update..."); |
||||||
|
if(downloadUpdate()) |
||||||
|
{ |
||||||
|
// SUCCESS
|
||||||
|
runLine("Installing update..."); |
||||||
|
installUpdate(); |
||||||
|
runLines(new String[] |
||||||
|
{ |
||||||
|
"{_LG}Installation complete!", |
||||||
|
"Please restart your server to avoid errors.", |
||||||
|
}); |
||||||
|
} else { |
||||||
|
// FAILED
|
||||||
|
runLines(new String[] { |
||||||
|
"{_LR}Downloading error!", |
||||||
|
"Cannot download update file. Please try later.", |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
private Latest latest = new Latest(); |
||||||
|
private void checkForUpdate() |
||||||
|
{ |
||||||
|
try |
||||||
|
{ |
||||||
|
this.latest = new Gson().fromJson(downloadJson(latestURL), Latest.class); |
||||||
|
} catch(IOException ex) { |
||||||
|
this.latest = new Latest(); |
||||||
|
} |
||||||
|
if(latest.note == null) |
||||||
|
latest.note = "New version: " + latest.version; |
||||||
|
if(latest.notes == null) |
||||||
|
latest.notes = new String[] { latest.note }; |
||||||
|
if(latest.version == null) |
||||||
|
latest.version = plugin.getDescription().getVersion(); |
||||||
|
} |
||||||
|
private void runLine(final String line) |
||||||
|
{ |
||||||
|
runLines(new String[] { line }); |
||||||
|
} |
||||||
|
private void runLines(final String[] lines) |
||||||
|
{ |
||||||
|
final Runnable syncTask = new Runnable() |
||||||
|
{ |
||||||
|
@Override |
||||||
|
public synchronized void run() |
||||||
|
{ |
||||||
|
// CONSOLE
|
||||||
|
final ConsoleCommandSender console = plugin.getServer().getConsoleSender(); |
||||||
|
for(String line : lines) |
||||||
|
if(line != null) |
||||||
|
console.sendMessage(GenericChatCodes.processStringStatic(chatPrefix + line)); |
||||||
|
// PLAYERS
|
||||||
|
for(Player online : staff) |
||||||
|
for(String line : lines) |
||||||
|
if(line != null) |
||||||
|
online.sendMessage(GenericChatCodes.processStringStatic(chatPrefix + line)); |
||||||
|
notify(); |
||||||
|
} |
||||||
|
}; |
||||||
|
try |
||||||
|
{ |
||||||
|
synchronized(syncTask) |
||||||
|
{ |
||||||
|
plugin.getServer().getScheduler().runTask(plugin, syncTask); |
||||||
|
syncTask.wait(); |
||||||
|
} |
||||||
|
} catch(InterruptedException ex) { |
||||||
|
} |
||||||
|
} |
||||||
|
private ArrayList<String> latestToLines() |
||||||
|
{ |
||||||
|
// THERE IS NO UPDATE
|
||||||
|
if(plugin.getDescription().getVersion().equals(latest.version)) |
||||||
|
return null; |
||||||
|
// THERE IS AN UPDATE
|
||||||
|
final ArrayList<String> result = new ArrayList<>(); |
||||||
|
result.add("New " |
||||||
|
+ (latest.snapshot ? "{_DS}snapshot {_LS}" : "{_WH}release {_LS}") |
||||||
|
+ "version {_LG}" + latest.version + "{_LS} is available!"); |
||||||
|
result.addAll(Arrays.asList(latest.notes)); |
||||||
|
result.add("Apply this update with command {GOLD}/rscfjd update do"); |
||||||
|
return result; |
||||||
|
} |
||||||
|
public void onAdminJoin(Player player, boolean fromEvent) |
||||||
|
{ |
||||||
|
staff.add(player); |
||||||
|
if(fromEvent) |
||||||
|
{ |
||||||
|
final ArrayList<String> lines = latestToLines(); |
||||||
|
if(lines != null) |
||||||
|
for(String line : lines) |
||||||
|
if(line != null) |
||||||
|
player.sendMessage(GenericChatCodes.processStringStatic(chatPrefix + line)); |
||||||
|
} |
||||||
|
} |
||||||
|
@EventHandler |
||||||
|
protected void onPlayerQuit(PlayerQuitEvent event) |
||||||
|
{ |
||||||
|
staff.add(event.getPlayer()); |
||||||
|
} |
||||||
|
@EventHandler |
||||||
|
protected void onPlayerKick(PlayerKickEvent event) |
||||||
|
{ |
||||||
|
staff.add(event.getPlayer()); |
||||||
|
} |
||||||
|
private static String downloadJson(String url) throws IOException |
||||||
|
{ |
||||||
|
try |
||||||
|
{ |
||||||
|
final HttpURLConnection connection = (HttpURLConnection)new URL(url).openConnection(); |
||||||
|
connection.setDoOutput(true); |
||||||
|
connection.setDoInput(true); |
||||||
|
connection.setConnectTimeout(5000); |
||||||
|
connection.setReadTimeout(5000); |
||||||
|
connection.setUseCaches(false); |
||||||
|
final int responseCode = connection.getResponseCode(); |
||||||
|
if(responseCode == HttpURLConnection.HTTP_OK) |
||||||
|
return readUnicodeStream(connection.getInputStream()); |
||||||
|
throw new IOException(new StringBuilder() |
||||||
|
.append(Integer.toString(responseCode)) |
||||||
|
.append("Erroneous result of executing web-method: ") |
||||||
|
.append(connection.getResponseMessage()) |
||||||
|
.append("\r\n") |
||||||
|
.append(readUnicodeStream(connection.getErrorStream())) |
||||||
|
.toString()); |
||||||
|
} catch(JsonParseException | MalformedURLException ex) { |
||||||
|
throw new IOException(ex); |
||||||
|
} catch(IOException ex) { |
||||||
|
throw ex; |
||||||
|
} |
||||||
|
} |
||||||
|
private static String readUnicodeStream(InputStream is) throws IOException |
||||||
|
{ |
||||||
|
try(ByteArrayOutputStream baos = new ByteArrayOutputStream()) |
||||||
|
{ |
||||||
|
final byte[] buffer = new byte[1024]; |
||||||
|
for(int length = 0; length != -1; length = is.read(buffer)) |
||||||
|
baos.write(buffer, 0, length); |
||||||
|
return new String(baos.toByteArray(), "UTF-8"); |
||||||
|
} |
||||||
|
} |
||||||
|
private boolean downloadUpdate() |
||||||
|
{ |
||||||
|
final File folder = plugin.getDataFolder().getParentFile(); |
||||||
|
final File target = new File(folder, plugin.getName() + "_v" + latest.version + ".jar"); |
||||||
|
try(FileOutputStream fos = new FileOutputStream(target)) |
||||||
|
{ |
||||||
|
final ReadableByteChannel rbc = Channels.newChannel(new URL(latest.url).openStream()); |
||||||
|
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); |
||||||
|
fos.flush(); |
||||||
|
return true; |
||||||
|
} catch(MalformedURLException ex) { |
||||||
|
System.err.println(ex); |
||||||
|
} catch(IOException ex) { |
||||||
|
System.err.println(ex); |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
private void installUpdate() |
||||||
|
{ |
||||||
|
// RENAME OLD VERSION
|
||||||
|
try |
||||||
|
{ |
||||||
|
final String outdatedJarPath = plugin.getClass().getProtectionDomain().getCodeSource().getLocation().toURI().getPath(); |
||||||
|
final File outdatedJarSrc = new File(outdatedJarPath); |
||||||
|
final File outdatedJarDst = new File(outdatedJarPath + "-outdated"); |
||||||
|
outdatedJarSrc.renameTo(outdatedJarDst); |
||||||
|
} catch(URISyntaxException ex) { |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue