mirror of
https://github.com/GravitLauncher/Launcher
synced 2025-05-12 20:16:34 +03:00
[FEATURE] Автоматическое создание ZIP архивов для директорий весом менее 32MB.
This commit is contained in:
parent
493fbf8f2b
commit
e30e749351
28 changed files with 97 additions and 125 deletions
|
@ -31,12 +31,14 @@
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.zip.CRC32;
|
import java.util.zip.CRC32;
|
||||||
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
import io.netty.handler.logging.LogLevel;
|
import io.netty.handler.logging.LogLevel;
|
||||||
import pro.gravit.launcher.Launcher;
|
import pro.gravit.launcher.Launcher;
|
||||||
import pro.gravit.launcher.LauncherConfig;
|
import pro.gravit.launcher.LauncherConfig;
|
||||||
import pro.gravit.launcher.NeedGarbageCollection;
|
import pro.gravit.launcher.NeedGarbageCollection;
|
||||||
import pro.gravit.launcher.hasher.HashedDir;
|
import pro.gravit.launcher.hasher.HashedDir;
|
||||||
|
import pro.gravit.launcher.hasher.HashedEntry;
|
||||||
import pro.gravit.launcher.hwid.HWIDProvider;
|
import pro.gravit.launcher.hwid.HWIDProvider;
|
||||||
import pro.gravit.launcher.managers.ConfigManager;
|
import pro.gravit.launcher.managers.ConfigManager;
|
||||||
import pro.gravit.launcher.managers.GarbageManager;
|
import pro.gravit.launcher.managers.GarbageManager;
|
||||||
|
@ -65,7 +67,6 @@
|
||||||
import pro.gravit.launchserver.components.Component;
|
import pro.gravit.launchserver.components.Component;
|
||||||
import pro.gravit.launchserver.components.RegLimiterComponent;
|
import pro.gravit.launchserver.components.RegLimiterComponent;
|
||||||
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
|
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
|
||||||
import pro.gravit.launchserver.dao.UserService;
|
|
||||||
import pro.gravit.launchserver.dao.provider.DaoProvider;
|
import pro.gravit.launchserver.dao.provider.DaoProvider;
|
||||||
import pro.gravit.launchserver.manangers.*;
|
import pro.gravit.launchserver.manangers.*;
|
||||||
import pro.gravit.launchserver.manangers.hook.AuthHookManager;
|
import pro.gravit.launchserver.manangers.hook.AuthHookManager;
|
||||||
|
@ -457,6 +458,8 @@ public static void main(String... args) throws Throwable {
|
||||||
|
|
||||||
public final Timer taskPool;
|
public final Timer taskPool;
|
||||||
|
|
||||||
|
public final Path optimizedUpdatesDir;
|
||||||
|
|
||||||
public static Class<? extends LauncherBinary> defaultLauncherEXEBinaryClass = null;
|
public static Class<? extends LauncherBinary> defaultLauncherEXEBinaryClass = null;
|
||||||
|
|
||||||
public LaunchServer(Path dir, boolean testEnv, String[] args) throws IOException, InvalidKeySpecException {
|
public LaunchServer(Path dir, boolean testEnv, String[] args) throws IOException, InvalidKeySpecException {
|
||||||
|
@ -485,6 +488,7 @@ public LaunchServer(Path dir, boolean testEnv, String[] args) throws IOException
|
||||||
publicKeyFile = dir.resolve("public.key");
|
publicKeyFile = dir.resolve("public.key");
|
||||||
privateKeyFile = dir.resolve("private.key");
|
privateKeyFile = dir.resolve("private.key");
|
||||||
updatesDir = dir.resolve("updates");
|
updatesDir = dir.resolve("updates");
|
||||||
|
optimizedUpdatesDir = dir.resolve("optimized_updates");
|
||||||
profilesDir = dir.resolve("profiles");
|
profilesDir = dir.resolve("profiles");
|
||||||
|
|
||||||
//Registration handlers and providers
|
//Registration handlers and providers
|
||||||
|
@ -634,6 +638,9 @@ public LaunchServer(Path dir, boolean testEnv, String[] args) throws IOException
|
||||||
// Sync updates dir
|
// Sync updates dir
|
||||||
if (!IOHelper.isDir(updatesDir))
|
if (!IOHelper.isDir(updatesDir))
|
||||||
Files.createDirectory(updatesDir);
|
Files.createDirectory(updatesDir);
|
||||||
|
if (!IOHelper.isDir(optimizedUpdatesDir))
|
||||||
|
Files.createDirectory(optimizedUpdatesDir);
|
||||||
|
updatesDirMap = null;
|
||||||
syncUpdatesDir(null);
|
syncUpdatesDir(null);
|
||||||
|
|
||||||
// Sync profiles dir
|
// Sync profiles dir
|
||||||
|
@ -872,6 +879,7 @@ public void syncProfilesDir() throws IOException {
|
||||||
|
|
||||||
public void syncUpdatesDir(Collection<String> dirs) throws IOException {
|
public void syncUpdatesDir(Collection<String> dirs) throws IOException {
|
||||||
LogHelper.info("Syncing updates dir");
|
LogHelper.info("Syncing updates dir");
|
||||||
|
boolean start = updatesDirMap == null;
|
||||||
Map<String, SignedObjectHolder<HashedDir>> newUpdatesDirMap = new HashMap<>(16);
|
Map<String, SignedObjectHolder<HashedDir>> newUpdatesDirMap = new HashMap<>(16);
|
||||||
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(updatesDir)) {
|
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(updatesDir)) {
|
||||||
for (final Path updateDir : dirStream) {
|
for (final Path updateDir : dirStream) {
|
||||||
|
@ -894,17 +902,43 @@ public void syncUpdatesDir(Collection<String> dirs) throws IOException {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sync and sign update dir
|
// Sync and sign update dir
|
||||||
LogHelper.info("Syncing '%s' update dir", name);
|
LogHelper.info("Syncing '%s' update dir", name);
|
||||||
HashedDir updateHDir = new HashedDir(updateDir, null, true, true);
|
HashedDir updateHDir = new HashedDir(updateDir, null, true, true);
|
||||||
|
if (!start) processUpdate(updateDir, updateHDir, name);
|
||||||
newUpdatesDirMap.put(name, new SignedObjectHolder<>(updateHDir, privateKey));
|
newUpdatesDirMap.put(name, new SignedObjectHolder<>(updateHDir, privateKey));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updatesDirMap = Collections.unmodifiableMap(newUpdatesDirMap);
|
updatesDirMap = Collections.unmodifiableMap(newUpdatesDirMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void restart() {
|
private void processUpdate(Path updateDir, HashedDir updateHDir, String name) throws IOException {
|
||||||
|
updateHDir.walk(IOHelper.CROSS_SEPARATOR, (path, filename, entry) -> {
|
||||||
|
if (entry.getType().equals(HashedEntry.Type.DIR)) {
|
||||||
|
if (entry.size() < IOHelper.MB32) {
|
||||||
|
Path p = updateDir.resolve(path);
|
||||||
|
Path out = optimizedUpdatesDir.resolve(name).resolve(path);
|
||||||
|
try (ZipOutputStream compressed = new ZipOutputStream(IOHelper.newOutput(out))) {
|
||||||
|
IOHelper.walk(p, new SimpleFileVisitor<Path>() {
|
||||||
|
@Override
|
||||||
|
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||||
|
compressed.putNextEntry(IOHelper.newZipEntry(
|
||||||
|
p.relativize(file).toString()
|
||||||
|
.replace(IOHelper.PLATFORM_SEPARATOR, IOHelper.CROSS_SEPARATOR)));
|
||||||
|
IOHelper.transfer(file, compressed);
|
||||||
|
return super.visitFile(file, attrs);
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
return HashedDir.WalkAction.SKIP_DIR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return HashedDir.WalkAction.CONTINUE;
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void restart() {
|
||||||
ProcessBuilder builder = new ProcessBuilder();
|
ProcessBuilder builder = new ProcessBuilder();
|
||||||
if (config.startScript != null) builder.command(Collections.singletonList(config.startScript));
|
if (config.startScript != null) builder.command(Collections.singletonList(config.startScript));
|
||||||
else throw new IllegalArgumentException("Please create start script and link it as startScript in config.");
|
else throw new IllegalArgumentException("Please create start script and link it as startScript in config.");
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package pro.gravit.launchserver.command.basic;
|
package pro.gravit.launchserver.command.basic;
|
||||||
|
|
||||||
import org.bouncycastle.cert.X509CertificateHolder;
|
import org.bouncycastle.cert.X509CertificateHolder;
|
||||||
import pro.gravit.launcher.events.PingEvent;
|
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
import pro.gravit.launchserver.command.Command;
|
import pro.gravit.launchserver.command.Command;
|
||||||
import pro.gravit.launchserver.socket.handlers.NettyServerSocketHandler;
|
import pro.gravit.launchserver.socket.handlers.NettyServerSocketHandler;
|
||||||
|
@ -9,7 +8,6 @@
|
||||||
|
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.security.KeyPairGenerator;
|
|
||||||
|
|
||||||
public class TestCommand extends Command {
|
public class TestCommand extends Command {
|
||||||
public TestCommand(LaunchServer server) {
|
public TestCommand(LaunchServer server) {
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
|
||||||
|
|
||||||
public class UserService {
|
public class UserService {
|
||||||
|
|
||||||
private final UserDAO usersDao;
|
private final UserDAO usersDao;
|
||||||
|
|
|
@ -1,22 +1,16 @@
|
||||||
package pro.gravit.launchserver.manangers;
|
package pro.gravit.launchserver.manangers;
|
||||||
|
|
||||||
|
|
||||||
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
|
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
|
||||||
import org.bouncycastle.asn1.x500.X500Name;
|
import org.bouncycastle.asn1.x500.X500Name;
|
||||||
import org.bouncycastle.asn1.x500.X500NameBuilder;
|
import org.bouncycastle.asn1.x500.X500NameBuilder;
|
||||||
import org.bouncycastle.asn1.x500.style.BCStyle;
|
import org.bouncycastle.asn1.x500.style.BCStyle;
|
||||||
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
|
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
|
||||||
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
|
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
|
||||||
import org.bouncycastle.cert.CertIOException;
|
|
||||||
import org.bouncycastle.cert.X509CertificateHolder;
|
import org.bouncycastle.cert.X509CertificateHolder;
|
||||||
import org.bouncycastle.cert.X509v3CertificateBuilder;
|
import org.bouncycastle.cert.X509v3CertificateBuilder;
|
||||||
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
|
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
|
||||||
import org.bouncycastle.crypto.params.ECKeyParameters;
|
|
||||||
import org.bouncycastle.crypto.util.PrivateKeyFactory;
|
import org.bouncycastle.crypto.util.PrivateKeyFactory;
|
||||||
import org.bouncycastle.crypto.util.PrivateKeyInfoFactory;
|
import org.bouncycastle.crypto.util.PrivateKeyInfoFactory;
|
||||||
import org.bouncycastle.jce.ECNamedCurveTable;
|
|
||||||
import org.bouncycastle.jce.spec.ECParameterSpec;
|
|
||||||
import org.bouncycastle.openssl.PEMWriter;
|
|
||||||
import org.bouncycastle.operator.ContentSigner;
|
import org.bouncycastle.operator.ContentSigner;
|
||||||
import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
|
import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
|
||||||
import org.bouncycastle.operator.OperatorCreationException;
|
import org.bouncycastle.operator.OperatorCreationException;
|
||||||
|
@ -27,12 +21,10 @@
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
import pro.gravit.utils.helper.SecurityHelper;
|
import pro.gravit.utils.helper.SecurityHelper;
|
||||||
|
|
||||||
import java.io.FileWriter;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.security.*;
|
import java.security.*;
|
||||||
import java.security.cert.CertificateException;
|
|
||||||
import java.security.spec.ECGenParameterSpec;
|
import java.security.spec.ECGenParameterSpec;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
|
|
@ -2,14 +2,11 @@
|
||||||
|
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
|
|
||||||
import pro.gravit.launcher.hasher.HashedEntry;
|
|
||||||
import pro.gravit.launcher.hasher.HashedEntryAdapter;
|
|
||||||
import pro.gravit.launcher.hwid.HWID;
|
import pro.gravit.launcher.hwid.HWID;
|
||||||
import pro.gravit.launcher.hwid.HWIDProvider;
|
import pro.gravit.launcher.hwid.HWIDProvider;
|
||||||
import pro.gravit.launcher.managers.GsonManager;
|
import pro.gravit.launcher.managers.GsonManager;
|
||||||
import pro.gravit.launcher.request.JsonResultSerializeAdapter;
|
import pro.gravit.launcher.request.JsonResultSerializeAdapter;
|
||||||
import pro.gravit.launcher.request.WebSocketEvent;
|
import pro.gravit.launcher.request.WebSocketEvent;
|
||||||
import pro.gravit.launcher.request.websockets.ClientWebSocketService;
|
|
||||||
import pro.gravit.launchserver.auth.handler.AuthHandler;
|
import pro.gravit.launchserver.auth.handler.AuthHandler;
|
||||||
import pro.gravit.launchserver.auth.hwid.HWIDHandler;
|
import pro.gravit.launchserver.auth.hwid.HWIDHandler;
|
||||||
import pro.gravit.launchserver.auth.permissions.PermissionsHandler;
|
import pro.gravit.launchserver.auth.permissions.PermissionsHandler;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package pro.gravit.launchserver.socket;
|
package pro.gravit.launchserver.socket;
|
||||||
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import io.netty.bootstrap.ServerBootstrap;
|
import io.netty.bootstrap.ServerBootstrap;
|
||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.ChannelFuture;
|
||||||
|
@ -63,7 +64,7 @@ public void initChannel(SocketChannel ch) {
|
||||||
pipeline.addLast(new WebSocketServerCompressionHandler());
|
pipeline.addLast(new WebSocketServerCompressionHandler());
|
||||||
pipeline.addLast(new WebSocketServerProtocolHandler(WEBSOCKET_PATH, null, true));
|
pipeline.addLast(new WebSocketServerProtocolHandler(WEBSOCKET_PATH, null, true));
|
||||||
if (server.config.netty.fileServerEnabled)
|
if (server.config.netty.fileServerEnabled)
|
||||||
pipeline.addLast(new FileServerHandler(server.updatesDir, true));
|
pipeline.addLast(new FileServerHandler(Arrays.asList(server.updatesDir, server.optimizedUpdatesDir)));
|
||||||
pipeline.addLast(new WebSocketFrameHandler(context, server, service));
|
pipeline.addLast(new WebSocketFrameHandler(context, server, service));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -58,7 +58,8 @@ public WebSocketService(ChannelGroup channels, LaunchServer server) {
|
||||||
private static final HashMap<String, Class> responses = new HashMap<>();
|
private static final HashMap<String, Class> responses = new HashMap<>();
|
||||||
private final Gson gson;
|
private final Gson gson;
|
||||||
|
|
||||||
public void process(ChannelHandlerContext ctx, TextWebSocketFrame frame, Client client, String ip) {
|
@SuppressWarnings("unchecked")
|
||||||
|
public void process(ChannelHandlerContext ctx, TextWebSocketFrame frame, Client client, String ip) {
|
||||||
String request = frame.text();
|
String request = frame.text();
|
||||||
WebSocketServerResponse response = gson.fromJson(request, WebSocketServerResponse.class);
|
WebSocketServerResponse response = gson.fromJson(request, WebSocketServerResponse.class);
|
||||||
if (server.config.netty.proxy.enabled) {
|
if (server.config.netty.proxy.enabled) {
|
||||||
|
|
|
@ -23,9 +23,9 @@
|
||||||
import pro.gravit.launchserver.socket.LauncherNettyServer;
|
import pro.gravit.launchserver.socket.LauncherNettyServer;
|
||||||
import pro.gravit.utils.helper.LogHelper;
|
import pro.gravit.utils.helper.LogHelper;
|
||||||
|
|
||||||
@SuppressWarnings({"unused", "rawtypes"})
|
@SuppressWarnings("unused")
|
||||||
public final class NettyServerSocketHandler implements Runnable, AutoCloseable {
|
public final class NettyServerSocketHandler implements Runnable, AutoCloseable {
|
||||||
private SSLServerSocketFactory ssf;
|
private SSLServerSocketFactory ssf;
|
||||||
|
|
||||||
public volatile boolean logConnections = Boolean.getBoolean("launcher.logConnections");
|
public volatile boolean logConnections = Boolean.getBoolean("launcher.logConnections");
|
||||||
|
|
||||||
|
|
|
@ -2,22 +2,17 @@
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import com.google.gson.GsonBuilder;
|
|
||||||
|
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.SimpleChannelInboundHandler;
|
import io.netty.channel.SimpleChannelInboundHandler;
|
||||||
import io.netty.channel.group.DefaultChannelGroup;
|
|
||||||
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
|
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
|
||||||
import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
|
import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
|
||||||
import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
|
import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
|
||||||
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
|
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
|
||||||
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
|
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
|
||||||
import io.netty.util.concurrent.GlobalEventExecutor;
|
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
import pro.gravit.launchserver.socket.Client;
|
import pro.gravit.launchserver.socket.Client;
|
||||||
import pro.gravit.launchserver.socket.NettyConnectContext;
|
import pro.gravit.launchserver.socket.NettyConnectContext;
|
||||||
import pro.gravit.launchserver.socket.WebSocketService;
|
import pro.gravit.launchserver.socket.WebSocketService;
|
||||||
import pro.gravit.utils.helper.CommonHelper;
|
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
import pro.gravit.utils.helper.LogHelper;
|
import pro.gravit.utils.helper.LogHelper;
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
import static io.netty.handler.codec.http.HttpMethod.GET;
|
import static io.netty.handler.codec.http.HttpMethod.GET;
|
||||||
import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
|
import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
|
||||||
import static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN;
|
import static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN;
|
||||||
import static io.netty.handler.codec.http.HttpResponseStatus.FOUND;
|
|
||||||
import static io.netty.handler.codec.http.HttpResponseStatus.INTERNAL_SERVER_ERROR;
|
import static io.netty.handler.codec.http.HttpResponseStatus.INTERNAL_SERVER_ERROR;
|
||||||
import static io.netty.handler.codec.http.HttpResponseStatus.METHOD_NOT_ALLOWED;
|
import static io.netty.handler.codec.http.HttpResponseStatus.METHOD_NOT_ALLOWED;
|
||||||
import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND;
|
import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND;
|
||||||
|
@ -22,13 +21,13 @@
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.GregorianCalendar;
|
import java.util.GregorianCalendar;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import javax.activation.MimetypesFileTypeMap;
|
import javax.activation.MimetypesFileTypeMap;
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.ChannelFuture;
|
||||||
import io.netty.channel.ChannelFutureListener;
|
import io.netty.channel.ChannelFutureListener;
|
||||||
|
@ -48,6 +47,8 @@
|
||||||
import io.netty.handler.codec.http.LastHttpContent;
|
import io.netty.handler.codec.http.LastHttpContent;
|
||||||
import io.netty.handler.stream.ChunkedFile;
|
import io.netty.handler.stream.ChunkedFile;
|
||||||
import io.netty.util.CharsetUtil;
|
import io.netty.util.CharsetUtil;
|
||||||
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
|
import pro.gravit.utils.helper.LogHelper;
|
||||||
|
|
||||||
public class FileServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
|
public class FileServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
|
||||||
|
|
||||||
|
@ -56,12 +57,10 @@ public class FileServerHandler extends SimpleChannelInboundHandler<FullHttpReque
|
||||||
public static final String READ = "r";
|
public static final String READ = "r";
|
||||||
public static final int HTTP_CACHE_SECONDS = 60;
|
public static final int HTTP_CACHE_SECONDS = 60;
|
||||||
private static final boolean OLD_ALGO = Boolean.parseBoolean(System.getProperty("launcher.fileserver.oldalgo", "true"));
|
private static final boolean OLD_ALGO = Boolean.parseBoolean(System.getProperty("launcher.fileserver.oldalgo", "true"));
|
||||||
private final Path base;
|
private final List<Path> base;
|
||||||
private final boolean fullOut;
|
|
||||||
|
|
||||||
public FileServerHandler(Path base, boolean fullOut) {
|
public FileServerHandler(List<Path> base) {
|
||||||
this.base = base;
|
this.base = base;
|
||||||
this.fullOut = fullOut;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -83,13 +82,13 @@ public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) thr
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
File file = base.resolve(path).toFile();
|
Optional<File> fileO = base.stream().map(t -> t.resolve(path)).filter(t -> IOHelper.isFile(t) && !IOHelper.isHidden(t)).map(t -> t.toFile()).findFirst();
|
||||||
if (file.isHidden() || !file.exists()) {
|
if (!fileO.isPresent()) {
|
||||||
sendError(ctx, NOT_FOUND);
|
sendError(ctx, NOT_FOUND);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
File file = fileO.get();
|
||||||
if (file.isDirectory()) {
|
/*if (file.isDirectory()) {
|
||||||
if (fullOut) {
|
if (fullOut) {
|
||||||
if (uri.endsWith("/")) {
|
if (uri.endsWith("/")) {
|
||||||
sendListing(ctx, file, uri);
|
sendListing(ctx, file, uri);
|
||||||
|
@ -98,12 +97,12 @@ public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) thr
|
||||||
}
|
}
|
||||||
} else sendError(ctx, NOT_FOUND); // can not handle dirs
|
} else sendError(ctx, NOT_FOUND); // can not handle dirs
|
||||||
return;
|
return;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
if (!file.isFile()) {
|
/*if (!file.isFile()) {
|
||||||
sendError(ctx, FORBIDDEN);
|
sendError(ctx, FORBIDDEN);
|
||||||
return;
|
return;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
// Cache Validation
|
// Cache Validation
|
||||||
String ifModifiedSince = request.headers().get(HttpHeaderNames.IF_MODIFIED_SINCE);
|
String ifModifiedSince = request.headers().get(HttpHeaderNames.IF_MODIFIED_SINCE);
|
||||||
|
@ -166,14 +165,12 @@ public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) thr
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||||
cause.printStackTrace();
|
LogHelper.error(cause);
|
||||||
if (ctx.channel().isActive()) {
|
if (ctx.channel().isActive()) {
|
||||||
sendError(ctx, INTERNAL_SERVER_ERROR);
|
sendError(ctx, INTERNAL_SERVER_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Pattern INSECURE_URI = Pattern.compile(".*[<>&\"].*");
|
|
||||||
|
|
||||||
private static String sanitizeUri(String uri) {
|
private static String sanitizeUri(String uri) {
|
||||||
// Decode the path.
|
// Decode the path.
|
||||||
try {
|
try {
|
||||||
|
@ -192,60 +189,6 @@ private static String sanitizeUri(String uri) {
|
||||||
return Paths.get(uri).normalize().toString().substring(1);
|
return Paths.get(uri).normalize().toString().substring(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Pattern ALLOWED_FILE_NAME = Pattern.compile("[^-\\._]?[^<>&\\\"]*");
|
|
||||||
|
|
||||||
private static void sendListing(ChannelHandlerContext ctx, File dir, String dirPath) {
|
|
||||||
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK);
|
|
||||||
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html; charset=UTF-8");
|
|
||||||
|
|
||||||
StringBuilder buf = new StringBuilder()
|
|
||||||
.append("<!DOCTYPE html>\r\n")
|
|
||||||
.append("<html><head><meta charset='utf-8' /><title>")
|
|
||||||
.append("Listing of: ")
|
|
||||||
.append(dirPath)
|
|
||||||
.append("</title></head><body>\r\n")
|
|
||||||
|
|
||||||
.append("<h3>Listing of: ")
|
|
||||||
.append(dirPath)
|
|
||||||
.append("</h3>\r\n")
|
|
||||||
|
|
||||||
.append("<ul>")
|
|
||||||
.append("<li><a href=\"../\">..</a></li>\r\n");
|
|
||||||
|
|
||||||
for (File f : dir.listFiles()) {
|
|
||||||
if (f.isHidden() || !f.canRead()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
String name = f.getName();
|
|
||||||
if (!ALLOWED_FILE_NAME.matcher(name).matches()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.append("<li><a href=\"")
|
|
||||||
.append(name)
|
|
||||||
.append("\">")
|
|
||||||
.append(name)
|
|
||||||
.append("</a></li>\r\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.append("</ul></body></html>\r\n");
|
|
||||||
ByteBuf buffer = Unpooled.copiedBuffer(buf, CharsetUtil.UTF_8);
|
|
||||||
response.content().writeBytes(buffer);
|
|
||||||
buffer.release();
|
|
||||||
|
|
||||||
// Close the connection as soon as the error message is sent.
|
|
||||||
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void sendRedirect(ChannelHandlerContext ctx, String newUri) {
|
|
||||||
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, FOUND);
|
|
||||||
response.headers().set(HttpHeaderNames.LOCATION, newUri);
|
|
||||||
|
|
||||||
// Close the connection as soon as the error message is sent.
|
|
||||||
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) {
|
private static void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) {
|
||||||
FullHttpResponse response = new DefaultFullHttpResponse(
|
FullHttpResponse response = new DefaultFullHttpResponse(
|
||||||
HTTP_1_1, status, Unpooled.copiedBuffer("Failure: " + status + "\r\n", CharsetUtil.UTF_8));
|
HTTP_1_1, status, Unpooled.copiedBuffer("Failure: " + status + "\r\n", CharsetUtil.UTF_8));
|
||||||
|
|
|
@ -36,10 +36,17 @@ public interface DownloadTotalCallback {
|
||||||
public static class DownloadTask {
|
public static class DownloadTask {
|
||||||
public String apply;
|
public String apply;
|
||||||
public long size;
|
public long size;
|
||||||
|
public boolean isZip;
|
||||||
|
|
||||||
public DownloadTask(String apply, long size) {
|
public DownloadTask(String apply, long size) {
|
||||||
this.apply = apply;
|
this.apply = apply;
|
||||||
this.size = size;
|
this.size = size;
|
||||||
|
isZip = false;
|
||||||
|
}
|
||||||
|
public DownloadTask(String apply, long size, boolean isZip) {
|
||||||
|
this.apply = apply;
|
||||||
|
this.size = size;
|
||||||
|
this.isZip = isZip;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +66,7 @@ public void download(String base, List<DownloadTask> applies, Path dstDirFile, D
|
||||||
get.reset();
|
get.reset();
|
||||||
get.setURI(u);
|
get.setURI(u);
|
||||||
}
|
}
|
||||||
httpclient.execute(get, new FileDownloadResponseHandler(targetPath, apply, callback, totalCallback, false));
|
httpclient.execute(get, new FileDownloadResponseHandler(targetPath, apply, callback, totalCallback));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,12 +125,12 @@ public FileDownloadResponseHandler(Path target) {
|
||||||
totalCallback = null;
|
totalCallback = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FileDownloadResponseHandler(Path target, DownloadTask task, DownloadCallback callback, DownloadTotalCallback totalCallback, boolean zip) {
|
public FileDownloadResponseHandler(Path target, DownloadTask task, DownloadCallback callback, DownloadTotalCallback totalCallback) {
|
||||||
this.target = target;
|
this.target = target;
|
||||||
this.task = task;
|
this.task = task;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
this.totalCallback = totalCallback;
|
this.totalCallback = totalCallback;
|
||||||
this.zip = zip;
|
this.zip = task != null ? task.isZip : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FileDownloadResponseHandler(Path target, DownloadCallback callback, DownloadTotalCallback totalCallback, boolean zip) {
|
public FileDownloadResponseHandler(Path target, DownloadCallback callback, DownloadTotalCallback totalCallback, boolean zip) {
|
||||||
|
@ -137,16 +144,6 @@ public FileDownloadResponseHandler(Path target, DownloadCallback callback, Downl
|
||||||
@Override
|
@Override
|
||||||
public Path handleResponse(HttpResponse response) throws IOException {
|
public Path handleResponse(HttpResponse response) throws IOException {
|
||||||
InputStream source = response.getEntity().getContent();
|
InputStream source = response.getEntity().getContent();
|
||||||
int returnCode = response.getStatusLine().getStatusCode();
|
|
||||||
if(returnCode != 200)
|
|
||||||
{
|
|
||||||
throw new IllegalStateException(String.format("Request download file %s return code %d", target.toString(), returnCode));
|
|
||||||
}
|
|
||||||
long contentLength = response.getEntity().getContentLength();
|
|
||||||
if (task != null && contentLength != task.size)
|
|
||||||
{
|
|
||||||
LogHelper.warning("Missing content length: expected %d | found %d", task.size, contentLength);
|
|
||||||
}
|
|
||||||
if (zip) {
|
if (zip) {
|
||||||
try (ZipInputStream input = IOHelper.newZipInput(source)) {
|
try (ZipInputStream input = IOHelper.newZipInput(source)) {
|
||||||
ZipEntry entry = input.getNextEntry();
|
ZipEntry entry = input.getNextEntry();
|
||||||
|
@ -171,13 +168,14 @@ public Path handleResponse(HttpResponse response) throws IOException {
|
||||||
}
|
}
|
||||||
if (callback != null && task != null) {
|
if (callback != null && task != null) {
|
||||||
callback.stateChanged(task.apply, 0, task.size);
|
callback.stateChanged(task.apply, 0, task.size);
|
||||||
transfer(source, this.target, task.apply, task.size, callback, totalCallback);
|
transfer(source, target, task.apply, task.size < 0 ? source.available() : task.size, callback, totalCallback);
|
||||||
} else
|
} else
|
||||||
IOHelper.transfer(source, this.target);
|
IOHelper.transfer(source, IOHelper.newOutput(target));
|
||||||
return this.target;
|
return this.target;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void transfer(InputStream input, Path file, String filename, long size, DownloadCallback callback, DownloadTotalCallback totalCallback) throws IOException {
|
public static void transfer(InputStream input, Path file, String filename, long size, DownloadCallback callback, DownloadTotalCallback totalCallback) throws IOException {
|
||||||
try (OutputStream fileOutput = IOHelper.newOutput(file)) {
|
try (OutputStream fileOutput = IOHelper.newOutput(file)) {
|
||||||
long downloaded = 0L;
|
long downloaded = 0L;
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
//Набор стандартных событий
|
//Набор стандартных событий
|
||||||
public class ControlEvent {
|
public class ControlEvent {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
private static final UUID uuid = UUID.fromString("f1051a64-0cd0-4ed8-8430-d856a196e91f");
|
private static final UUID uuid = UUID.fromString("f1051a64-0cd0-4ed8-8430-d856a196e91f");
|
||||||
|
|
||||||
public enum ControlCommand {
|
public enum ControlCommand {
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
package pro.gravit.launcher.events.request;
|
package pro.gravit.launcher.events.request;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import pro.gravit.launcher.ClientPermissions;
|
import pro.gravit.launcher.ClientPermissions;
|
||||||
import pro.gravit.launcher.LauncherNetworkAPI;
|
import pro.gravit.launcher.LauncherNetworkAPI;
|
||||||
import pro.gravit.launcher.events.RequestEvent;
|
import pro.gravit.launcher.events.RequestEvent;
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
package pro.gravit.launcher.events.request;
|
package pro.gravit.launcher.events.request;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import pro.gravit.launcher.LauncherNetworkAPI;
|
import pro.gravit.launcher.LauncherNetworkAPI;
|
||||||
import pro.gravit.launcher.events.RequestEvent;
|
import pro.gravit.launcher.events.RequestEvent;
|
||||||
import pro.gravit.launcher.profiles.PlayerProfile;
|
import pro.gravit.launcher.profiles.PlayerProfile;
|
||||||
|
|
|
@ -8,7 +8,8 @@
|
||||||
|
|
||||||
|
|
||||||
public class CheckServerRequestEvent extends RequestEvent {
|
public class CheckServerRequestEvent extends RequestEvent {
|
||||||
private static final UUID _uuid = UUID.fromString("8801d07c-51ba-4059-b61d-fe1f1510b28a");
|
@SuppressWarnings("unused")
|
||||||
|
private static final UUID _uuid = UUID.fromString("8801d07c-51ba-4059-b61d-fe1f1510b28a");
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
public UUID uuid;
|
public UUID uuid;
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
|
|
||||||
public class JoinServerRequestEvent extends RequestEvent {
|
public class JoinServerRequestEvent extends RequestEvent {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
private static final UUID uuid = UUID.fromString("2a12e7b5-3f4a-4891-a2f9-ea141c8e1995");
|
private static final UUID uuid = UUID.fromString("2a12e7b5-3f4a-4891-a2f9-ea141c8e1995");
|
||||||
|
|
||||||
public JoinServerRequestEvent(boolean allow) {
|
public JoinServerRequestEvent(boolean allow) {
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
|
|
||||||
public class LauncherRequestEvent extends RequestEvent {
|
public class LauncherRequestEvent extends RequestEvent {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
private static final UUID uuid = UUID.fromString("d54cc12a-4f59-4f23-9b10-f527fdd2e38f");
|
private static final UUID uuid = UUID.fromString("d54cc12a-4f59-4f23-9b10-f527fdd2e38f");
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
public String url;
|
public String url;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
|
|
||||||
public class ProfileByUUIDRequestEvent extends RequestEvent {
|
public class ProfileByUUIDRequestEvent extends RequestEvent {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
private static final UUID uuid = UUID.fromString("b9014cf3-4b95-4d38-8c5f-867f190a18a0");
|
private static final UUID uuid = UUID.fromString("b9014cf3-4b95-4d38-8c5f-867f190a18a0");
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
public String error;
|
public String error;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
|
|
||||||
public class ProfileByUsernameRequestEvent extends RequestEvent {
|
public class ProfileByUsernameRequestEvent extends RequestEvent {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
private static final UUID uuid = UUID.fromString("06204302-ff6b-4779-b97d-541e3bc39aa1");
|
private static final UUID uuid = UUID.fromString("06204302-ff6b-4779-b97d-541e3bc39aa1");
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
public String error;
|
public String error;
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
|
|
||||||
public class ProfilesRequestEvent extends RequestEvent {
|
public class ProfilesRequestEvent extends RequestEvent {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
private static final UUID uuid = UUID.fromString("2f26fbdf-598a-46dd-92fc-1699c0e173b1");
|
private static final UUID uuid = UUID.fromString("2f26fbdf-598a-46dd-92fc-1699c0e173b1");
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
public List<ClientProfile> profiles;
|
public List<ClientProfile> profiles;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
|
|
||||||
public class SetProfileRequestEvent extends RequestEvent {
|
public class SetProfileRequestEvent extends RequestEvent {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
private static final UUID uuid = UUID.fromString("08c0de9e-4364-4152-9066-8354a3a48541");
|
private static final UUID uuid = UUID.fromString("08c0de9e-4364-4152-9066-8354a3a48541");
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
public ClientProfile newProfile;
|
public ClientProfile newProfile;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
|
|
||||||
public class UpdateListRequestEvent extends RequestEvent {
|
public class UpdateListRequestEvent extends RequestEvent {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
private static final UUID uuid = UUID.fromString("5fa836ae-6b61-401c-96ac-d8396f07ec6b");
|
private static final UUID uuid = UUID.fromString("5fa836ae-6b61-401c-96ac-d8396f07ec6b");
|
||||||
@LauncherNetworkAPI
|
@LauncherNetworkAPI
|
||||||
public final HashSet<String> dirs;
|
public final HashSet<String> dirs;
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
import pro.gravit.launcher.LauncherAPI;
|
import pro.gravit.launcher.LauncherAPI;
|
||||||
import pro.gravit.launcher.LauncherNetworkAPI;
|
import pro.gravit.launcher.LauncherNetworkAPI;
|
||||||
import pro.gravit.launcher.events.request.AuthRequestEvent;
|
import pro.gravit.launcher.events.request.AuthRequestEvent;
|
||||||
import pro.gravit.launcher.hwid.OshiHWID;
|
|
||||||
import pro.gravit.launcher.request.Request;
|
import pro.gravit.launcher.request.Request;
|
||||||
import pro.gravit.launcher.request.websockets.WebSocketRequest;
|
import pro.gravit.launcher.request.websockets.WebSocketRequest;
|
||||||
import pro.gravit.utils.helper.VerifyHelper;
|
import pro.gravit.utils.helper.VerifyHelper;
|
||||||
|
|
|
@ -210,6 +210,10 @@ public UpdateRequestEvent requestDo(StandartClientWebSocketService service) thro
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
LogHelper.error(ex);
|
LogHelper.error(ex);
|
||||||
}
|
}
|
||||||
|
if (entry.size() < IOHelper.MB32) {
|
||||||
|
adds.add(new ListDownloader.DownloadTask(path, -1, true));
|
||||||
|
return HashedDir.WalkAction.SKIP_DIR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return HashedDir.WalkAction.CONTINUE;
|
return HashedDir.WalkAction.CONTINUE;
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|
||||||
import javax.net.ssl.SSLException;
|
import javax.net.ssl.SSLException;
|
||||||
|
|
|
@ -7,13 +7,10 @@
|
||||||
|
|
||||||
import javax.net.ssl.SSLException;
|
import javax.net.ssl.SSLException;
|
||||||
|
|
||||||
import com.google.gson.GsonBuilder;
|
|
||||||
|
|
||||||
import pro.gravit.launcher.events.request.ErrorRequestEvent;
|
import pro.gravit.launcher.events.request.ErrorRequestEvent;
|
||||||
import pro.gravit.launcher.request.Request;
|
import pro.gravit.launcher.request.Request;
|
||||||
import pro.gravit.launcher.request.RequestException;
|
import pro.gravit.launcher.request.RequestException;
|
||||||
import pro.gravit.launcher.request.WebSocketEvent;
|
import pro.gravit.launcher.request.WebSocketEvent;
|
||||||
import pro.gravit.utils.helper.CommonHelper;
|
|
||||||
import pro.gravit.utils.helper.JVMHelper;
|
import pro.gravit.utils.helper.JVMHelper;
|
||||||
import pro.gravit.utils.helper.LogHelper;
|
import pro.gravit.utils.helper.LogHelper;
|
||||||
|
|
||||||
|
|
|
@ -350,7 +350,7 @@ public void walk(CharSequence separator, WalkCallback callback) throws IOExcepti
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum WalkAction {
|
public enum WalkAction {
|
||||||
STOP, CONTINUE
|
STOP, SKIP_DIR, CONTINUE
|
||||||
}
|
}
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
|
@ -375,7 +375,9 @@ private WalkAction walk(String append, CharSequence separator, WalkCallback call
|
||||||
else newAppend = append + separator + entry.getKey();
|
else newAppend = append + separator + entry.getKey();
|
||||||
WalkAction a = callback.walked(newAppend, entry.getKey(), e);
|
WalkAction a = callback.walked(newAppend, entry.getKey(), e);
|
||||||
if (a == WalkAction.STOP) return a;
|
if (a == WalkAction.STOP) return a;
|
||||||
a = ((HashedDir) e).walk(newAppend, separator, callback, false);
|
if (a == WalkAction.CONTINUE)
|
||||||
|
a = ((HashedDir) e).walk(newAppend, separator, callback, false);
|
||||||
|
else a = WalkAction.CONTINUE; // skip
|
||||||
if (a == WalkAction.STOP) return a;
|
if (a == WalkAction.STOP) return a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -297,6 +297,15 @@ public static boolean isFile(Path path) {
|
||||||
return Files.isRegularFile(path, LINK_OPTIONS);
|
return Files.isRegularFile(path, LINK_OPTIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@LauncherAPI
|
||||||
|
public static boolean isHidden(Path path) {
|
||||||
|
try {
|
||||||
|
return Files.isHidden(path);
|
||||||
|
} catch (IOException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@LauncherAPI
|
@LauncherAPI
|
||||||
public static boolean isValidFileName(String fileName) {
|
public static boolean isValidFileName(String fileName) {
|
||||||
return !fileName.equals(".") && !fileName.equals("..") &&
|
return !fileName.equals(".") && !fileName.equals("..") &&
|
||||||
|
|
Loading…
Reference in a new issue