UpdateModule class

Пакет: com.hypixel.hytale.server.core.update

Файл: com/hypixel/hytale/server/core/update/UpdateModule.java

extends: JavaPlugin

Поля (54)

МодификаторыТипИмя
break
instance
Thread var1
String var1
UpdateConfig var1
String var1
long var1
CompletableFuture var1
UpdateConfig var1
ServerAuthManager var1
String var1
long var10
var10
Instant var10
long var11
double var12
long var13
long var14
long var15
long var17
UpdateConfig var2
UpdateConfig.AutoApplyMode var2
Thread var2
ServerAuthManager var2
String var2
UpdateService var2
UpdateConfig var2
Universe var2
Universe var2
int var3
long var3
String var3
String var3
String var3
String var3
UpdateService.DownloadTask var3
UpdateConfig var3
String var3
UpdateConfig.AutoApplyMode var3
Message var3
UpdateService.PatchlineSummary[] var4
String var4
UpdateConfig var4
CompletableFuture var4
Universe var4
PermissionsModule var4
long var5
String var5
int var5
int var6
int var7
long var7
long var8
long var9

Методы (51)

МодификаторыВозвратСигнатура
public record DownloadProgressrecord DownloadProgress(int percent, long downloadedBytes, long totalBytes, long etaSeconds)
private void autoDownloadUpdatevoid autoDownloadUpdate(@Nonnull UpdateService var1, @Nonnull UpdateService.VersionManifest var2)
private void broadcastToPlayersvoid broadcastToPlayers(@Nonnull Message var1)
public boolean cancelDownloadboolean cancelDownload()
private void checkAutoApplyvoid checkAutoApply(@Nonnull String var1)
private boolean checkPatchlineExpiryboolean checkPatchlineExpiry(UpdateService var1)
for for(UpdateService.PatchlineSummary var9 : var4)
if if(KILL_SWITCH_ENABLED)
if if(!KILL_SWITCH_ENABLED)
if if(var1 != null)
if if(this.autoApplyTask == null)
if if(var2 != UpdateConfig.AutoApplyMode.DISABLED)
if if(this.updateCheckTask != null)
if if(this.autoApplyTask != null)
if if(!KILL_SWITCH_ENABLED)
if if(var1 != null)
if if(var1 != 0L && var5 > 0L)
if if(var8 > 0L && var3 > 0L)
if if(var2 != null)
if if(var1 == null && var2 == null)
if if(var1 != null)
if if(var3 == null)
if if(var4 == null)
if if(Constants.SINGLEPLAYER)
if if(!var1x)
if if(var3 != null)
if if(var2x == null)
if if(var1 == null)
if if(var2)
if if(var3 != UpdateConfig.AutoApplyMode.DISABLED)
if if(var4 != null)
if if(var5 == 0)
if if(var7 >= var11 - 2000L)
if if(var2 != null)
if if(var2 != null)
public boolean isDownloadInProgressboolean isDownloadInProgress()
private void logStagedUpdateWarningvoid logStagedUpdateWarning(@Nullable String var1, boolean var2)
private void logUpdateAvailablevoid logUpdateAvailable(@Nullable String var1, @Nonnull String var2)
private void notifyPlayersvoid notifyPlayers(@Nonnull String var1)
public void onServerReadyvoid onServerReady()
private void performAutoApplyCheckvoid performAutoApplyCheck()
private void performUpdateCheckvoid performUpdateCheck()
public void releaseDownloadLockvoid releaseDownloadLock()
public void setActiveDownloadvoid setActiveDownload(@Nullable CompletableFuture<?> var1, @Nullable Thread var2)
public void setLatestKnownVersionvoid setLatestKnownVersion(@Nullable UpdateService.VersionManifest var1)
private boolean shouldEnableUpdateCheckerboolean shouldEnableUpdateChecker()
synchronized void startAutoApplyTaskIfNeededvoid startAutoApplyTaskIfNeeded()
abstract super super(var1)
private void triggerAutoApplyvoid triggerAutoApply()
public boolean tryAcquireDownloadLockboolean tryAcquireDownloadLock()
public void updateDownloadProgressvoid updateDownloadProgress(long var1, long var3)

Исходный код

