001/* 002 * PlotSquared, a land and world management plugin for Minecraft. 003 * Copyright (C) IntellectualSites <https://intellectualsites.com> 004 * Copyright (C) IntellectualSites team and contributors 005 * 006 * This program is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * This program is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with this program. If not, see <https://www.gnu.org/licenses/>. 018 */ 019package com.plotsquared.core.backup; 020 021import com.google.common.cache.Cache; 022import com.google.common.cache.CacheBuilder; 023import com.google.inject.Inject; 024import com.google.inject.Singleton; 025import com.plotsquared.core.PlotSquared; 026import com.plotsquared.core.configuration.Settings; 027import com.plotsquared.core.configuration.caption.Templates; 028import com.plotsquared.core.configuration.caption.TranslatableCaption; 029import com.plotsquared.core.inject.factory.PlayerBackupProfileFactory; 030import com.plotsquared.core.player.PlotPlayer; 031import com.plotsquared.core.plot.Plot; 032import com.plotsquared.core.util.task.TaskManager; 033import net.kyori.adventure.text.minimessage.Template; 034import org.checkerframework.checker.nullness.qual.NonNull; 035import org.checkerframework.checker.nullness.qual.Nullable; 036 037import java.nio.file.Files; 038import java.nio.file.Path; 039import java.util.Objects; 040import java.util.concurrent.ExecutionException; 041import java.util.concurrent.TimeUnit; 042 043/** 044 * {@inheritDoc} 045 */ 046@Singleton 047public class SimpleBackupManager implements BackupManager { 048 049 private final Path backupPath; 050 private final boolean automaticBackup; 051 private final int backupLimit; 052 private final Cache<PlotCacheKey, BackupProfile> backupProfileCache = CacheBuilder.newBuilder() 053 .expireAfterAccess(3, TimeUnit.MINUTES).build(); 054 private final PlayerBackupProfileFactory playerBackupProfileFactory; 055 056 @Inject 057 public SimpleBackupManager(final @NonNull PlayerBackupProfileFactory playerBackupProfileFactory) throws Exception { 058 this.playerBackupProfileFactory = playerBackupProfileFactory; 059 this.backupPath = Objects.requireNonNull(PlotSquared.platform()).getDirectory().toPath().resolve("backups"); 060 if (!Files.exists(backupPath)) { 061 Files.createDirectory(backupPath); 062 } 063 this.automaticBackup = Settings.Backup.AUTOMATIC_BACKUPS; 064 this.backupLimit = Settings.Backup.BACKUP_LIMIT; 065 } 066 067 public SimpleBackupManager( 068 final Path backupPath, final boolean automaticBackup, 069 final int backupLimit, final PlayerBackupProfileFactory playerBackupProfileFactory 070 ) { 071 this.backupPath = backupPath; 072 this.automaticBackup = automaticBackup; 073 this.backupLimit = backupLimit; 074 this.playerBackupProfileFactory = playerBackupProfileFactory; 075 } 076 077 @Override 078 public @NonNull BackupProfile getProfile(final @NonNull Plot plot) { 079 if (plot.hasOwner()) { 080 try { 081 return backupProfileCache.get( 082 new PlotCacheKey(plot), 083 () -> this.playerBackupProfileFactory.create(plot.getOwnerAbs(), plot) 084 ); 085 } catch (ExecutionException e) { 086 final BackupProfile profile = this.playerBackupProfileFactory.create(plot.getOwnerAbs(), plot); 087 this.backupProfileCache.put(new PlotCacheKey(plot), profile); 088 return profile; 089 } 090 } 091 return new NullBackupProfile(); 092 } 093 094 @Override 095 public void automaticBackup(@Nullable PlotPlayer<?> player, final @NonNull Plot plot, @NonNull Runnable whenDone) { 096 final BackupProfile profile; 097 if (!this.shouldAutomaticallyBackup() || (profile = getProfile(plot)) instanceof NullBackupProfile) { 098 whenDone.run(); 099 } else { 100 if (player != null) { 101 player.sendMessage( 102 TranslatableCaption.of("backups.backup_automatic_started"), 103 Template.of("plot", plot.getId().toString()) 104 ); 105 } 106 profile.createBackup().whenComplete((backup, throwable) -> { 107 if (throwable != null) { 108 if (player != null) { 109 player.sendMessage( 110 TranslatableCaption.of("backups.backup_automatic_failure"), 111 Templates.of("reason", throwable.getMessage()) 112 ); 113 } 114 throwable.printStackTrace(); 115 } else { 116 if (player != null) { 117 player.sendMessage(TranslatableCaption.of("backups.backup_automatic_finished")); 118 TaskManager.runTaskAsync(whenDone); 119 } 120 } 121 }); 122 } 123 } 124 125 @Override 126 public boolean shouldAutomaticallyBackup() { 127 return this.automaticBackup; 128 } 129 130 public Path getBackupPath() { 131 return this.backupPath; 132 } 133 134 public int getBackupLimit() { 135 return this.backupLimit; 136 } 137 138 private static final class PlotCacheKey { 139 140 private final Plot plot; 141 142 private PlotCacheKey(Plot plot) { 143 this.plot = plot; 144 } 145 146 @Override 147 public boolean equals(final Object o) { 148 if (this == o) { 149 return true; 150 } 151 if (o == null || getClass() != o.getClass()) { 152 return false; 153 } 154 final PlotCacheKey that = (PlotCacheKey) o; 155 return Objects.equals(plot.getArea(), that.plot.getArea()) 156 && Objects.equals(plot.getId(), that.plot.getId()) 157 && Objects.equals(plot.getOwnerAbs(), that.plot.getOwnerAbs()); 158 } 159 160 @Override 161 public int hashCode() { 162 return Objects.hash(plot.getArea(), plot.getId(), plot.getOwnerAbs()); 163 } 164 165 } 166 167}