package io.vertx.core.file.impl;
import io.vertx.core.impl.Utils;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.PosixFilePermissions;
import java.util.Set;
import java.util.UUID;
class FileCache {
static FileCache setupCache(String fileCacheDir) {
FileCache cache = new FileCache(setupCacheDir(fileCacheDir));
cache.registerShutdownHook();
return cache;
}
static File setupCacheDir(String fileCacheDir) {
if (fileCacheDir.endsWith(File.separator)) {
fileCacheDir = fileCacheDir.substring(0, fileCacheDir.length() - File.separator.length());
}
String cacheDirName = fileCacheDir + "-" + UUID.randomUUID().toString();
File cacheDir = new File(cacheDirName);
try {
if (Utils.isWindows()) {
Files.createDirectories(cacheDir.toPath());
} else {
Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rwx------");
Files.createDirectories(cacheDir.toPath(), PosixFilePermissions.asFileAttribute(perms));
}
} catch (IOException e) {
throw new IllegalStateException("Failed to create cache dir: " + cacheDirName, e);
}
return cacheDir;
}
private Thread shutdownHook;
private File cacheDir;
public FileCache(File cacheDir) {
this.cacheDir = cacheDir;
}
synchronized void registerShutdownHook() {
Thread shutdownHook = new Thread(this::runHook);
this.shutdownHook = shutdownHook;
Runtime.getRuntime().addShutdownHook(shutdownHook);
}
private void runHook() {
synchronized (this) {
if (cacheDir == null) {
return;
}
}
Thread deleteCacheDirThread = new Thread(() -> {
try {
deleteCacheDir();
} catch (IOException ignore) {
}
});
deleteCacheDirThread.start();
try {
deleteCacheDirThread.join(10 * 1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
void close() throws IOException {
final Thread hook;
synchronized (this) {
hook = shutdownHook;
shutdownHook = null;
}
if (hook != null) {
try {
Runtime.getRuntime().removeShutdownHook(hook);
} catch (IllegalStateException ignore) {
}
}
deleteCacheDir();
}
private void deleteCacheDir() throws IOException {
final File dir;
synchronized (this) {
if (cacheDir == null) {
return;
}
dir = cacheDir;
cacheDir = null;
}
if (dir.exists()) {
FileSystemImpl.delete(dir.toPath(), true);
}
}
File getFile(String fileName) {
if (cacheDir == null) {
throw new IllegalStateException("cacheDir is null");
}
return new File(cacheDir, fileName);
}
File cache(String fileName, File resource, boolean overwrite) throws IOException {
File cacheFile = new File(cacheDir, fileName);
boolean isDirectory = resource.isDirectory();
if (!isDirectory) {
cacheFile.getParentFile().mkdirs();
if (!overwrite) {
try {
Files.copy(resource.toPath(), cacheFile.toPath());
} catch (FileAlreadyExistsException ignore) {
}
} else {
Files.copy(resource.toPath(), cacheFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
} else {
cacheFile.mkdirs();
}
return cacheFile;
}
void cacheFile(String fileName, InputStream is, boolean overwrite) throws IOException {
File cacheFile = new File(cacheDir, fileName);
cacheFile.getParentFile().mkdirs();
if (!overwrite) {
try {
Files.copy(is, cacheFile.toPath());
} catch (FileAlreadyExistsException ignore) {
}
} else {
Files.copy(is, cacheFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
}
void cacheDir(String fileName) {
File file = new File(cacheDir, fileName);
file.mkdirs();
}
}