Показать/скрыть
class="kw">package com.hypixel.hytale.server.core.update;

class="kw">import com.hypixel.hytale.common.plugin.PluginManifest;
class="kw">import com.hypixel.hytale.common.util.SystemUtil;
class="kw">import com.hypixel.hytale.common.util.java.ManifestUtil;
class="kw">import com.hypixel.hytale.logger.HytaleLogger;
class="kw">import com.hypixel.hytale.server.core.Constants;
class="kw">import com.hypixel.hytale.server.core.HytaleServer;
class="kw">import com.hypixel.hytale.server.core.Message;
class="kw">import com.hypixel.hytale.server.core.ShutdownReason;
class="kw">import com.hypixel.hytale.server.core.auth.ServerAuthManager;
class="kw">import com.hypixel.hytale.server.core.config.UpdateConfig;
class="kw">import com.hypixel.hytale.server.core.permissions.HytalePermissions;
class="kw">import com.hypixel.hytale.server.core.permissions.PermissionsModule;
class="kw">import com.hypixel.hytale.server.core.plugin.JavaPlugin;
class="kw">import com.hypixel.hytale.server.core.plugin.JavaPluginInit;
class="kw">import com.hypixel.hytale.server.core.universe.PlayerRef;
class="kw">import com.hypixel.hytale.server.core.universe.Universe;
class="kw">import com.hypixel.hytale.server.core.update.command.UpdateCommand;
class="kw">import java.awt.Color;
class="kw">import java.io.IOException;
class="kw">import java.time.Instant;
class="kw">import java.util.concurrent.CancellationException;
class="kw">import java.util.concurrent.CompletableFuture;
class="kw">import java.util.concurrent.Executors;
class="kw">import java.util.concurrent.ScheduledExecutorService;
class="kw">import java.util.concurrent.ScheduledFuture;
class="kw">import java.util.concurrent.TimeUnit;
class="kw">import java.util.concurrent.atomic.AtomicBoolean;
class="kw">import java.util.concurrent.atomic.AtomicLong;
class="kw">import java.util.concurrent.atomic.AtomicReference;
class="kw">import java.util.logging.Level;
class="kw">import javax.annotation.Nonnull;
class="kw">import javax.annotation.Nullable;

class="kw">public class UpdateModule class="kw">extends JavaPlugin {
   @Nonnull
   class="kw">public class="kw">static class="kw">final PluginManifest MANIFEST = PluginManifest.corePlugin(UpdateModule.class).build();
   @Nonnull
   class="kw">private class="kw">static class="kw">final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass();
   class="kw">public class="kw">static class="kw">final boolean KILL_SWITCH_ENABLED = SystemUtil.getEnvBoolean("HYTALE_DISABLE_UPDATES");
   class="kw">private class="kw">static UpdateModule instance;
   @Nonnull
   class="kw">private class="kw">final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(var0 -> {
      Thread var1 = new Thread(var0, "UpdateChecker");
      var1.setDaemon(true);
      class="kw">return var1;
   });
   @Nullable
   class="kw">private ScheduledFuture<?> updateCheckTask;
   @Nullable
   class="kw">private ScheduledFuture<?> autoApplyTask;
   class="kw">private class="kw">final AtomicReference<UpdateService.VersionManifest> latestKnownVersion = new AtomicReference<>();
   class="kw">private class="kw">final AtomicReference<CompletableFuture<?>> activeDownload = new AtomicReference<>();
   class="kw">private class="kw">final AtomicReference<Thread> activeDownloadThread = new AtomicReference<>();
   class="kw">private class="kw">final AtomicBoolean downloadLock = new AtomicBoolean(false);
   class="kw">private class="kw">final AtomicLong downloadStartTime = new AtomicLong(0L);
   class="kw">private class="kw">final AtomicLong downloadedBytes = new AtomicLong(0L);
   class="kw">private class="kw">final AtomicLong totalBytes = new AtomicLong(0L);
   class="kw">private class="kw">final AtomicLong autoApplyScheduledTime = new AtomicLong(0L);
   class="kw">private class="kw">final AtomicLong lastWarningTime = new AtomicLong(0L);
   class="kw">private class="kw">final AtomicBoolean patchlineExpiryChecked = new AtomicBoolean(false);

