mirror of
https://github.com/GravitLauncher/Launcher
synced 2025-06-28 12:08:09 +03:00
[FEATURE] Backport vfs system from 6.0.0
This commit is contained in:
parent
6013f75091
commit
110c2a089e
15 changed files with 446 additions and 0 deletions
|
@ -0,0 +1,85 @@
|
||||||
|
package pro.gravit.launcher.base.vfs;
|
||||||
|
|
||||||
|
|
||||||
|
import pro.gravit.launcher.base.vfs.directory.SimpleVfsDirectory;
|
||||||
|
import pro.gravit.launcher.base.vfs.protocol.vfs.VfsURLStreamHandlerProvider;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class Vfs {
|
||||||
|
private final VfsDirectory directory;
|
||||||
|
private static final Map<String, Vfs> map = new HashMap<>();
|
||||||
|
private static final Vfs defaultImpl = new Vfs();
|
||||||
|
static {
|
||||||
|
URL.setURLStreamHandlerFactory(new VfsURLStreamHandlerProvider());
|
||||||
|
register("", defaultImpl);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vfs() {
|
||||||
|
directory = new SimpleVfsDirectory();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vfs(VfsDirectory directory) {
|
||||||
|
this.directory = directory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VfsEntry resolve(Path path) {
|
||||||
|
return directory.resolve(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void put(Path path, VfsEntry entry) {
|
||||||
|
VfsEntry parent = resolve(path.getParent());
|
||||||
|
if(parent instanceof SimpleVfsDirectory dir) {
|
||||||
|
dir.put(path.getFileName().toString(), entry);
|
||||||
|
} else {
|
||||||
|
throw new VfsException(String.format("%s not support add new files", path.getParent()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void register(String name, Vfs vfs) {
|
||||||
|
map.put(name, vfs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vfs getByName(String name) {
|
||||||
|
if(name == null) {
|
||||||
|
return defaultImpl;
|
||||||
|
}
|
||||||
|
return map.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Vfs get() {
|
||||||
|
return defaultImpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputStream getInputStream(Path path) throws IOException {
|
||||||
|
VfsEntry entry = directory.resolve(path);
|
||||||
|
if (entry == null) throw new FileNotFoundException(String.format("File %s not found", path));
|
||||||
|
if(entry instanceof VfsFile file) {
|
||||||
|
return file.getInputStream();
|
||||||
|
}
|
||||||
|
throw new VfsException(String.format("%s is a directory", path.getParent()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public URL getURL(String path) throws IOException {
|
||||||
|
return getURL(Paths.get(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
public URL getURL(Path name) throws IOException {
|
||||||
|
try (InputStream stream = defaultImpl.getInputStream(name)) {
|
||||||
|
return new URI("vfs", null, "/"+name, null).toURL();
|
||||||
|
} catch (UnsupportedOperationException ex) {
|
||||||
|
throw new FileNotFoundException(name.toString());
|
||||||
|
} catch (URISyntaxException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package pro.gravit.launcher.base.vfs;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public abstract class VfsDirectory extends VfsEntry {
|
||||||
|
public abstract VfsEntry find(String name);
|
||||||
|
public VfsEntry resolve(Path path) {
|
||||||
|
if(path == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
VfsDirectory current = this;
|
||||||
|
for(int i=0;i<path.getNameCount();++i) {
|
||||||
|
String s = path.getName(i).toString();
|
||||||
|
VfsEntry entity = current.find(s);
|
||||||
|
if(entity instanceof VfsDirectory newDir) {
|
||||||
|
current = newDir;
|
||||||
|
} else {
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
protected abstract Stream<String> getFiles();
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
package pro.gravit.launcher.base.vfs;
|
||||||
|
|
||||||
|
public class VfsEntry {
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package pro.gravit.launcher.base.vfs;
|
||||||
|
|
||||||
|
public class VfsException extends RuntimeException {
|
||||||
|
public VfsException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public VfsException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VfsException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VfsException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VfsException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||||
|
super(message, cause, enableSuppression, writableStackTrace);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package pro.gravit.launcher.base.vfs;
|
||||||
|
|
||||||
|
|
||||||
|
import pro.gravit.launcher.base.vfs.protocol.vfs.VfsURLConnection;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
|
||||||
|
public abstract class VfsFile extends VfsEntry {
|
||||||
|
public URLConnection openConnection(URL url) {
|
||||||
|
return new VfsURLConnection(url, this);
|
||||||
|
}
|
||||||
|
public abstract InputStream getInputStream();
|
||||||
|
|
||||||
|
public byte[] readAll() throws IOException {
|
||||||
|
try(var input = getInputStream()) {
|
||||||
|
try(var output = new ByteArrayOutputStream()) {
|
||||||
|
input.transferTo(output);
|
||||||
|
return output.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
package pro.gravit.launcher.base.vfs.directory;
|
||||||
|
|
||||||
|
|
||||||
|
import pro.gravit.launcher.base.vfs.VfsDirectory;
|
||||||
|
import pro.gravit.launcher.base.vfs.VfsEntry;
|
||||||
|
import pro.gravit.launcher.base.vfs.VfsException;
|
||||||
|
import pro.gravit.launcher.base.vfs.file.FileVfsFile;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class FileVfsDirectory extends VfsDirectory {
|
||||||
|
private final Path path;
|
||||||
|
|
||||||
|
public FileVfsDirectory(Path path) {
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VfsEntry find(String name) {
|
||||||
|
Path target = path.resolve(name);
|
||||||
|
if(Files.exists(target)) {
|
||||||
|
if(Files.isDirectory(target)) {
|
||||||
|
return new FileVfsDirectory(target);
|
||||||
|
}
|
||||||
|
return new FileVfsFile(target);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("resource")
|
||||||
|
@Override
|
||||||
|
protected Stream<String> getFiles() {
|
||||||
|
try {
|
||||||
|
return Files.list(path).map(Path::getFileName).map(Path::toString);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new VfsException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
package pro.gravit.launcher.base.vfs.directory;
|
||||||
|
|
||||||
|
|
||||||
|
import pro.gravit.launcher.base.vfs.VfsDirectory;
|
||||||
|
import pro.gravit.launcher.base.vfs.VfsEntry;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class SimpleVfsDirectory extends VfsDirectory {
|
||||||
|
private final Map<String, VfsEntry> map = new HashMap<>();
|
||||||
|
@Override
|
||||||
|
public VfsEntry find(String name) {
|
||||||
|
return map.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VfsEntry remove(String name) {
|
||||||
|
return map.remove(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void put(String name, VfsEntry entry) {
|
||||||
|
map.put(name, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Stream<String> getFiles() {
|
||||||
|
return map.keySet().stream();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package pro.gravit.launcher.base.vfs.file;
|
||||||
|
|
||||||
|
|
||||||
|
import pro.gravit.launcher.base.vfs.VfsFile;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
public class BytesVfsFile extends VfsFile {
|
||||||
|
private final byte[] bytes;
|
||||||
|
|
||||||
|
public BytesVfsFile(byte[] bytes) {
|
||||||
|
this.bytes = bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream getInputStream() {
|
||||||
|
return new ByteArrayInputStream(bytes);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package pro.gravit.launcher.base.vfs.file;
|
||||||
|
|
||||||
|
|
||||||
|
import pro.gravit.launcher.base.vfs.VfsFile;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
|
||||||
|
public class DelegateVfsFile extends VfsFile {
|
||||||
|
private final VfsFile vfsFile;
|
||||||
|
|
||||||
|
public DelegateVfsFile(VfsFile vfsFile) {
|
||||||
|
this.vfsFile = vfsFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URLConnection openConnection(URL url) {
|
||||||
|
return vfsFile.openConnection(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream getInputStream() {
|
||||||
|
return vfsFile.getInputStream();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package pro.gravit.launcher.base.vfs.file;
|
||||||
|
|
||||||
|
|
||||||
|
import pro.gravit.launcher.base.vfs.VfsException;
|
||||||
|
import pro.gravit.launcher.base.vfs.VfsFile;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
public class FileVfsFile extends VfsFile {
|
||||||
|
private final File file;
|
||||||
|
|
||||||
|
public FileVfsFile(File file) {
|
||||||
|
this.file = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileVfsFile(Path path) {
|
||||||
|
this.file = path.toFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URLConnection openConnection(URL url) {
|
||||||
|
try {
|
||||||
|
return file.toURI().toURL().openConnection();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new VfsException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream getInputStream() {
|
||||||
|
try {
|
||||||
|
return new FileInputStream(file);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
throw new VfsException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package pro.gravit.launcher.base.vfs.file;
|
||||||
|
|
||||||
|
|
||||||
|
import pro.gravit.launcher.base.vfs.VfsFile;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class InputStreamVfsFile extends VfsFile {
|
||||||
|
private final Supplier<InputStream> streamSupplier;
|
||||||
|
|
||||||
|
public InputStreamVfsFile(Supplier<InputStream> streamSupplier) {
|
||||||
|
this.streamSupplier = streamSupplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream getInputStream() {
|
||||||
|
return streamSupplier.get();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package pro.gravit.launcher.base.vfs.file;
|
||||||
|
|
||||||
|
|
||||||
|
import pro.gravit.launcher.base.vfs.VfsException;
|
||||||
|
import pro.gravit.launcher.base.vfs.VfsFile;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
|
||||||
|
public class UrlVfsFile extends VfsFile {
|
||||||
|
private final URL internalUrl;
|
||||||
|
|
||||||
|
public UrlVfsFile(URL internalUrl) {
|
||||||
|
this.internalUrl = internalUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public URLConnection openConnection(URL url) {
|
||||||
|
try {
|
||||||
|
return internalUrl.openConnection();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new VfsException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream getInputStream() {
|
||||||
|
try {
|
||||||
|
return openConnection(internalUrl).getInputStream();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new VfsException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package pro.gravit.launcher.base.vfs.protocol.vfs;
|
||||||
|
|
||||||
|
|
||||||
|
import pro.gravit.launcher.base.vfs.Vfs;
|
||||||
|
import pro.gravit.launcher.base.vfs.VfsFile;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
import java.net.URLDecoder;
|
||||||
|
import java.net.URLStreamHandler;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
|
public class Handler extends URLStreamHandler {
|
||||||
|
@Override
|
||||||
|
protected URLConnection openConnection(URL url) throws IOException {
|
||||||
|
Vfs enFS = Vfs.getByName(url.getHost());
|
||||||
|
String realPath = URLDecoder.decode(url.getPath(), StandardCharsets.UTF_8);
|
||||||
|
var fileEntry = enFS.resolve(Paths.get(realPath));
|
||||||
|
if(fileEntry == null) throw new FileNotFoundException(url.toString());
|
||||||
|
if(fileEntry instanceof VfsFile file) {
|
||||||
|
return file.openConnection(url);
|
||||||
|
}
|
||||||
|
throw new UnsupportedOperationException(String.format("%s not supported openConnection()", url));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package pro.gravit.launcher.base.vfs.protocol.vfs;
|
||||||
|
|
||||||
|
|
||||||
|
import pro.gravit.launcher.base.vfs.VfsFile;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
|
||||||
|
public class VfsURLConnection extends URLConnection {
|
||||||
|
private final VfsFile fileEntry;
|
||||||
|
public VfsURLConnection(URL url, VfsFile fileEntry) {
|
||||||
|
super(url);
|
||||||
|
this.fileEntry = fileEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void connect() throws IOException {
|
||||||
|
// NOP
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InputStream getInputStream() throws IOException {
|
||||||
|
return fileEntry.getInputStream();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package pro.gravit.launcher.base.vfs.protocol.vfs;
|
||||||
|
|
||||||
|
import java.net.URLStreamHandler;
|
||||||
|
import java.net.spi.URLStreamHandlerProvider;
|
||||||
|
|
||||||
|
public class VfsURLStreamHandlerProvider extends URLStreamHandlerProvider {
|
||||||
|
@Override
|
||||||
|
public URLStreamHandler createURLStreamHandler(String s) {
|
||||||
|
if (s.equals("vfs")) {
|
||||||
|
return new Handler();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue