mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-12-23 09:01:08 +03:00
Merge branch 'release/5.0.1'
This commit is contained in:
commit
e55200f5eb
39 changed files with 711 additions and 262 deletions
|
@ -24,7 +24,7 @@ build:
|
|||
- ./gradlew assemble
|
||||
artifacts:
|
||||
paths:
|
||||
- LaunchServer/build/libs/*.jar
|
||||
- LaunchServer/build/libs/*
|
||||
- ServerWrapper/build/libs/*.jar
|
||||
expire_in: 1 week
|
||||
|
||||
|
|
|
@ -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<String, String> bindings = new HashMap<>();
|
||||
public Map<String, NettyUpdatesBind> bindings = new HashMap<>();
|
||||
public NettyPerformanceConfig performance;
|
||||
public NettyBindAddress[] binds;
|
||||
public LogLevel logLevel = LogLevel.DEBUG;
|
||||
|
|
|
@ -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<HWID> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 -> {
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
BIN
Launcher/runtime/dialog/images/downloader/blured.jpg
Normal file
BIN
Launcher/runtime/dialog/images/downloader/blured.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.8 KiB |
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -8,26 +8,24 @@
|
|||
|
||||
<!-- DrLeonardo Design -->
|
||||
|
||||
<Pane fx:id="overlay" prefHeight="450.0" prefWidth="693.0" xmlns="http://javafx.com/javafx/8.0.201"
|
||||
xmlns:fx="http://javafx.com/fxml/1">
|
||||
<Pane fx:id="overlay" prefHeight="450.0" prefWidth="694.0" xmlns="http://javafx.com/javafx/8.0.201" xmlns:fx="http://javafx.com/fxml/1">
|
||||
<children>
|
||||
<Pane prefHeight="450.0" prefWidth="693.0" styleClass="downloadPane">
|
||||
<Pane prefHeight="450.0" prefWidth="694.0" styleClass="downloadPane">
|
||||
<children>
|
||||
<Label fx:id="utitle" alignment="CENTER" layoutX="100.0" layoutY="125.0" prefHeight="30.0"
|
||||
prefWidth="495.0" text="Загрузка обновления..." textFill="WHITE">
|
||||
<Label fx:id="utitle" alignment="CENTER" layoutX="100.0" layoutY="125.0" prefHeight="30.0" prefWidth="495.0" text="Загрузка обновления..." textFill="WHITE">
|
||||
<font>
|
||||
<Font name="System Bold" size="20.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<JFXSpinner fx:id="progress" layoutX="98.0" layoutY="226.0" prefHeight="100.0" prefWidth="100.0" />
|
||||
<Label fx:id="description" layoutX="216.0" layoutY="226.0" prefHeight="100.0" prefWidth="380.0"
|
||||
text="..." textFill="WHITE">
|
||||
<Label fx:id="description" layoutX="216.0" layoutY="226.0" prefHeight="100.0" prefWidth="380.0" text="..." textFill="WHITE">
|
||||
<font>
|
||||
<Font name="System Bold" size="16.0" />
|
||||
</font>
|
||||
</Label>
|
||||
</children>
|
||||
</Pane>
|
||||
<Pane id="mask" layoutX="-1.0" opacity="0.0" prefHeight="450.0" prefWidth="694.0" visible="false" />
|
||||
</children>
|
||||
<stylesheets>
|
||||
<URL value="@update.css" />
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -18,53 +18,42 @@
|
|||
<children>
|
||||
<Pane fx:id="layout" prefWidth="740.0">
|
||||
<children>
|
||||
<Pane fx:id="authPane" layoutX="422.0" prefHeight="411.0" prefWidth="286.0" styleClass="loginPane">
|
||||
<Pane fx:id="authPane" layoutX="424.0" prefHeight="411.0" prefWidth="286.0" styleClass="loginPane">
|
||||
<children>
|
||||
<Pane fx:id="logo" layoutX="72.0" layoutY="62.0" prefWidth="124.0" styleClass="logo">
|
||||
</Pane>
|
||||
<JFXTextField id="login" alignment="CENTER" focusColor="#5fd97a" layoutX="34.0" layoutY="196.0"
|
||||
promptText="Логин" unFocusColor="#dadada"/>
|
||||
<JFXPasswordField id="password" alignment="CENTER" focusColor="#5fd97a" layoutX="34.0"
|
||||
layoutY="249.0" promptText="Пароль" unFocusColor="#dadada"/>
|
||||
<JFXTextField id="login" alignment="CENTER" focusColor="#5fd97a" layoutX="34.0" layoutY="196.0" promptText="Логин" unFocusColor="#dadada" />
|
||||
<JFXPasswordField id="password" alignment="CENTER" focusColor="#5fd97a" layoutX="34.0" layoutY="249.0" promptText="Пароль" unFocusColor="#dadada" />
|
||||
<JFXButton id="goAuth" layoutX="34.0" layoutY="370.0" styleClass="auth" text="ВОЙТИ" />
|
||||
<JFXCheckBox id="rememberchb" fx:id="savePassword" checkedColor="#5fd97a"
|
||||
contentDisplay="CENTER" layoutX="63.0" layoutY="297.0" prefWidth="144.0"
|
||||
text="Сохранить пароль" textFill="#dadada" unCheckedColor="#909090"/>
|
||||
<JFXComboBox id="authOptions" fx:id="authOptions" focusColor="#5fd97a" layoutX="34.0"
|
||||
layoutY="341.0" prefHeight="25.0" prefWidth="200.0" promptText="Авторизация 1"
|
||||
unFocusColor="#70666600">
|
||||
<JFXCheckBox id="rememberchb" fx:id="savePassword" checkedColor="#5fd97a" contentDisplay="CENTER" layoutX="63.0" layoutY="297.0" prefWidth="144.0" text="Сохранить пароль" textFill="#dadada" unCheckedColor="#909090" />
|
||||
<JFXComboBox id="authOptions" fx:id="authOptions" focusColor="#5fd97a" layoutX="34.0" layoutY="341.0" prefHeight="25.0" prefWidth="200.0" promptText="Способ авторизации" unFocusColor="#70666600">
|
||||
<styleClass>
|
||||
<String fx:value="combologin" />
|
||||
<String fx:value="combologin-popup" />
|
||||
</styleClass>
|
||||
</JFXComboBox>
|
||||
<Hyperlink id="link" fx:id="link" layoutX="94.0" layoutY="422.0" prefHeight="19.0"
|
||||
prefWidth="81.0" textAlignment="CENTER"/>
|
||||
<Hyperlink id="link" fx:id="link" layoutX="94.0" layoutY="422.0" prefHeight="19.0" prefWidth="81.0" textAlignment="CENTER" />
|
||||
</children>
|
||||
</Pane>
|
||||
<JFXMasonryPane fx:id="news" prefHeight="432.0" prefWidth="423.0" styleClass="news" />
|
||||
</children>
|
||||
</Pane>
|
||||
<Pane id="mask" opacity="0.0" prefHeight="425.0" prefWidth="694.0" visible="false"/>
|
||||
<Pane fx:id="bar" layoutX="696.0" prefHeight="425.0" prefWidth="43.0" styleClass="bar">
|
||||
<Pane id="mask" opacity="0.0" prefHeight="450.0" prefWidth="694.0" visible="false" />
|
||||
<Pane fx:id="bar" layoutX="694.0" prefHeight="425.0" prefWidth="43.0" styleClass="bar">
|
||||
<children>
|
||||
<JFXButton id="hide" alignment="CENTER" contentDisplay="CENTER" layoutY="45.0" ripplerFill="#646464"
|
||||
text="" textAlignment="CENTER">
|
||||
<JFXButton id="hide" alignment="CENTER" contentDisplay="CENTER" layoutY="45.0" ripplerFill="#646464" text="" textAlignment="CENTER">
|
||||
<graphic>
|
||||
<MaterialDesignIconView fill="WHITE" glyphName="MINUS" size="30" textAlignment="CENTER" />
|
||||
</graphic>
|
||||
</JFXButton>
|
||||
<JFXButton id="close" alignment="CENTER" contentDisplay="CENTER" ripplerFill="#fb8c8c" text=""
|
||||
textAlignment="CENTER">
|
||||
<JFXButton id="close" alignment="CENTER" contentDisplay="CENTER" ripplerFill="#fb8c8c" text="" textAlignment="CENTER">
|
||||
<graphic>
|
||||
<MaterialDesignIconView fill="WHITE" glyphName="CLOSE" size="30" textAlignment="CENTER" />
|
||||
</graphic>
|
||||
</JFXButton>
|
||||
<JFXButton id="discord" alignment="CENTER" contentDisplay="CENTER" layoutY="370.0" ripplerFill="#646464"
|
||||
text="" textAlignment="CENTER">
|
||||
<JFXButton id="discord" alignment="CENTER" contentDisplay="CENTER" layoutY="370.0" ripplerFill="#646464" text="" textAlignment="CENTER">
|
||||
<graphic>
|
||||
<MaterialDesignIconView fill="#5fd97a" glyphName="MESSAGE_TEXT" size="20"
|
||||
textAlignment="CENTER"/>
|
||||
<MaterialDesignIconView fill="#5fd97a" glyphName="MESSAGE_TEXT" size="20" textAlignment="CENTER" />
|
||||
</graphic>
|
||||
</JFXButton>
|
||||
</children>
|
||||
|
|
|
@ -13,124 +13,95 @@
|
|||
|
||||
<!-- DrLeonardo Design -->
|
||||
|
||||
<Pane fx:id="serverPaneLayout" maxHeight="-1.0" maxWidth="-1.0" prefWidth="740.0" visible="true"
|
||||
xmlns="http://javafx.com/javafx/8.0.201" xmlns:fx="http://javafx.com/fxml/1">
|
||||
<Pane fx:id="serverPaneLayout" maxHeight="-1.0" maxWidth="-1.0" prefWidth="740.0" visible="true" xmlns="http://javafx.com/javafx/8.0.201" xmlns:fx="http://javafx.com/fxml/1">
|
||||
<children>
|
||||
<Pane fx:id="layout" maxHeight="-1.0" maxWidth="-1.0" prefWidth="740.0" visible="true"
|
||||
xmlns="http://javafx.com/javafx/8.0.201" xmlns:fx="http://javafx.com/fxml/1">
|
||||
<Pane fx:id="layout" maxHeight="-1.0" maxWidth="-1.0" prefWidth="740.0" visible="true" xmlns="http://javafx.com/javafx/8.0.201" xmlns:fx="http://javafx.com/fxml/1">
|
||||
<children>
|
||||
<Pane id="serverPane" prefHeight="450.0" prefWidth="693.0">
|
||||
<Pane id="serverPane" prefHeight="450.0" prefWidth="694.0">
|
||||
<children>
|
||||
<ScrollPane id="serverlist" hbarPolicy="NEVER" layoutX="1.0" prefHeight="450.0"
|
||||
prefWidth="307.0" visible="true">
|
||||
<ScrollPane id="serverlist" hbarPolicy="NEVER" layoutX="1.0" prefHeight="450.0" prefWidth="307.0" visible="true">
|
||||
<content>
|
||||
<FlowPane focusTraversable="false" prefHeight="446.0" prefWidth="306.0"
|
||||
prefWrapLength="0.0" rowValignment="TOP" vgap="10.0" visible="true">
|
||||
<FlowPane focusTraversable="false" prefHeight="446.0" prefWidth="306.0" prefWrapLength="0.0" rowValignment="TOP" vgap="10.0" visible="true">
|
||||
<JFXButton id="servercontainer" ripplerFill="#ffffff80" text="">
|
||||
<FlowPane.margin>
|
||||
<Insets bottom="10.0" />
|
||||
</FlowPane.margin>
|
||||
</JFXButton>
|
||||
</FlowPane.margin></JFXButton>
|
||||
<padding>
|
||||
<Insets left="10.0" top="10.0" />
|
||||
</padding>
|
||||
</FlowPane>
|
||||
</content>
|
||||
</ScrollPane>
|
||||
<Pane id="serverentrance" layoutX="306.0" prefHeight="425.0" prefWidth="388.0"
|
||||
styleClass="serverentrance">
|
||||
<Pane id="serverentrance" layoutX="308.0" prefHeight="425.0" prefWidth="388.0" styleClass="serverentrance">
|
||||
<children>
|
||||
<ScrollPane id="serverinfo" hbarPolicy="NEVER" layoutX="4.0" layoutY="53.0"
|
||||
pannable="true" prefHeight="322.0" prefWidth="381.0" visible="true">
|
||||
<ScrollPane id="serverinfo" hbarPolicy="NEVER" layoutX="4.0" layoutY="53.0" pannable="true" prefHeight="322.0" prefWidth="381.0" visible="true">
|
||||
<content>
|
||||
<FlowPane id="" focusTraversable="false" orientation="HORIZONTAL"
|
||||
prefHeight="310.0" prefWidth="369.0" rowValignment="TOP"
|
||||
visible="true">
|
||||
<FlowPane id="" focusTraversable="false" orientation="HORIZONTAL" prefHeight="310.0" prefWidth="369.0" rowValignment="TOP" visible="true">
|
||||
<padding>
|
||||
<Insets bottom="10.0" left="15.0" top="7.0" />
|
||||
</padding>
|
||||
<children>
|
||||
<Label id="serverDescription" alignment="TOP_LEFT" contentDisplay="LEFT"
|
||||
nodeOrientation="LEFT_TO_RIGHT" prefHeight="274.0"
|
||||
prefWidth="349.0"
|
||||
text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla convallis magna tellus, in bibendum tortor dignissim non. Phasellus vel tincidunt nulla, eu convallis ligula. Suspendisse ut diam vestibulum, tincidunt neque ut, posuere risus. Pellentesque posuere molestie eros, quis laoreet ante ornare quis. Morbi eu tortor fermentum, iaculis risus sit amet, fringilla augue. Aenean nulla purus, rutrum non sapien et, convallis tincidunt purus. Vivamus a eros pulvinar, dignissim leo lacinia, sodales nulla. Aliquam tortor augue, cursus a rutrum viverra, consequat non tellus. Donec porta nisl sed quam dictum commodo. Sed et vulputate dolor. Morbi ultrices justo vitae convallis semper. Donec sodales velit vel velit faucibus, et scelerisque felis finibus. Sed rutrum lacinia mauris, porta cursus mauris tempor eu. Duis turpis nulla, dictum vitae commodo rhoncus, pretium in turpis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos."
|
||||
textAlignment="JUSTIFY" textFill="#141414" wrapText="true"/>
|
||||
<Label id="serverDescription" alignment="TOP_LEFT" contentDisplay="LEFT" nodeOrientation="LEFT_TO_RIGHT" prefHeight="274.0" prefWidth="349.0" text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla convallis magna tellus, in bibendum tortor dignissim non. Phasellus vel tincidunt nulla, eu convallis ligula. Suspendisse ut diam vestibulum, tincidunt neque ut, posuere risus. Pellentesque posuere molestie eros, quis laoreet ante ornare quis. Morbi eu tortor fermentum, iaculis risus sit amet, fringilla augue. Aenean nulla purus, rutrum non sapien et, convallis tincidunt purus. Vivamus a eros pulvinar, dignissim leo lacinia, sodales nulla. Aliquam tortor augue, cursus a rutrum viverra, consequat non tellus. Donec porta nisl sed quam dictum commodo. Sed et vulputate dolor. Morbi ultrices justo vitae convallis semper. Donec sodales velit vel velit faucibus, et scelerisque felis finibus. Sed rutrum lacinia mauris, porta cursus mauris tempor eu. Duis turpis nulla, dictum vitae commodo rhoncus, pretium in turpis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos." textAlignment="JUSTIFY" textFill="#141414" wrapText="true" />
|
||||
</children>
|
||||
</FlowPane>
|
||||
</content>
|
||||
</ScrollPane>
|
||||
<JFXButton id="clientLaunch" layoutX="19.0" layoutY="380.0" prefHeight="51.0"
|
||||
prefWidth="285.0" styleClass="clientLaunch" text="ИГРАТЬ">
|
||||
<JFXButton id="clientLaunch" layoutX="19.0" layoutY="380.0" prefHeight="51.0" prefWidth="285.0" styleClass="clientLaunch" text="ИГРАТЬ">
|
||||
<font>
|
||||
<Font size="22.0" />
|
||||
</font>
|
||||
</JFXButton>
|
||||
<JFXButton id="clientSettings" alignment="CENTER" centerShape="false"
|
||||
contentDisplay="CENTER" layoutX="305.0" layoutY="380.0" prefHeight="51.0"
|
||||
prefWidth="60.0" ripplerFill="#84da96" styleClass="clientSettings" text=""
|
||||
textAlignment="CENTER">
|
||||
<JFXButton id="clientSettings" alignment="CENTER" centerShape="false" contentDisplay="CENTER" layoutX="305.0" layoutY="380.0" prefHeight="51.0" prefWidth="60.0" ripplerFill="#84da96" styleClass="clientSettings" text="" textAlignment="CENTER">
|
||||
<graphic>
|
||||
<FontAwesomeIconView fill="WHITE" glyphName="SLIDERS" size="30.0" />
|
||||
</graphic>
|
||||
</JFXButton>
|
||||
<Label id="serverStatus" alignment="TOP_RIGHT" contentDisplay="RIGHT" layoutX="165.0"
|
||||
layoutY="12.0" prefHeight="25.0" prefWidth="97.0" text="12/100"
|
||||
textAlignment="RIGHT" textFill="WHITE">
|
||||
</graphic></JFXButton>
|
||||
<Label id="serverStatus" alignment="TOP_RIGHT" contentDisplay="RIGHT" layoutX="165.0" layoutY="12.0" prefHeight="25.0" prefWidth="97.0" text="12/100" textAlignment="RIGHT" textFill="WHITE">
|
||||
<font>
|
||||
<Font name="System Bold" size="16.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Label id="serverLabel" layoutX="20.0" layoutY="11.0" prefHeight="27.0"
|
||||
prefWidth="203.0" text="СЕРВЕР">
|
||||
<Label id="serverLabel" layoutX="20.0" layoutY="11.0" prefHeight="27.0" prefWidth="203.0" text="СЕРВЕР">
|
||||
<font>
|
||||
<Font name="System Bold" size="18.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<JFXButton id="logout" alignment="CENTER" contentDisplay="CENTER" layoutX="295.0"
|
||||
layoutY="12.0" prefHeight="25.0" prefWidth="81.0" ripplerFill="#61616100"
|
||||
text="Выйти" textAlignment="CENTER"/>
|
||||
<JFXButton id="logout" alignment="CENTER" contentDisplay="CENTER" layoutX="295.0" layoutY="12.0" prefHeight="25.0" prefWidth="81.0" ripplerFill="#61616100" text="Выйти" textAlignment="CENTER" />
|
||||
</children>
|
||||
</Pane>
|
||||
</children>
|
||||
</Pane>
|
||||
</children>
|
||||
</Pane>
|
||||
<Pane fx:id="bar" layoutX="696.0" prefHeight="425.0" prefWidth="43.0" styleClass="bar">
|
||||
<Pane fx:id="bar" layoutX="694.0" prefHeight="425.0" prefWidth="43.0" styleClass="bar">
|
||||
<children>
|
||||
<JFXButton id="hide" alignment="CENTER" contentDisplay="CENTER" layoutY="45.0" ripplerFill="#646464"
|
||||
text="" textAlignment="CENTER">
|
||||
<JFXButton id="hide" alignment="CENTER" contentDisplay="CENTER" layoutY="45.0" ripplerFill="#646464" text="" textAlignment="CENTER">
|
||||
<graphic>
|
||||
<MaterialDesignIconView fill="WHITE" glyphName="MINUS" size="30" textAlignment="CENTER" />
|
||||
</graphic>
|
||||
</JFXButton>
|
||||
<JFXButton id="close" alignment="CENTER" contentDisplay="CENTER" ripplerFill="#fb8c8c" text=""
|
||||
textAlignment="CENTER">
|
||||
<JFXButton id="close" alignment="CENTER" contentDisplay="CENTER" ripplerFill="#fb8c8c" text="" textAlignment="CENTER">
|
||||
<graphic>
|
||||
<MaterialDesignIconView fill="WHITE" glyphName="CLOSE" size="30" textAlignment="CENTER" />
|
||||
</graphic>
|
||||
</JFXButton>
|
||||
<JFXButton id="discord" alignment="CENTER" contentDisplay="CENTER" layoutY="380.0" ripplerFill="#646464"
|
||||
text="" textAlignment="CENTER">
|
||||
<JFXButton id="discord" alignment="CENTER" contentDisplay="CENTER" layoutY="380.0" ripplerFill="#646464" text="" textAlignment="CENTER">
|
||||
<graphic>
|
||||
<MaterialDesignIconView fill="#5fd97a" glyphName="MESSAGE_TEXT" size="20" smooth="false"
|
||||
textAlignment="CENTER"/>
|
||||
<MaterialDesignIconView fill="#5fd97a" glyphName="MESSAGE_TEXT" size="20" smooth="false" textAlignment="CENTER" />
|
||||
</graphic>
|
||||
</JFXButton>
|
||||
<JFXButton id="settings" alignment="CENTER" contentDisplay="CENTER" layoutY="90.0" ripplerFill="#646464"
|
||||
text="" textAlignment="CENTER">
|
||||
<JFXButton id="settings" alignment="CENTER" contentDisplay="CENTER" layoutY="90.0" ripplerFill="#646464" text="" textAlignment="CENTER">
|
||||
<graphic>
|
||||
<MaterialDesignIconView fill="WHITE" glyphName="SETTINGS" size="20" textAlignment="CENTER" />
|
||||
</graphic>
|
||||
</JFXButton>
|
||||
<JFXButton id="goConsole" alignment="CENTER" contentDisplay="CENTER" layoutY="138.0"
|
||||
ripplerFill="#646464" text="" textAlignment="CENTER">
|
||||
<JFXButton id="goConsole" alignment="CENTER" contentDisplay="CENTER" layoutY="138.0" ripplerFill="#646464" text="" textAlignment="CENTER">
|
||||
<graphic>
|
||||
<MaterialDesignIconView fill="WHITE" glyphName="CONSOLE" size="20" textAlignment="CENTER" />
|
||||
</graphic>
|
||||
</JFXButton>
|
||||
</children>
|
||||
</Pane>
|
||||
<Pane id="mask" opacity="0.0" prefHeight="425.0" prefWidth="694.0" visible="false"/>
|
||||
<Pane id="mask" opacity="0.0" prefHeight="450.0" prefWidth="694.0" visible="false" />
|
||||
</children>
|
||||
<stylesheets>
|
||||
<URL value="@../../styles.css" />
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import com.jfoenix.controls.JFXButton?>
|
||||
<?import com.jfoenix.controls.JFXToggleButton?>
|
||||
<?import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIconView?>
|
||||
<?import java.net.URL?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
|
@ -9,25 +8,19 @@
|
|||
<?import javafx.scene.layout.Pane?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.shape.Line?>
|
||||
<?import javafx.scene.text.Font?>
|
||||
<?import javafx.scene.text.Text?>
|
||||
|
||||
<!-- DrLeonardo Design -->
|
||||
|
||||
<Pane fx:id="background" prefHeight="450.0" prefWidth="738.0" xmlns="http://javafx.com/javafx/8.0.201"
|
||||
xmlns:fx="http://javafx.com/fxml/1">
|
||||
<Pane fx:id="background" prefHeight="450.0" prefWidth="740.0" xmlns="http://javafx.com/javafx/8.0.201" xmlns:fx="http://javafx.com/fxml/1">
|
||||
<children>
|
||||
<Pane id="optionsPane" prefHeight="450.0" prefWidth="692.0" styleClass="optionsPane">
|
||||
<children>
|
||||
<JFXToggleButton fx:id="presset" layoutX="30.0" layoutY="10.0" opacity="0.21" styleClass="pressetLight"
|
||||
text="Presset 1"/>
|
||||
<JFXToggleButton fx:id="presset" layoutX="287.0" layoutY="10.0" opacity="0.21"
|
||||
styleClass="pressetMedium" text="Presset 2"/>
|
||||
<JFXToggleButton fx:id="isPresset" layoutX="528.0" layoutY="10.0" opacity="0.21" prefHeight="58.0"
|
||||
prefWidth="134.0" styleClass="pressetHigh" text="Presset 3" wrapText="true"/>
|
||||
<Line endX="595.0" layoutX="100.0" layoutY="80.0" startX="-100.0" stroke="#5b3636"
|
||||
styleClass="lineHead"/>
|
||||
<ScrollPane id="modlist" layoutY="84.0" prefHeight="364.0" prefWidth="693.0">
|
||||
<Line endX="595.0" layoutX="100.0" layoutY="46.0" startX="-100.0" stroke="#5b3636" styleClass="lineHead" />
|
||||
<ScrollPane id="modlist" layoutY="46.0" prefHeight="402.0" prefWidth="693.0">
|
||||
<content>
|
||||
<VBox prefHeight="360.0" prefWidth="678.0">
|
||||
<VBox prefHeight="397.0" prefWidth="678.0">
|
||||
<children>
|
||||
</children>
|
||||
<padding>
|
||||
|
@ -36,24 +29,26 @@
|
|||
</VBox>
|
||||
</content>
|
||||
</ScrollPane>
|
||||
<Text fill="#393939" layoutX="15.0" layoutY="28.0" strokeType="OUTSIDE" strokeWidth="0.0" text="ОПЦИОНАЛЬНЫЕ МОДИФИКАЦИИ" wrappingWidth="265.904296875">
|
||||
<font>
|
||||
<Font name="System Bold" size="13.0" />
|
||||
</font>
|
||||
</Text>
|
||||
</children>
|
||||
</Pane>
|
||||
<Pane fx:id="bar" layoutX="692.0" prefHeight="425.0" prefWidth="43.0" styleClass="bar">
|
||||
<Pane fx:id="bar" layoutX="694.0" prefHeight="425.0" prefWidth="43.0" styleClass="bar">
|
||||
<children>
|
||||
<JFXButton id="hide" alignment="CENTER" contentDisplay="CENTER" layoutY="45.0" ripplerFill="#646464"
|
||||
text="" textAlignment="CENTER">
|
||||
<JFXButton id="hide" alignment="CENTER" contentDisplay="CENTER" layoutY="45.0" ripplerFill="#646464" text="" textAlignment="CENTER">
|
||||
<graphic>
|
||||
<MaterialDesignIconView fill="WHITE" glyphName="MINUS" size="30" textAlignment="CENTER" />
|
||||
</graphic>
|
||||
</JFXButton>
|
||||
<JFXButton id="close" alignment="CENTER" contentDisplay="CENTER" ripplerFill="#fb8c8c" text=""
|
||||
textAlignment="CENTER">
|
||||
<JFXButton id="close" alignment="CENTER" contentDisplay="CENTER" ripplerFill="#fb8c8c" text="" textAlignment="CENTER">
|
||||
<graphic>
|
||||
<MaterialDesignIconView fill="WHITE" glyphName="CLOSE" size="30" textAlignment="CENTER" />
|
||||
</graphic>
|
||||
</JFXButton>
|
||||
<JFXButton id="back" alignment="CENTER" contentDisplay="CENTER" layoutY="405.0" ripplerFill="#646464"
|
||||
text="" textAlignment="CENTER">
|
||||
<JFXButton id="back" alignment="CENTER" contentDisplay="CENTER" layoutY="405.0" ripplerFill="#646464" text="" textAlignment="CENTER">
|
||||
<graphic>
|
||||
<MaterialDesignIconView fill="WHITE" glyphName="CHEVRON_LEFT" size="30" textAlignment="CENTER" />
|
||||
</graphic>
|
||||
|
|
|
@ -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**/
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -37,6 +37,10 @@ public class NewLauncherSettings {
|
|||
public List<ClientProfile> lastProfiles = new LinkedList<>();
|
||||
@LauncherAPI
|
||||
public Map<String, UserSettings> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<NewLauncherSettings.HashedStoreEntry> lastEn = new AtomicReference<>(null);
|
||||
ArrayList<String> 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<Path> 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<ListDownloader.DownloadTask> adds) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postDownload(UpdateRequest request, UpdateRequestEvent e) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postUpdate(UpdateRequest request, UpdateRequestEvent e) {
|
||||
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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))) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<DownloadTask> 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<Path> {
|
|||
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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,20 @@
|
|||
import java.util.Objects;
|
||||
|
||||
public final class UpdateRequest extends Request<UpdateRequestEvent> 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<ListDownloader.DownloadTask> 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<ListDownloader.DownloadTask> 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)) {
|
||||
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();
|
||||
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;
|
||||
|
|
|
@ -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<ResultEvent> requests = new HashSet<>();
|
||||
public Set<ResultEvent> requests = ConcurrentHashMap.newKeySet();
|
||||
|
||||
@Override
|
||||
public void process(ResultInterface result) {
|
||||
|
|
|
@ -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<Object> {
|
||||
|
||||
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
|
||||
|
|
|
@ -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<String, HashedEntry> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -75,6 +75,7 @@ public String readLine() throws IOException {
|
|||
try {
|
||||
return reader.readLine();
|
||||
} catch (UserInterruptException e) {
|
||||
System.exit(0);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,8 +113,11 @@ public static void debug(String format, Object... args) {
|
|||
|
||||
@LauncherAPI
|
||||
public static void dev(String format, Object... args) {
|
||||
if(isDevEnabled())
|
||||
{
|
||||
dev(String.format(format, args));
|
||||
}
|
||||
}
|
||||
|
||||
@LauncherAPI
|
||||
public static void error(Throwable exc) {
|
||||
|
|
Loading…
Reference in a new issue