   class="kw">public UpdateModule(@Nonnull JavaPluginInit var1) {
      super(var1);
      instance = this;
   }

   @Nullable
   class="kw">public class="kw">static UpdateModule get() {
      class="kw">return instance;
   }

   @Override
   class="kw">protected void setup() {
      if (KILL_SWITCH_ENABLED) {
         LOGGER.at(Level.INFO).log("Update commands disabled via HYTALE_DISABLE_UPDATES environment variable");
      }

      this.getCommandRegistry().registerCommand(new UpdateCommand());
   }

   @Override
   class="kw">protected void start() {
      if (!KILL_SWITCH_ENABLED) {
         String var1 = UpdateService.getStagedVersion();
         if (var1 != null) {
            this.logStagedUpdateWarning(var1, true);
            this.startAutoApplyTaskIfNeeded();
         }

         if (this.shouldEnableUpdateChecker()) {
            UpdateConfig var2 = HytaleServer.get().getConfig().getUpdateConfig();
            int var3 = var2.getCheckIntervalSeconds();
            LOGGER.at(Level.INFO).log("Update checker enabled (interval: %ds)", var3);
            this.updateCheckTask = this.scheduler.scheduleAtFixedRate(this::performUpdateCheck, 60L, var3, TimeUnit.SECONDS);
         }
      }
   }

   class="kw">private class="kw">synchronized void startAutoApplyTaskIfNeeded() {
      if (this.autoApplyTask == null) {
         UpdateConfig var1 = HytaleServer.get().getConfig().getUpdateConfig();
         UpdateConfig.AutoApplyMode var2 = var1.getAutoApplyMode();
         if (var2 != UpdateConfig.AutoApplyMode.DISABLED) {
            LOGGER.at(Level.INFO).log("Starting auto-apply task (mode: %s, delay: %d min)", var2, var1.getAutoApplyDelayMinutes());
            this.autoApplyTask = this.scheduler.scheduleAtFixedRate(this::performAutoApplyCheck, 0L, 60L, TimeUnit.SECONDS);
         }
      }
   }

   @Override
   class="kw">protected void shutdown() {
      if (this.updateCheckTask != null) {
         this.updateCheckTask.cancel(false);
      }

      if (this.autoApplyTask != null) {
         this.autoApplyTask.cancel(false);
      }

      this.scheduler.shutdown();
   }

   class="kw">public void onServerReady() {
      if (!KILL_SWITCH_ENABLED) {
         String var1 = UpdateService.getStagedVersion();
         if (var1 != null) {
            this.logStagedUpdateWarning(var1, false);
         }
      }
   }

   @Nullable
   class="kw">public UpdateService.VersionManifest getLatestKnownVersion() {
      class="kw">return this.latestKnownVersion.get();
   }

   class="kw">public void setLatestKnownVersion(@Nullable UpdateService.VersionManifest var1) {
      this.latestKnownVersion.set(var1);
   }

   class="kw">public boolean isDownloadInProgress() {
      class="kw">return this.downloadLock.get();
   }

   class="kw">public boolean tryAcquireDownloadLock() {
      class="kw">return this.downloadLock.compareAndSet(false, true);
   }

   class="kw">public void setActiveDownload(@Nullable CompletableFuture<?> var1, @Nullable Thread var2) {
      this.activeDownload.set(var1);
      this.activeDownloadThread.set(var2);
   }

   class="kw">public void releaseDownloadLock() {
      this.activeDownload.set(null);
      this.activeDownloadThread.set(null);
      this.downloadLock.set(false);
      this.downloadStartTime.set(0L);
      this.downloadedBytes.set(0L);
      this.totalBytes.set(0L);
   }

   class="kw">public void updateDownloadProgress(long var1, long var3) {
      if (this.downloadStartTime.get() == 0L) {
         this.downloadStartTime.set(System.currentTimeMillis());
      }

      this.downloadedBytes.set(var1);
      this.totalBytes.set(var3);
   }

   @Nullable
   class="kw">public UpdateModule.DownloadProgress getDownloadProgress() {
      if (!this.downloadLock.get()) {
         class="kw">return null;
      }

