[FEATURE] Автоматическое создание ZIP архивов для директорий весом менее 32MB.

This commit is contained in:
Zaxar163 2019-07-03 16:14:49 +03:00
parent 493fbf8f2b
commit e30e749351
28 changed files with 97 additions and 125 deletions

View file

@ -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.");

View file

@ -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) {

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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));
} }
}); });

View file

@ -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) {

View file

@ -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");

View file

@ -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;

View file

@ -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));

View file

@ -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;

View file

@ -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 {

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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) {

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;
}); });

View file

@ -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;

View file

@ -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;

View file

@ -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;
} }
} }

View file

@ -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("..") &&