mirror of
https://github.com/essentials/Essentials.git
synced 2025-08-15 11:04:29 +02:00
Add support for zipped User / Warp files
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -31,4 +31,5 @@ manifest.mf
|
||||
*.iws
|
||||
.idea/
|
||||
|
||||
EssentialsRelease/
|
||||
EssentialsRelease/
|
||||
/Essentials/dependency-reduced-pom.xml
|
@@ -21,7 +21,17 @@
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>0.11.4</version>
|
||||
<version>0.11.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-compress</artifactId>
|
||||
<version>1.4.1</version>
|
||||
</dependency>
|
||||
<!-- Test Depends -->
|
||||
<dependency>
|
||||
@@ -63,4 +73,37 @@
|
||||
<version>1.2</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>2.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<artifactSet>
|
||||
<includes>
|
||||
<include>commons-io:*</include>
|
||||
<include>org.apache.commons:*</include>
|
||||
</includes>
|
||||
</artifactSet>
|
||||
<minimizeJar>true</minimizeJar>
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>org.apache.commons</pattern>
|
||||
<shadedPattern>net.ess3.commons</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
@@ -5,16 +5,23 @@ import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentSkipListMap;
|
||||
import java.util.concurrent.ConcurrentSkipListSet;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.regex.Pattern;
|
||||
import net.ess3.api.IEssentials;
|
||||
import net.ess3.api.InvalidNameException;
|
||||
import net.ess3.utils.Util;
|
||||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
||||
import org.apache.commons.compress.archivers.zip.ZipFile;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
|
||||
public abstract class StorageObjectMap<I> extends CacheLoader<String, I> implements IStorageObjectMap<I>
|
||||
@@ -23,6 +30,7 @@ public abstract class StorageObjectMap<I> extends CacheLoader<String, I> impleme
|
||||
private final transient File folder;
|
||||
protected final transient Cache<String, I> cache = CacheBuilder.newBuilder().softValues().build(this);
|
||||
protected final transient ConcurrentSkipListSet<String> keys = new ConcurrentSkipListSet<String>();
|
||||
protected final transient ConcurrentSkipListMap<String, File> zippedfiles = new ConcurrentSkipListMap<String, File>();
|
||||
|
||||
public StorageObjectMap(final IEssentials ess, final String folderName)
|
||||
{
|
||||
@@ -51,20 +59,77 @@ public abstract class StorageObjectMap<I> extends CacheLoader<String, I> impleme
|
||||
cache.invalidateAll();
|
||||
for (String string : folder.list())
|
||||
{
|
||||
final File file = new File(folder, string);
|
||||
if (!file.isFile() || !file.canRead())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (string.endsWith(".yml"))
|
||||
{
|
||||
addFileToKeys(string.substring(0, string.length() - 4));
|
||||
}
|
||||
if (string.endsWith(".zip"))
|
||||
{
|
||||
addZipFile(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addFileToKeys(String filename)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
final String name = Util.decodeFileName(filename);
|
||||
keys.add(name.toLowerCase(Locale.ENGLISH));
|
||||
|
||||
}
|
||||
catch (InvalidNameException ex)
|
||||
{
|
||||
ess.getLogger().log(Level.WARNING, "Invalid filename: " + filename, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private final Pattern zipCheck = Pattern.compile("^[a-zA-Z0-9-]+\\.yml$");
|
||||
|
||||
private void addZipFile(File file)
|
||||
{
|
||||
try
|
||||
{
|
||||
ZipFile zipFile = new ZipFile(file);
|
||||
try
|
||||
{
|
||||
if (!string.endsWith(".yml"))
|
||||
Enumeration<ZipArchiveEntry> entries = zipFile.getEntriesInPhysicalOrder();
|
||||
while (entries.hasMoreElements())
|
||||
{
|
||||
continue;
|
||||
ZipArchiveEntry entry = entries.nextElement();
|
||||
String name = entry.getName();
|
||||
if (entry.isDirectory() || entry.getSize() == 0 || !zipCheck.matcher(name).matches())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
try
|
||||
{
|
||||
String shortName = name.substring(0, name.length() - 4);
|
||||
addFileToKeys(shortName);
|
||||
final String decodedName = Util.decodeFileName(shortName).toLowerCase(Locale.ENGLISH);
|
||||
zippedfiles.put(decodedName, file);
|
||||
}
|
||||
catch (InvalidNameException ex)
|
||||
{
|
||||
ess.getLogger().log(Level.WARNING, "Invalid filename " + name + " in " + file.getAbsoluteFile(), ex);
|
||||
}
|
||||
}
|
||||
final String name = Util.decodeFileName(string.substring(0, string.length() - 4));
|
||||
keys.add(name.toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
catch (InvalidNameException ex)
|
||||
finally
|
||||
{
|
||||
ess.getLogger().log(Level.WARNING, "Invalid filename: " + string, ex);
|
||||
zipFile.close();
|
||||
}
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
ess.getLogger().log(Level.WARNING, "Error opening file " + file.getAbsolutePath(), ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -98,13 +163,18 @@ public abstract class StorageObjectMap<I> extends CacheLoader<String, I> impleme
|
||||
@Override
|
||||
public void removeObject(final String name) throws InvalidNameException
|
||||
{
|
||||
keys.remove(name.toLowerCase(Locale.ENGLISH));
|
||||
cache.invalidate(name.toLowerCase(Locale.ENGLISH));
|
||||
String lowerCaseName = name.toLowerCase(Locale.ENGLISH);
|
||||
keys.remove(lowerCaseName);
|
||||
cache.invalidate(lowerCaseName);
|
||||
final File file = getStorageFile(name);
|
||||
if (file.exists())
|
||||
{
|
||||
file.delete();
|
||||
}
|
||||
if (zippedfiles.containsKey(lowerCaseName))
|
||||
{
|
||||
zippedfiles.put(lowerCaseName, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -126,7 +196,14 @@ public abstract class StorageObjectMap<I> extends CacheLoader<String, I> impleme
|
||||
{
|
||||
throw new InvalidNameException(new IOException("Folder does not exists: " + folder));
|
||||
}
|
||||
return new File(folder, Util.sanitizeFileName(name) + ".yml");
|
||||
String sanitizedFilename = Util.sanitizeFileName(name) + ".yml";
|
||||
File file = new File(folder, sanitizedFilename);
|
||||
|
||||
if (!file.exists())
|
||||
{
|
||||
extractFileFromZip(name, sanitizedFilename, file);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -134,4 +211,44 @@ public abstract class StorageObjectMap<I> extends CacheLoader<String, I> impleme
|
||||
{
|
||||
loadAllObjectsAsync();
|
||||
}
|
||||
|
||||
private void extractFileFromZip(final String name, String sanitizedFilename, File file)
|
||||
{
|
||||
String lowerCaseName = name.toLowerCase(Locale.ENGLISH);
|
||||
File zipFile = zippedfiles.get(lowerCaseName);
|
||||
if (zipFile != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
ZipFile zip = new ZipFile(zipFile);
|
||||
try
|
||||
{
|
||||
ZipArchiveEntry entry = zip.getEntry(sanitizedFilename);
|
||||
if (entry != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
IOUtils.copy(zip.getInputStream(entry), new FileOutputStream(file));
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
ess.getLogger().log(Level.WARNING, "Failed to write file: " + file.getAbsolutePath(), ex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ess.getLogger().log(Level.WARNING, "File " + file.getAbsolutePath() + " not found in zip file " + zipFile.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
zip.close();
|
||||
}
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
ess.getLogger().log(Level.WARNING, "File " + file.getAbsolutePath() + " could not be extracted from " + zipFile.getAbsolutePath(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -7,6 +7,7 @@ import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
import junit.framework.TestCase;
|
||||
import net.ess3.api.IPlugin;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.Server;
|
||||
@@ -82,17 +83,8 @@ public abstract class EssentialsTest extends TestCase
|
||||
plugin = mock(IPlugin.class);
|
||||
|
||||
|
||||
File tmp;
|
||||
try
|
||||
{
|
||||
tmp = File.createTempFile("ess", "tmp");
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
tmp.deleteOnExit();
|
||||
when(plugin.getDataFolder()).thenReturn(tmp.getParentFile());
|
||||
File folder = FileUtils.getTempDirectory();
|
||||
when(plugin.getDataFolder()).thenReturn(folder);
|
||||
when(world.getName()).thenReturn("world");
|
||||
|
||||
ess = new Essentials(server, logger, plugin);
|
||||
|
Reference in New Issue
Block a user