      long var1 = this.downloadStartTime.get();
      long var3 = this.downloadedBytes.get();
      long var5 = this.totalBytes.get();
      if (var1 != 0L && var5 > 0L) {
         int var7 = (int)(var3 * 100L / var5);
         long var8 = System.currentTimeMillis() - var1;
         long var10 = -1L;
         if (var8 > 0L && var3 > 0L) {
            double var12 = (double)var3 / var8;
            long var14 = var5 - var3;
            var10 = (long)(var14 / var12 / 1000.0);
         }

         class="kw">return new UpdateModule.DownloadProgress(var7, var3, var5, var10);
      } else {
         class="kw">return new UpdateModule.DownloadProgress(0, 0L, var5, -1L);
      }
   }

   class="kw">public boolean cancelDownload() {
      CompletableFuture var1 = this.activeDownload.getAndSet(null);
      Thread var2 = this.activeDownloadThread.getAndSet(null);
      if (var2 != null) {
         var2.interrupt();
      }

      if (var1 == null && var2 == null) {
         class="kw">return false;
      }

      if (var1 != null) {
         var1.cancel(true);
      }

      this.releaseDownloadLock();
      class="kw">return true;
   }

   class="kw">private boolean checkPatchlineExpiry(UpdateService var1) class="kw">throws IOException, InterruptedException {
      ServerAuthManager var2 = ServerAuthManager.getInstance();
      String var3 = var2.getOAuthAccessToken();
      if (var3 == null) {
         class="kw">return false;
      }

      UpdateService.PatchlineSummary[] var4 = var1.fetchPatchlines(var3);
      if (var4 == null) {
         class="kw">return false;
      }

      String var5 = UpdateService.getEffectivePatchline();

      for (UpdateService.PatchlineSummary var9 : var4) {
         if (var9.name.equals(var5) && var9.expiresAt > 0L) {
            Instant var10 = Instant.ofEpochMilli(var9.expiresAt);
            if (var10.isBefore(Instant.now())) {
               LOGGER.at(Level.SEVERE).log("Patchline '%s' expired at %s", var5, var10);
            } else {
               LOGGER.at(Level.WARNING).log("Patchline '%s' will expire at %s", var5, var10);
            }
            break;
         }
      }

      class="kw">return true;
   }

   class="kw">private boolean shouldEnableUpdateChecker() {
      if (!ManifestUtil.isJar()) {
         LOGGER.at(Level.INFO).log("Update checker disabled: not running from JAR");
         class="kw">return false;
      }

      if (Constants.SINGLEPLAYER) {
         LOGGER.at(Level.INFO).log("Update checker disabled: singleplayer mode");
         class="kw">return false;
      }

      UpdateConfig var1 = HytaleServer.get().getConfig().getUpdateConfig();
      if (!var1.isEnabled()) {
         LOGGER.at(Level.INFO).log("Update checker disabled: disabled in config");
         class="kw">return false;
      }

      String var2 = ManifestUtil.getPatchline();
      String var3 = var1.getPatchline();
      if (!"dev".equals(var2) || var3 != null && !var3.isEmpty()) {
         if (!UpdateService.isValidUpdateLayout()) {
            LOGGER.at(Level.WARNING)
               .log("Update checker disabled: invalid folder layout. Expected to run from Server/ with Assets.zip and start.sh/bat in parent directory.");
            class="kw">return false;
         } else {
            class="kw">return true;
         }
      } else {
         LOGGER.at(Level.INFO).log("Update checker disabled: dev patchline (set Patchline in config to override)");
         class="kw">return false;
      }
   }

