diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index fa9a842f..7b6ba3cc 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -24,7 +24,7 @@ build: - ./gradlew assemble artifacts: paths: - - LaunchServer/build/libs/*.jar + - LaunchServer/build/libs/* - ServerWrapper/build/libs/*.jar expire_in: 1 week diff --git a/LaunchServer/src/main/java/ru/gravit/launchserver/LaunchServer.java b/LaunchServer/src/main/java/ru/gravit/launchserver/LaunchServer.java index 51743f7d..bc13b9d1 100644 --- a/LaunchServer/src/main/java/ru/gravit/launchserver/LaunchServer.java +++ b/LaunchServer/src/main/java/ru/gravit/launchserver/LaunchServer.java @@ -263,9 +263,15 @@ public static class ExeConf { public String txtFileVersion; public String txtProductVersion; } + public static class NettyUpdatesBind + { + public String url; + public boolean zip; + } public class LauncherConf { public String guardType; + public boolean attachLibraryBeforeProGuard; } public class NettyConfig { @@ -276,7 +282,7 @@ public class NettyConfig { public String downloadURL; public String launcherEXEURL; public String address; - public Map bindings = new HashMap<>(); + public Map bindings = new HashMap<>(); public NettyPerformanceConfig performance; public NettyBindAddress[] binds; public LogLevel logLevel = LogLevel.DEBUG; diff --git a/LaunchServer/src/main/java/ru/gravit/launchserver/auth/hwid/MysqlHWIDHandler.java b/LaunchServer/src/main/java/ru/gravit/launchserver/auth/hwid/MysqlHWIDHandler.java index 2f4f037e..9bc6500e 100644 --- a/LaunchServer/src/main/java/ru/gravit/launchserver/auth/hwid/MysqlHWIDHandler.java +++ b/LaunchServer/src/main/java/ru/gravit/launchserver/auth/hwid/MysqlHWIDHandler.java @@ -27,6 +27,7 @@ public class MysqlHWIDHandler extends HWIDHandler { private String hwidFieldHWDiskSerial; private String hwidFieldProcessorID; private String hwidFieldBanned; + private String hwidFieldMAC; private String queryHwids; private String[] paramsHwids; @@ -37,7 +38,7 @@ public class MysqlHWIDHandler extends HWIDHandler { private String banMessage; private boolean compareMode = false; - //Using queryHWID "queryHwids": "SELECT * FROM `users_hwids` WHERE `totalMemory` = ? or `serialNumber` = ? or `HWDiskSerial` = ? or `processorID` = ?" + //Using queryHWID "queryHwids": "SELECT * FROM `users_hwids` WHERE `totalMemory` = ? or `serialNumber` = ? or `HWDiskSerial` = ? or `processorID` = ? or `MACAddr` = ?" private int compare = 50; //При наборе схожести в 50 очков private boolean oneCompareMode = false; @@ -51,6 +52,7 @@ public class MysqlHWIDHandler extends HWIDHandler { `serialNumber` varchar(64) NOT NULL, `HWDiskSerial` varchar(64) NOT NULL, `processorID` varchar(64) NOT NULL, + `MACAddr` varchar(64) NOT NULL, `isBanned` tinyint(1) NOT NULL DEFAULT '0' ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; @@ -90,7 +92,7 @@ public void check0(HWID hwid, String username) throws HWIDException { public void onUpdateInfo(OshiHWID hwid, String username, Connection c) throws HWIDException { try (PreparedStatement a = c.prepareStatement(queryHwids)) { - String[] replaceParams = {"totalMemory", String.valueOf(hwid.totalMemory), "serialNumber", hwid.serialNumber, "HWDiskSerial", hwid.HWDiskSerial, "processorID", hwid.processorID}; + String[] replaceParams = {"totalMemory", String.valueOf(hwid.totalMemory), "serialNumber", hwid.serialNumber, "HWDiskSerial", hwid.HWDiskSerial, "processorID", hwid.processorID, "MAC", hwid.macAddr}; for (int i = 0; i < paramsHwids.length; i++) { a.setString(i + 1, CommonHelper.replace(paramsHwids[i], replaceParams)); } @@ -113,12 +115,13 @@ public void onUpdateInfo(OshiHWID hwid, String username, Connection c) throws HW throw new HWIDException(banMessage); } } else { - ps = c.prepareStatement(String.format("INSERT INTO `%s` (`%s`, `%s`, `%s`, `%s`) VALUES (?, ?, ?, ?);", - tableHwids, hwidFieldTotalMemory, hwidFieldSerialNumber, hwidFieldHWDiskSerial, hwidFieldProcessorID)); + ps = c.prepareStatement(String.format("INSERT INTO `%s` (`%s`, `%s`, `%s`, `%s`, `%s`) VALUES (?, ?, ?, ?, ?);", + tableHwids, hwidFieldTotalMemory, hwidFieldSerialNumber, hwidFieldHWDiskSerial, hwidFieldProcessorID, hwidFieldMAC)); ps.setString(1, String.valueOf(hwid.totalMemory)); ps.setString(2, hwid.serialNumber); ps.setString(3, hwid.HWDiskSerial); ps.setString(4, hwid.processorID); + ps.setString(5, hwid.macAddr); ps.setQueryTimeout(MySQLSourceConfig.TIMEOUT); ps.executeUpdate(); @@ -135,7 +138,7 @@ public void onUpdateInfo(OshiHWID hwid, String username, Connection c) throws HW public void onCheckInfo(OshiHWID hwid, String username, Connection c) throws HWIDException { try (PreparedStatement a = c.prepareStatement(queryHwids)) { - String[] replaceParams = {"totalMemory", String.valueOf(hwid.totalMemory), "serialNumber", hwid.serialNumber, "HWDiskSerial", hwid.HWDiskSerial, "processorID", hwid.processorID}; + String[] replaceParams = {"totalMemory", String.valueOf(hwid.totalMemory), "serialNumber", hwid.serialNumber, "HWDiskSerial", hwid.HWDiskSerial, "processorID", hwid.processorID, "MAC", hwid.macAddr}; for (int i = 0; i < paramsHwids.length; i++) { a.setString(i + 1, CommonHelper.replace(paramsHwids[i], replaceParams)); } @@ -149,7 +152,7 @@ public void onCheckInfo(OshiHWID hwid, String username, Connection c) throws HWI db_hwid.processorID = set.getString(hwidFieldProcessorID); db_hwid.HWDiskSerial = set.getString(hwidFieldHWDiskSerial); db_hwid.totalMemory = Long.valueOf(set.getString(hwidFieldTotalMemory)); - db_hwid.macAddr = ""; + db_hwid.macAddr = set.getString(hwidFieldMAC); LogHelper.dev("Compare HWID: %s vs %s", hwid.getSerializeString(), db_hwid.getSerializeString()); int compare_point = hwid.compare(db_hwid); if (compare_point < compare) continue; @@ -177,7 +180,7 @@ public void setIsBanned(HWID hwid, boolean isBanned) { OshiHWID oshiHWID = (OshiHWID) hwid; try (Connection c = mySQLHolder.getConnection()) { try (PreparedStatement a = c.prepareStatement(queryBan)) { - String[] replaceParamsUpd = {"totalMemory", String.valueOf(oshiHWID.totalMemory), "serialNumber", oshiHWID.serialNumber, "HWDiskSerial", oshiHWID.HWDiskSerial, "processorID", oshiHWID.processorID, "isBanned", isBanned ? "1" : "0"}; + String[] replaceParamsUpd = {"totalMemory", String.valueOf(oshiHWID.totalMemory), "serialNumber", oshiHWID.serialNumber, "HWDiskSerial", oshiHWID.HWDiskSerial, "processorID", oshiHWID.processorID, "MAC", oshiHWID.macAddr, "isBanned", isBanned ? "1" : "0"}; for (int i = 0; i < paramsBan.length; i++) { a.setString(i + 1, CommonHelper.replace(paramsBan[i], replaceParamsUpd)); } @@ -231,6 +234,7 @@ public List getHwid(String username) { oshiHWID.serialNumber = rs.getString(hwidFieldSerialNumber); oshiHWID.HWDiskSerial = rs.getString(hwidFieldHWDiskSerial); oshiHWID.processorID = rs.getString(hwidFieldProcessorID); + oshiHWID.macAddr = rs.getString(hwidFieldMAC); list.add(oshiHWID); } } diff --git a/LaunchServer/src/main/java/ru/gravit/launchserver/binary/JAConfigurator.java b/LaunchServer/src/main/java/ru/gravit/launchserver/binary/JAConfigurator.java index a720d371..f3980d97 100644 --- a/LaunchServer/src/main/java/ru/gravit/launchserver/binary/JAConfigurator.java +++ b/LaunchServer/src/main/java/ru/gravit/launchserver/binary/JAConfigurator.java @@ -83,6 +83,12 @@ public void setSecretKey(String key) { body.append("\";"); } + public void setOemUnlockKey(String key) { + body.append("this.oemUnlockKey = \""); + body.append(key); + body.append("\";"); + } + public void setGuardType(String key) { body.append("this.guardType = \""); body.append(key); diff --git a/LaunchServer/src/main/java/ru/gravit/launchserver/binary/JARLauncherBinary.java b/LaunchServer/src/main/java/ru/gravit/launchserver/binary/JARLauncherBinary.java index 839976f1..5d2ee007 100644 --- a/LaunchServer/src/main/java/ru/gravit/launchserver/binary/JARLauncherBinary.java +++ b/LaunchServer/src/main/java/ru/gravit/launchserver/binary/JARLauncherBinary.java @@ -42,10 +42,11 @@ public JARLauncherBinary(LaunchServer server) throws IOException { public void init() { tasks.add(new PrepareBuildTask(server)); tasks.add(new MainBuildTask(server)); + if(server.config.launcher.attachLibraryBeforeProGuard) tasks.add(new AttachJarsTask(server)); tasks.add(new ProGuardBuildTask(server)); tasks.add(new AdditionalFixesApplyTask(server)); tasks.add(new RadonBuildTask(server)); - tasks.add(new AttachJarsTask(server)); + if(!server.config.launcher.attachLibraryBeforeProGuard) tasks.add(new AttachJarsTask(server)); } @Override diff --git a/LaunchServer/src/main/java/ru/gravit/launchserver/binary/tasks/MainBuildTask.java b/LaunchServer/src/main/java/ru/gravit/launchserver/binary/tasks/MainBuildTask.java index 06d60a01..255dfd59 100644 --- a/LaunchServer/src/main/java/ru/gravit/launchserver/binary/tasks/MainBuildTask.java +++ b/LaunchServer/src/main/java/ru/gravit/launchserver/binary/tasks/MainBuildTask.java @@ -137,6 +137,8 @@ public Path process(Path inputJar) throws IOException { jaConfigurator.setGuardType(server.config.launcher.guardType); jaConfigurator.setWarningMissArchJava(server.config.isWarningMissArchJava); jaConfigurator.setEnv(server.config.env); + if(server.runtime.oemUnlockKey == null) server.runtime.oemUnlockKey = SecurityHelper.randomStringToken(); + jaConfigurator.setOemUnlockKey(server.runtime.oemUnlockKey); server.buildHookManager.registerAllClientModuleClass(jaConfigurator); reader.getCp().add(new JarFile(inputJar.toFile())); server.launcherBinary.coreLibs.forEach(e -> { diff --git a/LaunchServer/src/main/java/ru/gravit/launchserver/config/LaunchServerRuntimeConfig.java b/LaunchServer/src/main/java/ru/gravit/launchserver/config/LaunchServerRuntimeConfig.java index c46ffadf..31e55878 100644 --- a/LaunchServer/src/main/java/ru/gravit/launchserver/config/LaunchServerRuntimeConfig.java +++ b/LaunchServer/src/main/java/ru/gravit/launchserver/config/LaunchServerRuntimeConfig.java @@ -5,6 +5,7 @@ public class LaunchServerRuntimeConfig { public String clientToken; + public String oemUnlockKey; public void verify() { if (clientToken == null) LogHelper.error("[RuntimeConfig] clientToken must not be null"); diff --git a/LaunchServer/src/main/java/ru/gravit/launchserver/websocket/json/update/UpdateResponse.java b/LaunchServer/src/main/java/ru/gravit/launchserver/websocket/json/update/UpdateResponse.java index 34d75c14..b326f1c0 100644 --- a/LaunchServer/src/main/java/ru/gravit/launchserver/websocket/json/update/UpdateResponse.java +++ b/LaunchServer/src/main/java/ru/gravit/launchserver/websocket/json/update/UpdateResponse.java @@ -39,7 +39,13 @@ public void execute(ChannelHandlerContext ctx, Client client) { return; } String url = LaunchServer.server.config.netty.downloadURL.replace("%dirname%", dirName); - if (server.config.netty.bindings.get(dirName) != null) url = server.config.netty.bindings.get(dirName); - service.sendObject(ctx, new UpdateRequestEvent(dir.object, url)); + boolean zip = false; + if (server.config.netty.bindings.get(dirName) != null) + { + LaunchServer.NettyUpdatesBind bind = server.config.netty.bindings.get(dirName); + url = bind.url; + zip = bind.zip; + } + service.sendObject(ctx, new UpdateRequestEvent(dir.object, url, zip)); } } diff --git a/Launcher/runtime/dialog/dialog.js b/Launcher/runtime/dialog/dialog.js index 109112c2..acd7ba4b 100644 --- a/Launcher/runtime/dialog/dialog.js +++ b/Launcher/runtime/dialog/dialog.js @@ -5,7 +5,6 @@ var profilesList = []; var movePoint = null; var pingers = {}; var loginData; -// Variable which contains all types of auth. Appending data at line 255 var authTypes = {}; function initLauncher() { @@ -195,7 +194,6 @@ function goAuth(event) { return; } - // Get auth var auth = authOptions.getSelectionModel().getSelectedItem(); if (auth === null) { return; // No auth selected @@ -220,7 +218,7 @@ function goAuth(event) { } settings.login = login; - doAuth(/*auth, */login, rsaPassword, authTypes[auth]); + doAuth(login, rsaPassword, authTypes[auth]); } /* ======== Console ======== */ @@ -259,17 +257,14 @@ function verifyLauncher(e) { result.list.forEach(function(auth_type, i, arr) { var serverAuth = new com.jfoenix.controls.JFXComboBox(); serverAuth.getStyleClass().add("authOptions"); - // add display name to items and add name with iter to variable authTypes authOptions.getItems().add(auth_type.displayName); authTypes[auth_type.displayName] = auth_type.name; iter++; }); authOptions.getSelectionModel().select(0); var sm = authOptions.getSelectionModel().selectedIndexProperty(); - // add listener to authOptions select sm.addListener(new javafx.beans.value.ChangeListener({ changed: function (observableValue, oldSelection, newSelection) { - // get auth name from authTypes settings.auth = authTypes[authOptions.getSelectionModel().getSelectedItem()]; } })); @@ -423,8 +418,8 @@ var overlay = { dimPane.setVisible(true); dimPane.toFront(); - loginPaneLayout.setEffect(new javafx.scene.effect.GaussianBlur(55)); - serverPaneLayout.setEffect(new javafx.scene.effect.GaussianBlur(55)); + loginPaneLayout.setEffect(new javafx.scene.effect.GaussianBlur(10)); + serverPaneLayout.setEffect(new javafx.scene.effect.GaussianBlur(10)); fade(dimPane, 0.0, 0.0, 1.0, function(event) { dimPane.requestFocus(); dimPane.getChildren().add(newOverlay); diff --git a/Launcher/runtime/dialog/images/downloader/blured.jpg b/Launcher/runtime/dialog/images/downloader/blured.jpg new file mode 100644 index 00000000..b721d11c Binary files /dev/null and b/Launcher/runtime/dialog/images/downloader/blured.jpg differ diff --git a/Launcher/runtime/dialog/overlay/processing/processing.js b/Launcher/runtime/dialog/overlay/processing/processing.js index 568cc2ee..cfff7bc6 100644 --- a/Launcher/runtime/dialog/overlay/processing/processing.js +++ b/Launcher/runtime/dialog/overlay/processing/processing.js @@ -17,7 +17,6 @@ var processing = { setError: function(e) { LogHelper.error(e); processing.description.textProperty().unbind(); - //processing.errorImage.setImage(processing.errorImage); processing.description.getStyleClass().add("error"); processing.description.setText(e.toString()); }, @@ -48,8 +47,6 @@ function offlineAuthRequest(login) { Request.requestError("Имя пользователя некорректно"); return; } - - // Return offline profile and random access token return { pp: PlayerProfile.newOfflineProfile(login), accessToken: SecurityHelper.randomStringToken() @@ -57,18 +54,15 @@ function offlineAuthRequest(login) { }; } -/* Export functions */ function makeLauncherRequest(callback) { var task = settings.offline ? newTask(FunctionalBridge.offlineLauncherRequest) : newRequestTask(new LauncherRequest()); - // Set task properties and start processing.setTaskProperties(task, callback, function() { if (settings.offline) { return; } - // Repeat request, but in offline mode settings.offline = true; overlay.swap(2500, processing.overlay, function() makeLauncherRequest(callback)); }, false); @@ -78,13 +72,11 @@ function makeLauncherRequest(callback) { function makeProfilesRequest(callback) { var task = newRequestTask(new ProfilesRequest()); - // Set task properties and start processing.setTaskProperties(task, callback, function() { if (settings.offline) { return; } - // Repeat request, but in offline mode settings.offline = true; overlay.swap(2500, processing.overlay, function() makeProfilesRequest(callback)); }, false); @@ -94,7 +86,6 @@ function makeProfilesRequest(callback) { function makeAuthAvailabilityRequest(callback) { var task = newRequestTask(new GetAvailabilityAuthRequest()); - // Set task properties and start processing.setTaskProperties(task, callback, function() { if (settings.offline) { return; @@ -110,7 +101,6 @@ function makeAuthAvailabilityRequest(callback) { function makeSetProfileRequest(profile, callback) { var task = newRequestTask(new SetProfileRequest(profile)); - // Set task properties and start processing.setTaskProperties(task, callback, function() { if (settings.offline) { return; diff --git a/Launcher/runtime/dialog/overlay/update/update.css b/Launcher/runtime/dialog/overlay/update/update.css index dff8e234..4035391a 100644 --- a/Launcher/runtime/dialog/overlay/update/update.css +++ b/Launcher/runtime/dialog/overlay/update/update.css @@ -3,7 +3,7 @@ #overlay { -fx-background-color: transparent; -fx-background-size: cover; - -fx-background-image: url('../../images/background.jpg'); + -fx-background-image: url('../../images/downloader/blured.jpg'); } #overlay > #utitle { @@ -20,7 +20,7 @@ #overlay > #description.error { } .downloadPane { - -fx-background-color: rgba(0, 0, 0, 0.3); + -fx-background-color: rgba(0, 0, 0, 0.2); } /* Progress bar */ diff --git a/Launcher/runtime/dialog/overlay/update/update.fxml b/Launcher/runtime/dialog/overlay/update/update.fxml index 30ffcdb0..c44e8bc9 100644 --- a/Launcher/runtime/dialog/overlay/update/update.fxml +++ b/Launcher/runtime/dialog/overlay/update/update.fxml @@ -8,29 +8,27 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/Launcher/runtime/dialog/overlay/update/update.js b/Launcher/runtime/dialog/overlay/update/update.js index da013488..4996f7f8 100644 --- a/Launcher/runtime/dialog/overlay/update/update.js +++ b/Launcher/runtime/dialog/overlay/update/update.js @@ -4,6 +4,9 @@ var update = { initOverlay: function() { update.overlay = loadFXML("dialog/overlay/update/update.fxml"); + //var updateLayout = update.overlay.lookup("#overlay"); + //serverPaneLayout = updateLayout; + update.title = update.overlay.lookup("#utitle"); update.description = update.overlay.lookup("#description"); update.progress = update.overlay.lookup("#progress"); diff --git a/Launcher/runtime/dialog/scenes/login/login.fxml b/Launcher/runtime/dialog/scenes/login/login.fxml index 4d1bfe05..a2db6ff7 100644 --- a/Launcher/runtime/dialog/scenes/login/login.fxml +++ b/Launcher/runtime/dialog/scenes/login/login.fxml @@ -15,62 +15,51 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Launcher/runtime/dialog/scenes/mainmenu/mainmenu.fxml b/Launcher/runtime/dialog/scenes/mainmenu/mainmenu.fxml index f48cca8f..70e6b20c 100644 --- a/Launcher/runtime/dialog/scenes/mainmenu/mainmenu.fxml +++ b/Launcher/runtime/dialog/scenes/mainmenu/mainmenu.fxml @@ -13,127 +13,98 @@ - + - + - + - + - + - - - + + - + - + - + - + - + - - + - + - + - - - - + - - + - + - + - + - + - + - + - + - + - + - + - + - - + + diff --git a/Launcher/runtime/dialog/scenes/options/options.fxml b/Launcher/runtime/dialog/scenes/options/options.fxml index 90eebc82..c0b42259 100644 --- a/Launcher/runtime/dialog/scenes/options/options.fxml +++ b/Launcher/runtime/dialog/scenes/options/options.fxml @@ -1,7 +1,6 @@ - @@ -9,59 +8,55 @@ + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Launcher/runtime/dialog/styles.css b/Launcher/runtime/dialog/styles.css index 574e979a..d26cc8e4 100644 --- a/Launcher/runtime/dialog/styles.css +++ b/Launcher/runtime/dialog/styles.css @@ -34,8 +34,6 @@ #serverStatus{ /* Mask */ #mask { -fx-effect: DropShadow( gaussian , rgba(255,255,255,0.5) , 0,0,0,1 ); - -fx-pref-width: 692px; - -fx-pref-height: 450px; } /** Errors **/ @@ -194,7 +192,7 @@ .combologin-popup .list-view { .combologin .list-cell:filled:selected .text, .combologin .list-cell:filled:selected .text { - -fx-fill: #909090; + -fx-fill: #323232; } .combologin .arrow, @@ -211,13 +209,13 @@ .combologin-popup .list-view .list-cell:filled:selected, .combologin-popup .list { -fx-background: -fx-accent; -fx-background-color: -fx-selection-bar; - -fx-text-fill: -fx-selection-bar-text; + -fx-text-fill: #909090; } .combologin-popup .list-view .list-cell:filled:hover { -fx-background-color: white; - -fx-text-fill: -fx-text-inner-color; + -fx-text-fill: #909090; } /** web**/ diff --git a/Launcher/src/main/java/ru/gravit/launcher/LauncherEngine.java b/Launcher/src/main/java/ru/gravit/launcher/LauncherEngine.java index 9fcf3a0d..e531d802 100644 --- a/Launcher/src/main/java/ru/gravit/launcher/LauncherEngine.java +++ b/Launcher/src/main/java/ru/gravit/launcher/LauncherEngine.java @@ -3,6 +3,7 @@ import ru.gravit.launcher.client.ClientModuleManager; import ru.gravit.launcher.client.DirBridge; import ru.gravit.launcher.client.FunctionalBridge; +import ru.gravit.launcher.client.LauncherUpdateController; import ru.gravit.launcher.guard.LauncherGuardManager; import ru.gravit.launcher.gui.JSRuntimeProvider; import ru.gravit.launcher.gui.RuntimeProvider; @@ -11,6 +12,7 @@ import ru.gravit.launcher.request.Request; import ru.gravit.launcher.request.RequestException; import ru.gravit.launcher.request.auth.RestoreSessionRequest; +import ru.gravit.launcher.request.update.UpdateRequest; import ru.gravit.launcher.request.websockets.StandartClientWebSocketService; import ru.gravit.utils.helper.CommonHelper; import ru.gravit.utils.helper.EnvHelper; @@ -95,6 +97,7 @@ public void start(String... args) throws Throwable { }; } LauncherGuardManager.initGuard(false); + UpdateRequest.setController(new LauncherUpdateController()); Objects.requireNonNull(args, "args"); if (started.getAndSet(true)) throw new IllegalStateException("Launcher has been already started"); diff --git a/Launcher/src/main/java/ru/gravit/launcher/NewLauncherSettings.java b/Launcher/src/main/java/ru/gravit/launcher/NewLauncherSettings.java index ffd15b08..25e3b1fe 100644 --- a/Launcher/src/main/java/ru/gravit/launcher/NewLauncherSettings.java +++ b/Launcher/src/main/java/ru/gravit/launcher/NewLauncherSettings.java @@ -37,6 +37,10 @@ public class NewLauncherSettings { public List lastProfiles = new LinkedList<>(); @LauncherAPI public Map userSettings = new HashMap<>(); + @LauncherAPI + public boolean featureStore; + @LauncherAPI + public String consoleUnlockKey; public static class HashedStoreEntry { @LauncherAPI @@ -45,6 +49,8 @@ public static class HashedStoreEntry { public String name; @LauncherAPI public String fullPath; + @LauncherAPI + public transient boolean needSave = false; public HashedStoreEntry(HashedDir hdir, String name, String fullPath) { this.hdir = hdir; @@ -59,9 +65,9 @@ public HashedStoreEntry(HashedDir hdir, String name, String fullPath) { @LauncherAPI public void putHDir(String name, Path path, HashedDir dir) { String fullPath = path.toAbsolutePath().toString(); - for (HashedStoreEntry e : lastHDirs) { - if (e.fullPath.equals(fullPath) && e.name.equals(name)) return; - } - lastHDirs.add(new HashedStoreEntry(dir, name, fullPath)); + lastHDirs.removeIf((e) -> e.fullPath.equals(fullPath) && e.name.equals(name)); + HashedStoreEntry e = new HashedStoreEntry(dir, name, fullPath); + e.needSave = true; + lastHDirs.add(e); } } diff --git a/Launcher/src/main/java/ru/gravit/launcher/client/LauncherUpdateController.java b/Launcher/src/main/java/ru/gravit/launcher/client/LauncherUpdateController.java new file mode 100644 index 00000000..a5dc40d6 --- /dev/null +++ b/Launcher/src/main/java/ru/gravit/launcher/client/LauncherUpdateController.java @@ -0,0 +1,139 @@ +package ru.gravit.launcher.client; + +import ru.gravit.launcher.NewLauncherSettings; +import ru.gravit.launcher.downloader.ListDownloader; +import ru.gravit.launcher.events.request.UpdateRequestEvent; +import ru.gravit.launcher.hasher.HashedDir; +import ru.gravit.launcher.hasher.HashedEntry; +import ru.gravit.launcher.hasher.HashedFile; +import ru.gravit.launcher.managers.SettingsManager; +import ru.gravit.launcher.request.update.UpdateRequest; +import ru.gravit.utils.helper.IOHelper; +import ru.gravit.utils.helper.LogHelper; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; + +public class LauncherUpdateController implements UpdateRequest.UpdateController { + @Override + public void preUpdate(UpdateRequest request, UpdateRequestEvent e) { + + } + + @Override + public void preDiff(UpdateRequest request, UpdateRequestEvent e) { + + } + + @Override + public void postDiff(UpdateRequest request, UpdateRequestEvent e, HashedDir.Diff diff) throws IOException { + if(e.zip) return; + if(SettingsManager.settings.featureStore) + { + LogHelper.info("Enabled HStore feature. Find"); + AtomicReference lastEn = new AtomicReference<>(null); + ArrayList removed = new ArrayList<>(); + diff.mismatch.walk(File.separator, (path, name, entry) -> { + if(entry.getType() == HashedEntry.Type.DIR) { + Files.createDirectories(request.getDir().resolve(path)); + return HashedDir.WalkAction.CONTINUE; + } + HashedFile file = (HashedFile) entry; + //Первый экспериментальный способ - честно обходим все возможные Store + Path ret = null; + if(lastEn.get() == null) + { + for(NewLauncherSettings.HashedStoreEntry en : SettingsManager.settings.lastHDirs) + { + ret = tryFind(en, file); + if(ret != null) { + lastEn.set(en); + break; + } + } + } + else { + ret = tryFind(lastEn.get(), file); + } + if(ret == null) + { + for(NewLauncherSettings.HashedStoreEntry en : SettingsManager.settings.lastHDirs) + { + ret = tryFind(en, file); + if(ret != null) { + lastEn.set(en); + break; + } + } + } + if(ret != null) + { + //Еще раз проверим корректность хеша + //Возможно эта проверка избыточна + //if(file.isSame(ret, true)) + { + Path source = request.getDir().resolve(path); + LogHelper.debug("Copy file %s to %s", ret.toAbsolutePath().toString(), source.toAbsolutePath().toString()); + //Let's go! + Files.copy(ret, source); + try(InputStream input = IOHelper.newInput(ret)) + { + IOHelper.transfer(input, source); + } + entry.flag = true; + //removed.add(path.replace('\\', '/')); + } + } + return HashedDir.WalkAction.CONTINUE; + }); + } + } + public Path tryFind(NewLauncherSettings.HashedStoreEntry en, HashedFile file) throws IOException + { + AtomicReference ret = new AtomicReference<>(null); + en.hdir.walk(File.separator, (path, name, entry) -> { + if(entry.getType() == HashedEntry.Type.DIR) return HashedDir.WalkAction.CONTINUE; + HashedFile tfile = (HashedFile) entry; + if(tfile.isSame(file)) + { + LogHelper.dev("[DIR:%s] Found file %s in %s", en.name, name, path); + Path tdir = Paths.get(en.fullPath).resolve(path); + try { + if(tfile.isSame(tdir, true)) + { + LogHelper.dev("[DIR:%s] Confirmed file %s in %s", en.name, name, path); + ret.set(tdir); + return HashedDir.WalkAction.STOP; + } + } catch (IOException e) + { + LogHelper.error("Check file error %s %s", e.getClass().getName(), e.getMessage()); + } + } + return HashedDir.WalkAction.CONTINUE; + }); + return ret.get(); + } + + @Override + public void preDownload(UpdateRequest request, UpdateRequestEvent e, List adds) { + + } + + @Override + public void postDownload(UpdateRequest request, UpdateRequestEvent e) { + + } + + @Override + public void postUpdate(UpdateRequest request, UpdateRequestEvent e) { + + } +} diff --git a/Launcher/src/main/java/ru/gravit/launcher/console/FeatureCommand.java b/Launcher/src/main/java/ru/gravit/launcher/console/FeatureCommand.java new file mode 100644 index 00000000..07f9ffc8 --- /dev/null +++ b/Launcher/src/main/java/ru/gravit/launcher/console/FeatureCommand.java @@ -0,0 +1,37 @@ +package ru.gravit.launcher.console; + +import ru.gravit.launcher.managers.SettingsManager; +import ru.gravit.utils.command.Command; +import ru.gravit.utils.helper.LogHelper; + +public class FeatureCommand extends Command { + @Override + public String getArgsDescription() { + return "[feature] [true/false]"; + } + + @Override + public String getUsageDescription() { + return "Enable or disable feature"; + } + + @Override + public void invoke(String... args) throws Exception { + verifyArgs(args, 2); + boolean enabled = Boolean.valueOf(args[1]); + switch (args[0]) + { + case "store": + { + SettingsManager.settings.featureStore = enabled; + break; + } + default: + { + LogHelper.info("Features: [store]"); + return; + } + } + LogHelper.info("Feature %s %s", args[0], enabled ? "enabled" : "disabled"); + } +} diff --git a/Launcher/src/main/java/ru/gravit/launcher/console/UnlockCommand.java b/Launcher/src/main/java/ru/gravit/launcher/console/UnlockCommand.java index 0a9b5b73..a27a7ff3 100644 --- a/Launcher/src/main/java/ru/gravit/launcher/console/UnlockCommand.java +++ b/Launcher/src/main/java/ru/gravit/launcher/console/UnlockCommand.java @@ -1,6 +1,7 @@ package ru.gravit.launcher.console; import ru.gravit.launcher.managers.ConsoleManager; +import ru.gravit.launcher.managers.SettingsManager; import ru.gravit.utils.command.Command; import ru.gravit.utils.helper.LogHelper; @@ -22,6 +23,8 @@ public void invoke(String... args) throws Exception { LogHelper.info("Unlock successful"); ConsoleManager.unlock(); ConsoleManager.handler.unregisterCommand("unlock"); + LogHelper.info("Write unlock key"); + SettingsManager.settings.consoleUnlockKey = args[0]; } else { LogHelper.error("Unlock key incorrect"); } diff --git a/Launcher/src/main/java/ru/gravit/launcher/console/store/CopyStoreDirCommand.java b/Launcher/src/main/java/ru/gravit/launcher/console/store/CopyStoreDirCommand.java new file mode 100644 index 00000000..9731dba5 --- /dev/null +++ b/Launcher/src/main/java/ru/gravit/launcher/console/store/CopyStoreDirCommand.java @@ -0,0 +1,51 @@ +package ru.gravit.launcher.console.store; + +import ru.gravit.launcher.NewLauncherSettings; +import ru.gravit.launcher.managers.SettingsManager; +import ru.gravit.utils.command.Command; +import ru.gravit.utils.helper.LogHelper; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class CopyStoreDirCommand extends Command { + @Override + public String getArgsDescription() { + return "[index] [overwrite(true/false)]"; + } + + @Override + public String getUsageDescription() { + return "Copy dir in GravitLauncherStore"; + } + + @Override + public void invoke(String... args) throws Exception { + verifyArgs(args, 2); + int ind = 1; + int index = Integer.valueOf(args[0]); + boolean overwrite = Boolean.valueOf(args[1]); + for(NewLauncherSettings.HashedStoreEntry e : SettingsManager.settings.lastHDirs) + { + if(ind == index) + { + LogHelper.info("Copy [%d] FullPath: %s name: %s", ind, e.fullPath, e.name); + Path path = Paths.get(e.fullPath); + if(!Files.isDirectory(path)) + { + LogHelper.error("Directory %s not found", path.toAbsolutePath().toString()); + return; + } + Path target = Paths.get(SettingsManager.settings.updatesDirPath).resolve(e.name); + if(Files.exists(target) && !overwrite) + { + LogHelper.error("Directory %s found, flag overwrite not found", target.toAbsolutePath().toString()); + return; + } + Files.copy(path, target); + } + ind++; + } + } +} diff --git a/Launcher/src/main/java/ru/gravit/launcher/console/store/LinkStoreDirCommand.java b/Launcher/src/main/java/ru/gravit/launcher/console/store/LinkStoreDirCommand.java new file mode 100644 index 00000000..a107e6d3 --- /dev/null +++ b/Launcher/src/main/java/ru/gravit/launcher/console/store/LinkStoreDirCommand.java @@ -0,0 +1,51 @@ +package ru.gravit.launcher.console.store; + +import ru.gravit.launcher.NewLauncherSettings; +import ru.gravit.launcher.managers.SettingsManager; +import ru.gravit.utils.command.Command; +import ru.gravit.utils.helper.LogHelper; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class LinkStoreDirCommand extends Command { + + @Override + public String getArgsDescription() { + return "[index]"; + } + + @Override + public String getUsageDescription() { + return "Create symlink to GravitLauncherStore directory"; + } + + @Override + public void invoke(String... args) throws Exception { + verifyArgs(args, 1); + int ind = 1; + int index = Integer.valueOf(args[0]); + for(NewLauncherSettings.HashedStoreEntry e : SettingsManager.settings.lastHDirs) + { + if(ind == index) + { + LogHelper.info("Copy [%d] FullPath: %s name: %s", ind, e.fullPath, e.name); + Path path = Paths.get(e.fullPath); + if(!Files.isDirectory(path)) + { + LogHelper.error("Directory %s not found", path.toAbsolutePath().toString()); + return; + } + Path target = Paths.get(SettingsManager.settings.updatesDirPath).resolve(e.name); + if(Files.exists(target)) + { + LogHelper.error("Directory %s already exists", target.toAbsolutePath().toString()); + return; + } + Files.createSymbolicLink(path, target); + } + ind++; + } + } +} diff --git a/Launcher/src/main/java/ru/gravit/launcher/console/store/StoreListCommand.java b/Launcher/src/main/java/ru/gravit/launcher/console/store/StoreListCommand.java new file mode 100644 index 00000000..14a68524 --- /dev/null +++ b/Launcher/src/main/java/ru/gravit/launcher/console/store/StoreListCommand.java @@ -0,0 +1,28 @@ +package ru.gravit.launcher.console.store; + +import ru.gravit.launcher.NewLauncherSettings; +import ru.gravit.launcher.managers.SettingsManager; +import ru.gravit.utils.command.Command; +import ru.gravit.utils.helper.LogHelper; + +public class StoreListCommand extends Command { + @Override + public String getArgsDescription() { + return null; + } + + @Override + public String getUsageDescription() { + return "List GravitLauncherStore"; + } + + @Override + public void invoke(String... args) throws Exception { + int ind = 1; + for(NewLauncherSettings.HashedStoreEntry e : SettingsManager.settings.lastHDirs) + { + LogHelper.info("[%d] FullPath: %s name: %s", ind, e.fullPath, e.name); + ind++; + } + } +} diff --git a/Launcher/src/main/java/ru/gravit/launcher/managers/ConsoleManager.java b/Launcher/src/main/java/ru/gravit/launcher/managers/ConsoleManager.java index 0324de64..ac22db8d 100644 --- a/Launcher/src/main/java/ru/gravit/launcher/managers/ConsoleManager.java +++ b/Launcher/src/main/java/ru/gravit/launcher/managers/ConsoleManager.java @@ -1,8 +1,13 @@ package ru.gravit.launcher.managers; +import ru.gravit.launcher.Launcher; +import ru.gravit.launcher.console.FeatureCommand; import ru.gravit.launcher.console.UnlockCommand; import ru.gravit.launcher.console.admin.ExecCommand; import ru.gravit.launcher.console.admin.LogListenerCommand; +import ru.gravit.launcher.console.store.CopyStoreDirCommand; +import ru.gravit.launcher.console.store.LinkStoreDirCommand; +import ru.gravit.launcher.console.store.StoreListCommand; import ru.gravit.utils.command.BaseCommandCategory; import ru.gravit.utils.command.CommandHandler; import ru.gravit.utils.command.JLineCommandHandler; @@ -15,10 +20,14 @@ import ru.gravit.utils.helper.LogHelper; import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; public class ConsoleManager { public static CommandHandler handler; public static Thread thread; + public static boolean isConsoleUnlock = false; public static void initConsole() throws IOException { CommandHandler localCommandHandler; @@ -46,14 +55,21 @@ public static void registerCommands() { } public static boolean checkUnlockKey(String key) { - return true; + return key.equals(Launcher.getConfig().oemUnlockKey); } public static void unlock() { handler.registerCommand("debug", new DebugCommand()); + handler.registerCommand("feature", new FeatureCommand()); BaseCommandCategory admin = new BaseCommandCategory(); admin.registerCommand("exec", new ExecCommand()); admin.registerCommand("logListen", new LogListenerCommand()); handler.registerCategory(new CommandHandler.Category(admin, "admin", "Server admin commands")); + BaseCommandCategory store = new BaseCommandCategory(); + store.registerCommand("storeList", new StoreListCommand()); + store.registerCommand("copyStoreDir", new CopyStoreDirCommand()); + store.registerCommand("linkStoreDir", new LinkStoreDirCommand()); + handler.registerCategory(new CommandHandler.Category(admin, "store", "Store admin commands")); + isConsoleUnlock = true; } } diff --git a/Launcher/src/main/java/ru/gravit/launcher/managers/SettingsManager.java b/Launcher/src/main/java/ru/gravit/launcher/managers/SettingsManager.java index 61d05238..d6788e91 100644 --- a/Launcher/src/main/java/ru/gravit/launcher/managers/SettingsManager.java +++ b/Launcher/src/main/java/ru/gravit/launcher/managers/SettingsManager.java @@ -8,6 +8,7 @@ import ru.gravit.launcher.serialize.HInput; import ru.gravit.launcher.serialize.HOutput; import ru.gravit.utils.helper.IOHelper; +import ru.gravit.utils.helper.LogHelper; import java.io.IOException; import java.lang.reflect.Type; @@ -24,6 +25,9 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) String fullPath = input.readString(1024); HashedDir dir = new HashedDir(input); settings.lastHDirs.add(new NewLauncherSettings.HashedStoreEntry(dir, dirName, fullPath)); + } catch (IOException e) + { + LogHelper.error("Skip file %s exception: %s", file.toAbsolutePath().toString(), e.getMessage()); } return super.visitFile(file, attrs); } @@ -57,6 +61,14 @@ public void setConfig(NewLauncherSettings config) { settings = config; if (settings.updatesDirPath != null) settings.updatesDir = Paths.get(settings.updatesDirPath); + if(settings.consoleUnlockKey != null && !ConsoleManager.isConsoleUnlock) + { + if(ConsoleManager.checkUnlockKey(settings.consoleUnlockKey)) + { + ConsoleManager.unlock(); + LogHelper.info("Console auto unlocked"); + } + } } @LauncherAPI @@ -69,6 +81,7 @@ public void loadHDirStore(Path storePath) throws IOException { public void saveHDirStore(Path storeProjectPath) throws IOException { Files.createDirectories(storeProjectPath); for (NewLauncherSettings.HashedStoreEntry e : settings.lastHDirs) { + if(!e.needSave) continue; Path file = storeProjectPath.resolve(e.name.concat(".bin")); if (!Files.exists(file)) Files.createFile(file); try (HOutput output = new HOutput(IOHelper.newOutput(file))) { diff --git a/LauncherAPI/src/main/java/ru/gravit/launcher/AutogenConfig.java b/LauncherAPI/src/main/java/ru/gravit/launcher/AutogenConfig.java index dd00f048..355ba7be 100644 --- a/LauncherAPI/src/main/java/ru/gravit/launcher/AutogenConfig.java +++ b/LauncherAPI/src/main/java/ru/gravit/launcher/AutogenConfig.java @@ -8,6 +8,7 @@ public class AutogenConfig { private boolean isInitModules; public String guardType; public String secretKeyClient; + public String oemUnlockKey; public String guardLicenseName; public String guardLicenseKey; public String guardLicenseEncryptKey; diff --git a/LauncherAPI/src/main/java/ru/gravit/launcher/LauncherConfig.java b/LauncherAPI/src/main/java/ru/gravit/launcher/LauncherConfig.java index 2f7a3b4a..6ce013de 100644 --- a/LauncherAPI/src/main/java/ru/gravit/launcher/LauncherConfig.java +++ b/LauncherAPI/src/main/java/ru/gravit/launcher/LauncherConfig.java @@ -25,6 +25,7 @@ public static AutogenConfig getAutogenConfig() { public final String projectname; public final int clientPort; public String secretKeyClient; + public String oemUnlockKey; @LauncherAPI public final RSAPublicKey publicKey; @@ -45,6 +46,7 @@ public LauncherConfig(HInput input) throws IOException, InvalidKeySpecException projectname = config.projectname; clientPort = config.clientPort; secretKeyClient = config.secretKeyClient; + oemUnlockKey = config.oemUnlockKey; isWarningMissArchJava = config.isWarningMissArchJava; guardLicenseEncryptKey = config.guardLicenseEncryptKey; diff --git a/LauncherAPI/src/main/java/ru/gravit/launcher/downloader/ListDownloader.java b/LauncherAPI/src/main/java/ru/gravit/launcher/downloader/ListDownloader.java index b5350d8d..7646379c 100644 --- a/LauncherAPI/src/main/java/ru/gravit/launcher/downloader/ListDownloader.java +++ b/LauncherAPI/src/main/java/ru/gravit/launcher/downloader/ListDownloader.java @@ -18,6 +18,8 @@ import java.net.URL; import java.nio.file.Path; import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; public class ListDownloader { @FunctionalInterface @@ -49,13 +51,36 @@ public void download(String base, List applies, Path dstDirFile, D for (DownloadTask apply : applies) { URI u = new URL(base.concat(IOHelper.urlEncode(apply.apply).replace("%2F", "/"))).toURI(); callback.stateChanged(apply.apply, 0L, apply.size); - LogHelper.debug("Download URL: %s", u.toString()); + Path targetPath = dstDirFile.resolve(apply.apply); + LogHelper.debug("Download URL: %s to file %s dir: %s", u.toString(), targetPath.toAbsolutePath().toString(), dstDirFile.toAbsolutePath().toString()); if (get == null) get = new HttpGet(u); else { get.reset(); get.setURI(u); } - httpclient.execute(get, new FileDownloadResponseHandler(dstDirFile.resolve(apply.apply), apply, callback, totalCallback)); + httpclient.execute(get, new FileDownloadResponseHandler(targetPath, apply, callback, totalCallback, false)); + } + } + } + public void downloadZip(String base, Path dstDirFile, DownloadCallback callback, DownloadTotalCallback totalCallback) throws IOException, URISyntaxException { + /*try (CloseableHttpClient httpclient = HttpClients.custom() + .setRedirectStrategy(new LaxRedirectStrategy()) + .build()) { + HttpGet get; + URI u = new URL(base).toURI(); + LogHelper.debug("Download ZIP URL: %s", u.toString()); + get = new HttpGet(u); + httpclient.execute(get, new FileDownloadResponseHandler(dstDirFile, callback, totalCallback, true)); + }*/ + try (ZipInputStream input = IOHelper.newZipInput(new URL(base))) { + for (ZipEntry entry = input.getNextEntry(); entry != null; entry = input.getNextEntry()) { + if (entry.isDirectory()) + continue; // Skip directories + // Unpack entry + String name = entry.getName(); + LogHelper.subInfo("Downloading file: '%s'", name); + Path fileName = IOHelper.toPath(name); + transfer(input, dstDirFile.resolve(fileName), fileName.toString(), entry.getSize(), callback, totalCallback); } } } @@ -78,24 +103,62 @@ static class FileDownloadResponseHandler implements ResponseHandler { private final DownloadTask task; private final DownloadCallback callback; private final DownloadTotalCallback totalCallback; + private final boolean zip; public FileDownloadResponseHandler(Path target) { this.target = target; this.task = null; + this.zip = false; callback = null; totalCallback = null; } - public FileDownloadResponseHandler(Path target, DownloadTask task, DownloadCallback callback, DownloadTotalCallback totalCallback) { + public FileDownloadResponseHandler(Path target, DownloadTask task, DownloadCallback callback, DownloadTotalCallback totalCallback, boolean zip) { this.target = target; this.task = task; this.callback = callback; this.totalCallback = totalCallback; + this.zip = zip; + } + + public FileDownloadResponseHandler(Path target, DownloadCallback callback, DownloadTotalCallback totalCallback, boolean zip) { + this.target = target; + this.task = null; + this.callback = callback; + this.totalCallback = totalCallback; + this.zip = zip; } @Override public Path handleResponse(HttpResponse response) throws IOException { InputStream source = response.getEntity().getContent(); + if(zip) + { + try(ZipInputStream input = IOHelper.newZipInput(source)) + { + ZipEntry entry = input.getNextEntry(); + while(entry != null) + { + if(entry.isDirectory()) + { + entry = input.getNextEntry(); + continue; + } + long size = entry.getSize(); + String filename = entry.getName(); + Path target = this.target.resolve(filename); + if(callback != null) + { + callback.stateChanged(entry.getName(), 0, entry.getSize()); + } + LogHelper.dev("Resolved filename %s to %s", filename, target.toAbsolutePath().toString()); + transfer(source, target, filename, size, callback, totalCallback); + entry = input.getNextEntry(); + } + + } + return null; + } if (callback != null && task != null) { callback.stateChanged(task.apply, 0, task.size); transfer(source, this.target, task.apply, task.size, callback, totalCallback); diff --git a/LauncherAPI/src/main/java/ru/gravit/launcher/events/request/UpdateRequestEvent.java b/LauncherAPI/src/main/java/ru/gravit/launcher/events/request/UpdateRequestEvent.java index 6f49c758..ddcaa6c6 100644 --- a/LauncherAPI/src/main/java/ru/gravit/launcher/events/request/UpdateRequestEvent.java +++ b/LauncherAPI/src/main/java/ru/gravit/launcher/events/request/UpdateRequestEvent.java @@ -9,6 +9,8 @@ public class UpdateRequestEvent extends RequestEvent { public HashedDir hdir; @LauncherNetworkAPI public String url; + @LauncherNetworkAPI + public boolean zip; @Override public String getType() { @@ -17,10 +19,18 @@ public String getType() { public UpdateRequestEvent(HashedDir hdir) { this.hdir = hdir; + this.zip = false; } public UpdateRequestEvent(HashedDir hdir, String url) { this.hdir = hdir; this.url = url; + this.zip = false; + } + + public UpdateRequestEvent(HashedDir hdir, String url, boolean zip) { + this.hdir = hdir; + this.url = url; + this.zip = zip; } } diff --git a/LauncherAPI/src/main/java/ru/gravit/launcher/request/update/UpdateRequest.java b/LauncherAPI/src/main/java/ru/gravit/launcher/request/update/UpdateRequest.java index f7eb00f4..8ae58501 100644 --- a/LauncherAPI/src/main/java/ru/gravit/launcher/request/update/UpdateRequest.java +++ b/LauncherAPI/src/main/java/ru/gravit/launcher/request/update/UpdateRequest.java @@ -27,6 +27,20 @@ import java.util.Objects; public final class UpdateRequest extends Request implements RequestInterface { + public interface UpdateController + { + void preUpdate(UpdateRequest request, UpdateRequestEvent e) throws IOException; + void preDiff(UpdateRequest request, UpdateRequestEvent e) throws IOException; + void postDiff(UpdateRequest request, UpdateRequestEvent e,HashedDir.Diff diff) throws IOException; + void preDownload(UpdateRequest request, UpdateRequestEvent e, List adds) throws IOException; + void postDownload(UpdateRequest request, UpdateRequestEvent e) throws IOException; + void postUpdate(UpdateRequest request, UpdateRequestEvent e) throws IOException; + } + private static UpdateController controller; + + public static void setController(UpdateController controller) { + UpdateRequest.controller = controller; + } @Override public String getType() { @@ -170,15 +184,22 @@ public double getTotalSizeMiB() { public UpdateRequestEvent requestDo(StandartClientWebSocketService service) throws Exception { LogHelper.debug("Start update request"); UpdateRequestEvent e = (UpdateRequestEvent) service.sendRequest(this); + if(controller != null) controller.preUpdate(this, e); LogHelper.debug("Start update"); Launcher.profile.pushOptionalFile(e.hdir, !Launcher.profile.isUpdateFastCheck()); + if(controller != null) controller.preDiff(this, e); HashedDir.Diff diff = e.hdir.diff(localDir, matcher); + if(controller != null) controller.postDiff(this, e, diff); final List adds = new ArrayList<>(); + if(controller != null) controller.preDownload(this, e, adds); diff.mismatch.walk(IOHelper.CROSS_SEPARATOR, (path, name, entry) -> { if (entry.getType().equals(HashedEntry.Type.FILE)) { - HashedFile file = (HashedFile) entry; - totalSize += file.size; - adds.add(new ListDownloader.DownloadTask(path, file.size)); + if(!entry.flag) + { + HashedFile file = (HashedFile) entry; + totalSize += file.size; + adds.add(new ListDownloader.DownloadTask(path, file.size)); + } } else if (entry.getType().equals(HashedEntry.Type.DIR)) { try { Files.createDirectories(dir.resolve(path)); @@ -186,13 +207,24 @@ public UpdateRequestEvent requestDo(StandartClientWebSocketService service) thro LogHelper.error(ex); } } + return HashedDir.WalkAction.CONTINUE; }); totalSize = diff.mismatch.size(); startTime = Instant.now(); updateState("UnknownFile", 0L, 100); ListDownloader listDownloader = new ListDownloader(); - listDownloader.download(e.url, adds, dir, this::updateState, (add) -> totalDownloaded += add); + LogHelper.info("Download %s to %s", dirName, dir.toAbsolutePath().toString()); + if(e.zip && !adds.isEmpty()) + { + listDownloader.downloadZip(e.url, dir, this::updateState, (add) -> totalDownloaded += add); + } + else + { + listDownloader.download(e.url, adds, dir, this::updateState, (add) -> totalDownloaded += add); + } + if(controller != null) controller.postDownload(this, e); deleteExtraDir(dir, diff.extra, diff.extra.flag); + if(controller != null) controller.postUpdate(this, e); LogHelper.debug("Update success"); return e; } @@ -201,6 +233,11 @@ public UpdateRequestEvent requestDo(StandartClientWebSocketService service) thro @LauncherNetworkAPI private final String dirName; private transient final Path dir; + + public Path getDir() { + return dir; + } + private transient final FileNameMatcher matcher; private transient final boolean digest; diff --git a/LauncherAPI/src/main/java/ru/gravit/launcher/request/websockets/WaitEventHandler.java b/LauncherAPI/src/main/java/ru/gravit/launcher/request/websockets/WaitEventHandler.java index 4bcf3835..d319714d 100644 --- a/LauncherAPI/src/main/java/ru/gravit/launcher/request/websockets/WaitEventHandler.java +++ b/LauncherAPI/src/main/java/ru/gravit/launcher/request/websockets/WaitEventHandler.java @@ -5,10 +5,12 @@ import ru.gravit.utils.helper.LogHelper; import java.util.HashSet; +import java.util.Set; import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; public class WaitEventHandler implements ClientWebSocketService.EventHandler { - public HashSet requests = new HashSet<>(); + public Set requests = ConcurrentHashMap.newKeySet(); @Override public void process(ResultInterface result) { diff --git a/LauncherAPI/src/main/java/ru/gravit/launcher/request/websockets/WebSocketClientHandler.java b/LauncherAPI/src/main/java/ru/gravit/launcher/request/websockets/WebSocketClientHandler.java index 1f21cc48..d9c27341 100644 --- a/LauncherAPI/src/main/java/ru/gravit/launcher/request/websockets/WebSocketClientHandler.java +++ b/LauncherAPI/src/main/java/ru/gravit/launcher/request/websockets/WebSocketClientHandler.java @@ -6,6 +6,8 @@ import io.netty.util.CharsetUtil; import ru.gravit.utils.helper.LogHelper; +import java.util.concurrent.TimeUnit; + public class WebSocketClientHandler extends SimpleChannelInboundHandler { private final WebSocketClientHandshaker handshaker; @@ -30,6 +32,9 @@ public void handlerAdded(final ChannelHandlerContext ctx) throws Exception { public void channelActive(final ChannelHandlerContext ctx) throws Exception { handshaker.handshake(ctx.channel()); clientJSONPoint.onOpen(); + ctx.executor().schedule(() -> { + ctx.channel().writeAndFlush(new PingWebSocketFrame()); + }, 20L, TimeUnit.SECONDS); } @Override diff --git a/libLauncher/src/main/java/ru/gravit/launcher/hasher/HashedDir.java b/libLauncher/src/main/java/ru/gravit/launcher/hasher/HashedDir.java index 5db3d36f..bb1327be 100644 --- a/libLauncher/src/main/java/ru/gravit/launcher/hasher/HashedDir.java +++ b/libLauncher/src/main/java/ru/gravit/launcher/hasher/HashedDir.java @@ -338,31 +338,44 @@ public void write(HOutput output) throws IOException { } } - public void walk(CharSequence separator, WalkCallback callback) { + public void walk(CharSequence separator, WalkCallback callback) throws IOException { String append = ""; walk(append, separator, callback, true); } + public enum WalkAction + { + STOP, CONTINUE + } @FunctionalInterface public interface WalkCallback { - void walked(String path, String name, HashedEntry entry); + WalkAction walked(String path, String name, HashedEntry entry) throws IOException; } - private void walk(String append, CharSequence separator, WalkCallback callback, boolean noSeparator) { + private WalkAction walk(String append, CharSequence separator, WalkCallback callback, boolean noSeparator) throws IOException { for (Map.Entry entry : map.entrySet()) { HashedEntry e = entry.getValue(); if (e.getType() == Type.FILE) { if (noSeparator) - callback.walked(append + entry.getKey(), entry.getKey(), e); + { + WalkAction a = callback.walked(append + entry.getKey(), entry.getKey(), e); + if(a == WalkAction.STOP) return a; + } else - callback.walked(append + separator + entry.getKey(), entry.getKey(), e); + { + WalkAction a = callback.walked(append + separator + entry.getKey(), entry.getKey(), e); + if(a == WalkAction.STOP) return a; + } } else { String newAppend; if (noSeparator) newAppend = append + entry.getKey(); else newAppend = append + separator + entry.getKey(); - callback.walked(newAppend, entry.getKey(), e); - ((HashedDir) e).walk(newAppend, separator, callback, false); + WalkAction a = callback.walked(newAppend, entry.getKey(), e); + if(a == WalkAction.STOP) return a; + a = ((HashedDir) e).walk(newAppend, separator, callback, false); + if(a == WalkAction.STOP) return a; } } + return WalkAction.CONTINUE; } } diff --git a/libLauncher/src/main/java/ru/gravit/utils/Version.java b/libLauncher/src/main/java/ru/gravit/utils/Version.java index 5f5da60f..5f729792 100644 --- a/libLauncher/src/main/java/ru/gravit/utils/Version.java +++ b/libLauncher/src/main/java/ru/gravit/utils/Version.java @@ -17,8 +17,8 @@ public final class Version { public final Type release; public static final int MAJOR = 5; public static final int MINOR = 0; - public static final int PATCH = 0; - public static final int BUILD = 7; + public static final int PATCH = 1; + public static final int BUILD = 1; public static final Version.Type RELEASE = Version.Type.STABLE; @LauncherAPI diff --git a/libLauncher/src/main/java/ru/gravit/utils/command/JLineCommandHandler.java b/libLauncher/src/main/java/ru/gravit/utils/command/JLineCommandHandler.java index 33f678ed..0a3431cf 100644 --- a/libLauncher/src/main/java/ru/gravit/utils/command/JLineCommandHandler.java +++ b/libLauncher/src/main/java/ru/gravit/utils/command/JLineCommandHandler.java @@ -75,6 +75,7 @@ public String readLine() throws IOException { try { return reader.readLine(); } catch (UserInterruptException e) { + System.exit(0); return null; } } diff --git a/libLauncher/src/main/java/ru/gravit/utils/helper/LogHelper.java b/libLauncher/src/main/java/ru/gravit/utils/helper/LogHelper.java index 3d75e87c..22c1649a 100644 --- a/libLauncher/src/main/java/ru/gravit/utils/helper/LogHelper.java +++ b/libLauncher/src/main/java/ru/gravit/utils/helper/LogHelper.java @@ -113,7 +113,10 @@ public static void debug(String format, Object... args) { @LauncherAPI public static void dev(String format, Object... args) { - dev(String.format(format, args)); + if(isDevEnabled()) + { + dev(String.format(format, args)); + } } @LauncherAPI