   class="kw">private void performUpdateCheck() {
      ServerAuthManager var1 = ServerAuthManager.getInstance();
      if (!var1.hasSessionToken()) {
         LOGGER.at(Level.FINE).log("Not authenticated - skipping update check");
      } else {
         UpdateService var2 = new UpdateService();
         if (this.patchlineExpiryChecked.compareAndSet(false, true)) {
            CompletableFuture.<Boolean>supplyAsync(() -> {
               try {
                  class="kw">return this.checkPatchlineExpiry(var2);
               } catch (InterruptedException var3) {
                  Thread.currentThread().interrupt();
                  class="kw">return false;
               } catch (Exception var4) {
                  ((HytaleLogger.Api)LOGGER.at(Level.WARNING).withCause(var4)).log("Failed to check patchline expiry");
                  class="kw">return false;
               }
            }).thenAccept(var1x -> {
               if (!var1x) {
                  this.patchlineExpiryChecked.set(false);
               }
            });
         }

         String var3 = UpdateService.getStagedVersion();
         if (var3 != null) {
            LOGGER.at(Level.FINE).log("Staged update already exists (%s) - skipping update check", var3);
            this.startAutoApplyTaskIfNeeded();
         } else if (this.isDownloadInProgress()) {
            LOGGER.at(Level.FINE).log("Download in progress - skipping update check");
         } else {
            String var4 = UpdateService.getEffectivePatchline();
            var2.checkForUpdate(var4).thenAccept(var2x -> {
               if (var2x == null) {
                  LOGGER.at(Level.FINE).log("Update check returned no result");
               } else {
                  this.setLatestKnownVersion(var2x);
                  String var3 = ManifestUtil.getImplementationVersion();
                  if (var3 != null && var3.equals(var2x.version)) {
                     LOGGER.at(Level.FINE).log("Already running latest version: %s", var3);
                  } else {
                     this.logUpdateAvailable(var3, var2x.version);
                     UpdateConfig var4 = HytaleServer.get().getConfig().getUpdateConfig();
                     if (var4.isNotifyPlayersOnAvailable()) {
                        this.notifyPlayers(var2x.version);
                     }

                     if (var4.getAutoApplyMode() != UpdateConfig.AutoApplyMode.DISABLED) {
                        LOGGER.at(Level.INFO).log("Auto-downloading update %s...", var2x.version);
                        this.autoDownloadUpdate(var2, var2x);
                     }
                  }
               }
            });
         }
      }
   }

   class="kw">private void autoDownloadUpdate(@Nonnull UpdateService var1, @Nonnull UpdateService.VersionManifest var2) {
      if (UpdateService.getStagedVersion() == null && this.tryAcquireDownloadLock()) {
         UpdateService.DownloadTask var3 = var1.downloadUpdate(
            var2, UpdateService.getStagingDir(), (var1x, var2x, var4x) -> this.updateDownloadProgress(var2x, var4x)
         );
         CompletableFuture var4 = var3.future().whenComplete((var2x, var3x) -> {
            this.releaseDownloadLock();
            if (Boolean.TRUE.equals(var2x)) {
               LOGGER.at(Level.INFO).log("Update %s downloaded and staged", var2.version);
               this.startAutoApplyTaskIfNeeded();
            } else if (var3x class="kw">instanceof CancellationException) {
               LOGGER.at(Level.INFO).log("Download of update %s was cancelled", var2.version);
               UpdateService.deleteStagedUpdate();
            } else {
               LOGGER.at(Level.WARNING).log("Failed to download update %s: %s", var2.version, var3x != null ? var3x.getMessage() : "unknown error");
               UpdateService.deleteStagedUpdate();
            }
         });
         this.setActiveDownload(var4, var3.thread());
      }
   }

   class="kw">private void performAutoApplyCheck() {
      String var1 = UpdateService.getStagedVersion();
      if (var1 == null) {
         if (this.autoApplyScheduledTime.getAndSet(0L) != 0L) {
            LOGGER.at(Level.FINE).log("No staged update - clearing auto-apply schedule");
         }

         this.lastWarningTime.set(0L);
      } else {
         LOGGER.at(Level.FINE).log("Auto-apply check: staged version %s", var1);
         this.checkAutoApply(var1);
      }
   }

   class="kw">private void logUpdateAvailable(@Nullable String var1, @Nonnull String var2) {
      LOGGER.at(Level.INFO).log("Update available: %s (current: %s)", var2, var1);
      UpdateConfig var3 = HytaleServer.get().getConfig().getUpdateConfig();
      if (var3.getAutoApplyMode() == UpdateConfig.AutoApplyMode.DISABLED) {
         LOGGER.at(Level.INFO).log("Run '/update download' to stage the update");
      }
   }

   class="kw">private void logStagedUpdateWarning(@Nullable String var1, boolean var2) {
      String var3 = "\u001b[0;33m===============================================================================================";
      LOGGER.at(Level.INFO).log("%s", var3);
      if (var2) {
         LOGGER.at(Level.INFO).log("%s         WARNING: Staged update %s not applied!", "\u001b[0;33m", var1 != null ? var1 : "unknown");
         LOGGER.at(Level.INFO).log("%s         Use launcher script (start.sh/bat) or manually move files from updater/staging/", "\u001b[0;33m");
      } else {
         LOGGER.at(Level.INFO).log("%s         REMINDER: Staged update %s waiting to be applied", "\u001b[0;33m", var1 != null ? var1 : "unknown");
         LOGGER.at(Level.INFO).log("%s         Run '/update status' for details or '/update cancel' to abort", "\u001b[0;33m");
      }

      LOGGER.at(Level.INFO).log("%s", var3);
   }

   class="kw">private void checkAutoApply(@Nonnull String var1) {
      UpdateConfig var2 = HytaleServer.get().getConfig().getUpdateConfig();
      UpdateConfig.AutoApplyMode var3 = var2.getAutoApplyMode();
      if (var3 != UpdateConfig.AutoApplyMode.DISABLED) {
         Universe var4 = Universe.get();
         if (var4 != null) {
            int var5 = var4.getPlayers().size();
            if (var5 == 0) {
               LOGGER.at(Level.INFO).log("No players online - auto-applying update %s", var1);
               this.triggerAutoApply();
            } else if (var3 != UpdateConfig.AutoApplyMode.WHEN_EMPTY) {
               int var6 = var2.getAutoApplyDelayMinutes();
               long var7 = System.currentTimeMillis();
               long var9 = var7 + var6 * 60L * 1000L;
               if (this.autoApplyScheduledTime.compareAndSet(0L, var9)) {
                  LOGGER.at(Level.INFO).log("Update %s will be auto-applied in %d minutes (players online: %d)", var1, var6, var5);
                  this.broadcastToPlayers(
                     Message.translation("server.update.auto_apply_warning").param("version", var1).param("minutes", var6).color(Color.YELLOW)
                  );
               } else {
                  long var11 = this.autoApplyScheduledTime.get();
                  if (var7 >= var11 - 2000L) {
                     LOGGER.at(Level.INFO).log("Auto-apply delay expired - applying update %s", var1);
                     this.broadcastToPlayers(Message.translation("server.update.auto_apply_now").param("version", var1).color(Color.RED));
                     this.triggerAutoApply();
                  } else {
                     long var13 = (var11 - var7) / 60000L;
                     long var15 = var13 <= 1L ? 30000L : 300000L;
                     long var17 = this.lastWarningTime.get();
                     if (var7 - var17 >= var15 && this.lastWarningTime.compareAndSet(var17, var7)) {
                        LOGGER.at(Level.INFO).log("Update %s will be auto-applied in %d minute(s)", var1, Math.max(1L, var13));
                        this.broadcastToPlayers(
                           Message.translation("server.update.auto_apply_warning")
                              .param("version", var1)
                              .param("minutes", Math.max(1L, var13))
                              .color(Color.YELLOW)
                        );
                     }
                  }
               }
            }
         }
      }
   }

   class="kw">private void triggerAutoApply() {
      this.autoApplyScheduledTime.set(0L);
      HytaleServer.get().shutdownServer(ShutdownReason.UPDATE);
   }

   class="kw">private void broadcastToPlayers(@Nonnull Message var1) {
      Universe var2 = Universe.get();
      if (var2 != null) {
         for (PlayerRef var4 : var2.getPlayers()) {
            var4.sendMessage(var1);
         }
      }
   }

   class="kw">private void notifyPlayers(@Nonnull String var1) {
      Universe var2 = Universe.get();
      if (var2 != null) {
         Message var3 = Message.translation("server.update.notify_players").param("version", var1);
         PermissionsModule var4 = PermissionsModule.get();

         for (PlayerRef var6 : var2.getPlayers()) {
            if (var4.hasPermission(var6.getUuid(), HytalePermissions.UPDATE_NOTIFY)) {
               var6.sendMessage(var3);
            }
         }
      }
   }

   class="kw">public record DownloadProgress(int percent, long downloadedBytes, long totalBytes, long etaSeconds) {
      class="kw">public DownloadProgress {
      }
   }
}