commit
This commit is contained in:
parent
8c41c8392b
commit
13fa56b76f
71
pom.xml
71
pom.xml
@ -55,6 +55,7 @@
|
|||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
<version>1.18.14</version>
|
<version>1.18.14</version>
|
||||||
|
<scope>compile</scope> <!-- 解决 slf4j 冲突问题 -->
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- slf4j -->
|
<!-- slf4j -->
|
||||||
@ -70,12 +71,19 @@
|
|||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- commons-lang3 -->
|
<!-- commons -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.commons</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
<artifactId>commons-lang3</artifactId>
|
<artifactId>commons-lang3</artifactId>
|
||||||
<version>3.12.0</version>
|
<version>3.12.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-io</groupId>
|
||||||
|
<artifactId>commons-io</artifactId>
|
||||||
|
<version>2.11.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.hutool</groupId>
|
<groupId>cn.hutool</groupId>
|
||||||
@ -157,25 +165,60 @@
|
|||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.openjfx</groupId>
|
<groupId>com.zenjava</groupId>
|
||||||
<artifactId>javafx-maven-plugin</artifactId>
|
<artifactId>javafx-maven-plugin</artifactId>
|
||||||
<version>0.0.8</version>
|
<version>8.8.3</version>
|
||||||
|
<configuration>
|
||||||
|
<vendor>analysis</vendor>
|
||||||
|
<mainClass>top.octopusyan.YanFrpLuncher</mainClass>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<version>3.2.0</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<!-- Default configuration for running with: mvn clean javafx:run -->
|
<id>make-assembly</id>
|
||||||
<id>default-cli</id>
|
<!-- 绑定到package生命周期 -->
|
||||||
<configuration>
|
<phase>package</phase>
|
||||||
<mainClass>top.octopusyan/top.octopusyan.YanFrpLauncher</mainClass>
|
<goals>
|
||||||
<launcher>app</launcher>
|
<!-- 只运行一次 -->
|
||||||
<jlinkZipName>app</jlinkZipName>
|
<goal>single</goal>
|
||||||
<jlinkImageName>app</jlinkImageName>
|
</goals>
|
||||||
<noManPages>true</noManPages>
|
|
||||||
<stripDebug>true</stripDebug>
|
|
||||||
<noHeaderFiles>true</noHeaderFiles>
|
|
||||||
</configuration>
|
|
||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<mainClass>top.octopusyan.YanFrpLuncher</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
<descriptorRefs>
|
||||||
|
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||||
|
</descriptorRefs>
|
||||||
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<!-- <plugin>-->
|
||||||
|
<!-- <groupId>org.openjfx</groupId>-->
|
||||||
|
<!-- <artifactId>javafx-maven-plugin</artifactId>-->
|
||||||
|
<!-- <version>0.0.8</version>-->
|
||||||
|
<!-- <executions>-->
|
||||||
|
<!-- <execution>-->
|
||||||
|
<!-- <!– Default configuration for running with: mvn clean javafx:run –>-->
|
||||||
|
<!-- <id>default-cli</id>-->
|
||||||
|
<!-- <configuration>-->
|
||||||
|
<!-- <mainClass>top.octopusyan/top.octopusyan.YanFrpLuncher</mainClass>-->
|
||||||
|
<!-- <launcher>app</launcher>-->
|
||||||
|
<!-- <jlinkZipName>app</jlinkZipName>-->
|
||||||
|
<!-- <jlinkImageName>app</jlinkImageName>-->
|
||||||
|
<!-- <noManPages>true</noManPages>-->
|
||||||
|
<!-- <stripDebug>true</stripDebug>-->
|
||||||
|
<!-- <noHeaderFiles>true</noHeaderFiles>-->
|
||||||
|
<!-- </configuration>-->
|
||||||
|
<!-- </execution>-->
|
||||||
|
<!-- </executions>-->
|
||||||
|
<!-- </plugin>-->
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
@ -1,21 +1,25 @@
|
|||||||
package top.octopusyan;
|
package top.octopusyan;
|
||||||
|
|
||||||
import com.sun.org.slf4j.internal.Logger;
|
|
||||||
import com.sun.org.slf4j.internal.LoggerFactory;
|
|
||||||
import javafx.application.Application;
|
import javafx.application.Application;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
|
import javafx.fxml.JavaFXBuilderFactory;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import javafx.stage.StageStyle;
|
import javafx.stage.StageStyle;
|
||||||
import top.octopusyan.common.http.HttpConfig;
|
import org.slf4j.Logger;
|
||||||
import top.octopusyan.common.http.config.LogStrategy;
|
import org.slf4j.LoggerFactory;
|
||||||
import top.octopusyan.common.http.request.RequestHandler;
|
import top.octopusyan.base.BaseController;
|
||||||
|
import top.octopusyan.manager.http.HttpConfig;
|
||||||
|
import top.octopusyan.manager.http.config.LogStrategy;
|
||||||
|
import top.octopusyan.manager.http.request.RequestHandler;
|
||||||
import top.octopusyan.http.OkHttpClientConfig;
|
import top.octopusyan.http.OkHttpClientConfig;
|
||||||
import top.octopusyan.utils.AlertUtil;
|
import top.octopusyan.utils.AlertUtil;
|
||||||
import top.octopusyan.utils.ApplicatonStore;
|
import top.octopusyan.utils.ApplicatonStore;
|
||||||
|
import top.octopusyan.utils.FrpUtil;
|
||||||
|
import top.octopusyan.utils.FxmlUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author : octopus yan
|
* @author : octopus yan
|
||||||
@ -24,12 +28,15 @@ import top.octopusyan.utils.ApplicatonStore;
|
|||||||
* @create : 2022-3-29 15:00
|
* @create : 2022-3-29 15:00
|
||||||
*/
|
*/
|
||||||
public class YanFrpApplication extends Application {
|
public class YanFrpApplication extends Application {
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(YanFrpApplication.class);
|
private static final Logger logger = LoggerFactory.getLogger(YanFrpApplication.class);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init() throws Exception {
|
public void init() throws Exception {
|
||||||
super.init();
|
super.init();
|
||||||
LOGGER.debug("init...");
|
logger.info("init...");
|
||||||
|
|
||||||
|
// 初始化frp客户端临时文件
|
||||||
|
FrpUtil.initFrpc();
|
||||||
|
|
||||||
// 网络请求设置
|
// 网络请求设置
|
||||||
HttpConfig.with(OkHttpClientConfig.httpClient())
|
HttpConfig.with(OkHttpClientConfig.httpClient())
|
||||||
@ -49,7 +56,7 @@ public class YanFrpApplication extends Application {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage stage) {
|
public void start(Stage stage) {
|
||||||
LOGGER.debug("start...");
|
logger.info("start...");
|
||||||
|
|
||||||
// TODO 全局异常处理... (emm有点草率,先这样了。。)
|
// TODO 全局异常处理... (emm有点草率,先这样了。。)
|
||||||
Thread.setDefaultUncaughtExceptionHandler((t, e) -> Platform.runLater(() -> showErrorDialog(t, e)));
|
Thread.setDefaultUncaughtExceptionHandler((t, e) -> Platform.runLater(() -> showErrorDialog(t, e)));
|
||||||
@ -61,8 +68,12 @@ public class YanFrpApplication extends Application {
|
|||||||
ApplicatonStore.setRegisterSuccess(false);
|
ApplicatonStore.setRegisterSuccess(false);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// 静态写法无法获取controler
|
||||||
|
// StackPane root = new FXMLLoader(this.getClass().getResource("/fxml/login.fxml")).load();//底层面板
|
||||||
|
FXMLLoader fxmlLoader = FxmlUtil.init("/fxml/login.fxml");
|
||||||
|
|
||||||
|
StackPane root = fxmlLoader.load();//底层面板
|
||||||
stage.initStyle(StageStyle.TRANSPARENT);
|
stage.initStyle(StageStyle.TRANSPARENT);
|
||||||
StackPane root = new FXMLLoader(this.getClass().getResource("/fxml/login.fxml")).load();//底层面板
|
|
||||||
Scene scene = new Scene(
|
Scene scene = new Scene(
|
||||||
root,
|
root,
|
||||||
root.getPrefWidth() + 20,
|
root.getPrefWidth() + 20,
|
||||||
@ -73,22 +84,26 @@ public class YanFrpApplication extends Application {
|
|||||||
stage.setScene(scene);
|
stage.setScene(scene);
|
||||||
stage.show();
|
stage.show();
|
||||||
|
|
||||||
|
BaseController controller = fxmlLoader.getController();
|
||||||
|
controller.setApplication(this);
|
||||||
|
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
showErrorDialog(Thread.currentThread(), t);
|
showErrorDialog(Thread.currentThread(), t);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGGER.debug("start end...");
|
logger.debug("start end...");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showErrorDialog(Thread t, Throwable e) {
|
private void showErrorDialog(Thread t, Throwable e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
AlertUtil.exceptionAlert(new Exception(e)).show();
|
Platform.runLater(() -> AlertUtil.exceptionAlert(new Exception(e)).show());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stop() throws Exception {
|
public void stop() throws Exception {
|
||||||
super.stop();
|
super.stop();
|
||||||
LOGGER.debug("stop...");
|
FrpUtil.clearTmp();
|
||||||
|
logger.info("stop...");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
33
src/main/java/top/octopusyan/YanFrpLuncher.java
Normal file
33
src/main/java/top/octopusyan/YanFrpLuncher.java
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package top.octopusyan;
|
||||||
|
|
||||||
|
import javafx.application.Application;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.fxml.FXMLLoader;
|
||||||
|
import javafx.scene.Scene;
|
||||||
|
import javafx.scene.layout.StackPane;
|
||||||
|
import javafx.scene.paint.Color;
|
||||||
|
import javafx.stage.Stage;
|
||||||
|
import javafx.stage.StageStyle;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import top.octopusyan.base.BaseController;
|
||||||
|
import top.octopusyan.http.OkHttpClientConfig;
|
||||||
|
import top.octopusyan.manager.http.HttpConfig;
|
||||||
|
import top.octopusyan.manager.http.config.LogStrategy;
|
||||||
|
import top.octopusyan.manager.http.request.RequestHandler;
|
||||||
|
import top.octopusyan.utils.AlertUtil;
|
||||||
|
import top.octopusyan.utils.ApplicatonStore;
|
||||||
|
import top.octopusyan.utils.FrpUtil;
|
||||||
|
import top.octopusyan.utils.FxmlUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author : octopus yan
|
||||||
|
* @email : octopus_yan@foxmail.com
|
||||||
|
* @description : YanFrp Application
|
||||||
|
* @create : 2022-3-29 15:00
|
||||||
|
*/
|
||||||
|
public class YanFrpLuncher {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Application.launch(YanFrpApplication.class, args);
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package top.octopusyan.base;
|
package top.octopusyan.base;
|
||||||
|
|
||||||
import com.jfoenix.controls.JFXButton;
|
import com.jfoenix.controls.JFXButton;
|
||||||
|
import javafx.application.Application;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
@ -11,6 +12,7 @@ import javafx.scene.layout.Pane;
|
|||||||
import javafx.stage.Stage;
|
import javafx.stage.Stage;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import top.octopusyan.utils.FxmlUtil;
|
||||||
import top.octopusyan.utils.Loading;
|
import top.octopusyan.utils.Loading;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -25,21 +27,35 @@ import java.util.ResourceBundle;
|
|||||||
*/
|
*/
|
||||||
public abstract class BaseController<P extends Pane> implements Initializable {
|
public abstract class BaseController<P extends Pane> implements Initializable {
|
||||||
|
|
||||||
|
private Application application;
|
||||||
|
|
||||||
private double xOffSet = 0, yOffSet = 0;
|
private double xOffSet = 0, yOffSet = 0;
|
||||||
|
|
||||||
private volatile Loading loading;
|
private volatile Loading loading;
|
||||||
|
|
||||||
public void jumpTo(BaseController<P> controller){
|
public void jumpTo(BaseController<P> controller) throws IOException {
|
||||||
|
FXMLLoader fxmlLoader = FxmlUtil.init(controller.getRootFxmlPath());
|
||||||
|
|
||||||
Scene scene = getRootPanel().getScene();
|
Scene scene = getRootPanel().getScene();
|
||||||
try {
|
double oldHeight = getRootPanel().getPrefHeight();
|
||||||
Pane root = FXMLLoader.load(getClass().getResource(controller.getRootFxmlPath()));
|
double oldWidth = getRootPanel().getPrefWidth();
|
||||||
scene.setRoot(root);
|
|
||||||
|
Pane root = fxmlLoader.load();
|
||||||
Stage stage = (Stage) scene.getWindow();
|
Stage stage = (Stage) scene.getWindow();
|
||||||
stage.setWidth(root.getPrefWidth() + 20);
|
// 窗口大小
|
||||||
stage.setHeight(root.getPrefHeight() + 20);
|
double newWidth = root.getPrefWidth() + 20;
|
||||||
} catch (IOException e) {
|
double newHeight = root.getPrefHeight() + 20;
|
||||||
e.printStackTrace();
|
// 窗口位置
|
||||||
}
|
double newX = stage.getX() - (newWidth - oldWidth) / 2;
|
||||||
|
double newY = stage.getY() - (newHeight - oldHeight) / 2;
|
||||||
|
scene.setRoot(root);
|
||||||
|
stage.setX(newX < 0 ? 0 : newX);
|
||||||
|
stage.setY(newY < 0 ? 0 : newY);
|
||||||
|
stage.setWidth(newWidth);
|
||||||
|
stage.setHeight(newHeight);
|
||||||
|
|
||||||
|
controller = fxmlLoader.getController();
|
||||||
|
controller.setApplication(getApplication());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -96,6 +112,14 @@ public abstract class BaseController<P extends Pane> implements Initializable {
|
|||||||
loading.show();
|
loading.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setApplication(Application application) {
|
||||||
|
this.application = application;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Application getApplication() {
|
||||||
|
return application;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isLoadShowing() {
|
public boolean isLoadShowing() {
|
||||||
return loading != null && loading.showing();
|
return loading != null && loading.showing();
|
||||||
}
|
}
|
||||||
@ -163,7 +187,12 @@ public abstract class BaseController<P extends Pane> implements Initializable {
|
|||||||
Stage stage = (Stage) getRootPanel().getScene().getWindow();
|
Stage stage = (Stage) getRootPanel().getScene().getWindow();
|
||||||
stage.hide();
|
stage.hide();
|
||||||
stage.close();
|
stage.close();
|
||||||
|
try {
|
||||||
|
Thread.sleep(2000);
|
||||||
Platform.exit();
|
Platform.exit();
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
package top.octopusyan.common;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author : octopus yan
|
|
||||||
* @email : octopus_yan@foxmail.com
|
|
||||||
* @description : test
|
|
||||||
* @create : 2022-4-1 23:36
|
|
||||||
*/
|
|
||||||
public class test {
|
|
||||||
}
|
|
@ -1,5 +1,9 @@
|
|||||||
package top.octopusyan.config;
|
package top.octopusyan.config;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -10,14 +14,19 @@ import java.util.Map;
|
|||||||
* @create : 2022-4-5 18:14
|
* @create : 2022-4-5 18:14
|
||||||
*/
|
*/
|
||||||
public class ProxyConfig {
|
public class ProxyConfig {
|
||||||
private static Map<String, String> serverPath = new HashMap<>();
|
private static final Map<String, String> serverPath = new HashMap<>();
|
||||||
private static Map<String, Integer> typePort = new HashMap<>();
|
private static final Map<String, String> serverIp = new HashMap<>();
|
||||||
|
private static final Map<String, Integer> typePort = new HashMap<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
serverPath.put("香港", "xg.frp.octopusyan.top");
|
serverPath.put("香港", "xg.frp.octopusyan.top");
|
||||||
serverPath.put("北京", "bj.frp.octopusyan.top");
|
serverPath.put("北京", "bj.frp.octopusyan.top");
|
||||||
serverPath.put("上海", "frp.octopusyan.top");
|
serverPath.put("上海", "frp.octopusyan.top");
|
||||||
|
|
||||||
|
serverIp.put("香港", "101.32.202.135");
|
||||||
|
serverIp.put("北京", "112.125.120.135");
|
||||||
|
serverIp.put("上海", "81.68.214.67");
|
||||||
|
|
||||||
typePort.put("http", 80);
|
typePort.put("http", 80);
|
||||||
typePort.put("https", 80);
|
typePort.put("https", 80);
|
||||||
typePort.put("ssh", 22);
|
typePort.put("ssh", 22);
|
||||||
@ -25,8 +34,25 @@ public class ProxyConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Getter
|
||||||
public enum ProxyServer {
|
public enum ProxyServer {
|
||||||
香港, 北京, 上海
|
xg("香港", 1),
|
||||||
|
bj("北京", 2),
|
||||||
|
sh("上海", 3);
|
||||||
|
private final String serverName;
|
||||||
|
private final int value;
|
||||||
|
|
||||||
|
ProxyServer(String serverName, int value) {
|
||||||
|
this.serverName = serverName;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ProxyServer valueOf(int node) {
|
||||||
|
for (ProxyServer value : values()) {
|
||||||
|
if (value.value == node) return value;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ProxyType {
|
public enum ProxyType {
|
||||||
@ -36,7 +62,7 @@ public class ProxyConfig {
|
|||||||
TCP("tcp"),
|
TCP("tcp"),
|
||||||
;
|
;
|
||||||
|
|
||||||
private String type;
|
private final String type;
|
||||||
|
|
||||||
public String getType() {
|
public String getType() {
|
||||||
return type;
|
return type;
|
||||||
@ -51,7 +77,49 @@ public class ProxyConfig {
|
|||||||
return serverPath.get(serverName);
|
return serverPath.get(serverName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int getServerNode(String serverName) {
|
||||||
|
for (ProxyServer server : Arrays.asList(ProxyServer.values())) {
|
||||||
|
if(server.serverName.equals(serverName)) return server.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取服务名称
|
||||||
|
* @param node 服务器标签
|
||||||
|
*/
|
||||||
|
public static String getServerName(int node) {
|
||||||
|
ProxyServer proxyServer = ProxyServer.valueOf(node);
|
||||||
|
assert proxyServer != null;
|
||||||
|
return proxyServer.getServerName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取服务器IP地址
|
||||||
|
* @param serverName 服务器名称
|
||||||
|
*/
|
||||||
|
public static String getServerIP(String serverName) {
|
||||||
|
return serverIp.get(serverName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取服务器IP地址
|
||||||
|
* @param node 服务器标签
|
||||||
|
*/
|
||||||
|
public static String getServerIP(int node) {
|
||||||
|
return serverIp.get(getServerName(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取代理类型默认端口
|
||||||
|
* @param type 类型名称
|
||||||
|
*/
|
||||||
public static Integer getTypePort(String type) {
|
public static Integer getTypePort(String type) {
|
||||||
return typePort.get(type);
|
return typePort.get(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Integer getTypeIndex(String type) {
|
||||||
|
return Arrays.asList(ProxyType.values()).indexOf(ProxyType.valueOf(StringUtils.upperCase(type)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
155
src/main/java/top/octopusyan/config/TextValidate.java
Normal file
155
src/main/java/top/octopusyan/config/TextValidate.java
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
package top.octopusyan.config;
|
||||||
|
|
||||||
|
import com.jfoenix.validation.RegexValidator;
|
||||||
|
import com.jfoenix.validation.RequiredFieldValidator;
|
||||||
|
import com.jfoenix.validation.StringLengthValidator;
|
||||||
|
import com.jfoenix.validation.base.ValidatorBase;
|
||||||
|
import top.octopusyan.config.ProxyConfig;
|
||||||
|
import top.octopusyan.model.ProxySetupModel;
|
||||||
|
import top.octopusyan.utils.DomainUtil;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author : octopus yan
|
||||||
|
* @email : octopus_yan@foxmail.com
|
||||||
|
* @description : JFX文本校验
|
||||||
|
* @create : 2022-4-2 17:03
|
||||||
|
*/
|
||||||
|
public class TextValidate {
|
||||||
|
// /**
|
||||||
|
// * 账号格式错误
|
||||||
|
// */
|
||||||
|
// public static ValidatorBase AccountFail = new ValidatorBase() {
|
||||||
|
// @Override
|
||||||
|
// protected void eval() {
|
||||||
|
// setMessage("账号格式错误");
|
||||||
|
// hasErrors.set(true);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 账号不能为空
|
||||||
|
*/
|
||||||
|
public static RequiredFieldValidator AccoountRequired = new RequiredFieldValidator("账号不能为空!");
|
||||||
|
/**
|
||||||
|
* 账号格式
|
||||||
|
*/
|
||||||
|
public static RegexValidator AccoountValidator = new RegexValidator("账号格式有误!");
|
||||||
|
/**
|
||||||
|
* 密码不能为空
|
||||||
|
*/
|
||||||
|
public static RequiredFieldValidator PasswordRequired = new RequiredFieldValidator("密码不能为空!");
|
||||||
|
/**
|
||||||
|
* 邮箱地址格式验证
|
||||||
|
*/
|
||||||
|
public static RegexValidator EmailFormat = new RegexValidator("邮箱地址格式错误");
|
||||||
|
/**
|
||||||
|
* 域名为空检查
|
||||||
|
*/
|
||||||
|
public static RequiredFieldValidator DomainRequired = new RequiredFieldValidator("域名不能为空!");
|
||||||
|
/**
|
||||||
|
* 端口为空检查
|
||||||
|
*/
|
||||||
|
public static RequiredFieldValidator PortRequired = new RequiredFieldValidator("端口不能为空");
|
||||||
|
/**
|
||||||
|
* 端口格式检查
|
||||||
|
*/
|
||||||
|
public static final RegexValidator PortFormat = new RegexValidator("端口格式错误");
|
||||||
|
/**
|
||||||
|
* IP为空检查
|
||||||
|
*/
|
||||||
|
public static RequiredFieldValidator IpRequired = new RequiredFieldValidator("本地IP不能为空");
|
||||||
|
/**
|
||||||
|
* IP格式检查
|
||||||
|
*/
|
||||||
|
public static final RegexValidator IpFormat = new RegexValidator("本地IP格式错误");
|
||||||
|
|
||||||
|
static {
|
||||||
|
EmailFormat.setRegexPattern("^\\s*\\w+(?:\\.{0,1}[\\w-]+)*@[a-zA-Z0-9]+(?:[-.][a-zA-Z0-9]+)*\\.[a-zA-Z]+\\s*$");
|
||||||
|
AccoountValidator.setRegexPattern("^[a-zA-Z0-9_-]*$");
|
||||||
|
PortFormat.setRegexPattern("^([0-9]|[1-9]\\d{1,3}|[1-5]\\d{4}|6[0-4]\\d{4}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5])$");
|
||||||
|
IpFormat.setRegexPattern("^(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])$");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文本长度校验
|
||||||
|
* <p/> message > name + "长度有误"
|
||||||
|
*/
|
||||||
|
public static StringLengthValidator getLengthValidator(String name, int length) {
|
||||||
|
return new StringLengthValidator(name + "长度有误", length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文本长度校验
|
||||||
|
* <p/> message > name + "长度有误,应在" + min + "到" + max + "之间"
|
||||||
|
*/
|
||||||
|
public static RegexValidator getLengthValidator(int min, int max, String name) {
|
||||||
|
String message = name + "长度有误,应在" + min + "到" + max + "之间";
|
||||||
|
|
||||||
|
RegexValidator validator = new RegexValidator(message);
|
||||||
|
|
||||||
|
validator.setRegexPattern("[a-zA-Z0-9_-]{" + min + "," + max + "}$");
|
||||||
|
|
||||||
|
return validator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 域名格式检查
|
||||||
|
*/
|
||||||
|
public static ValidatorBase domainFormatValidator(ProxySetupModel model) {
|
||||||
|
|
||||||
|
return new ValidatorBase("域名格式错误") {
|
||||||
|
@Override
|
||||||
|
protected void eval() {
|
||||||
|
if (!DomainUtil.isCustomize(model.get()))
|
||||||
|
hasErrors.set(false);
|
||||||
|
else {
|
||||||
|
boolean matches = Pattern.compile("^(?=^.{3,255}$)[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+$")
|
||||||
|
.matcher(model.getDomain() + model.getDomainSuffix()).matches();
|
||||||
|
hasErrors.set(!matches);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 域名格式检查
|
||||||
|
*/
|
||||||
|
public static ValidatorBase domainLengthValidator(ProxySetupModel model) {
|
||||||
|
|
||||||
|
return new RegexValidator("请输入子域名,长度不小于3个字符") {
|
||||||
|
@Override
|
||||||
|
protected void eval() {
|
||||||
|
setRegexPattern("^[a-zA-Z0-9_-]{3,18}$");
|
||||||
|
if (DomainUtil.isHttp(model) && !DomainUtil.isCustomize(model.get())) {
|
||||||
|
super.eval();
|
||||||
|
} else {
|
||||||
|
hasErrors.set(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义域名解析检查
|
||||||
|
*/
|
||||||
|
public static ValidatorBase domainAddressValidator(ProxySetupModel model) {
|
||||||
|
|
||||||
|
return new ValidatorBase("请输入您的域名,并解析至: " + ProxyConfig.getServerIP(model.getServer())) {
|
||||||
|
@Override
|
||||||
|
protected void eval() {
|
||||||
|
if (!DomainUtil.isCustomize(model.get()))
|
||||||
|
hasErrors.set(false);
|
||||||
|
else
|
||||||
|
hasErrors.set(
|
||||||
|
!Objects.equals(
|
||||||
|
ProxyConfig.getServerIP(model.getServer()),
|
||||||
|
DomainUtil.getDomainAddress(model.getDomain())
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -5,39 +5,28 @@ import com.jfoenix.controls.JFXCheckBox;
|
|||||||
import com.jfoenix.controls.JFXPasswordField;
|
import com.jfoenix.controls.JFXPasswordField;
|
||||||
import com.jfoenix.controls.JFXTextField;
|
import com.jfoenix.controls.JFXTextField;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
import javafx.event.EventHandler;
|
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
import javafx.scene.control.Button;
|
import javafx.scene.control.Button;
|
||||||
import javafx.scene.image.ImageView;
|
import javafx.scene.image.ImageView;
|
||||||
import javafx.scene.input.KeyCode;
|
import javafx.scene.input.KeyCode;
|
||||||
import javafx.scene.input.MouseEvent;
|
|
||||||
import javafx.scene.layout.AnchorPane;
|
import javafx.scene.layout.AnchorPane;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jsoup.Jsoup;
|
|
||||||
import org.jsoup.nodes.Document;
|
|
||||||
import org.jsoup.select.Elements;
|
|
||||||
import org.kordamp.ikonli.javafx.FontIcon;
|
import org.kordamp.ikonli.javafx.FontIcon;
|
||||||
import top.octopusyan.base.BaseController;
|
import top.octopusyan.base.BaseController;
|
||||||
import top.octopusyan.common.http.EasyHttp;
|
import top.octopusyan.manager.http.EasyHttp;
|
||||||
import top.octopusyan.common.http.api.NotParamApi;
|
import top.octopusyan.manager.http.api.NotParamApi;
|
||||||
import top.octopusyan.common.http.config.HttpConstant;
|
import top.octopusyan.manager.http.config.HttpConstant;
|
||||||
import top.octopusyan.common.http.listener.OnHttpListener;
|
import top.octopusyan.manager.http.listener.OnHttpListener;
|
||||||
|
import top.octopusyan.config.TextValidate;
|
||||||
import top.octopusyan.http.Api;
|
import top.octopusyan.http.Api;
|
||||||
import top.octopusyan.http.request.LoginParam;
|
import top.octopusyan.http.request.LoginParam;
|
||||||
import top.octopusyan.http.request.ProxySetup;
|
import top.octopusyan.utils.*;
|
||||||
import top.octopusyan.utils.AlertUtil;
|
|
||||||
import top.octopusyan.utils.ApplicatonStore;
|
|
||||||
import top.octopusyan.utils.ProxyUtil;
|
|
||||||
import top.octopusyan.utils.TextValidate;
|
|
||||||
|
|
||||||
import java.net.URL;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
|
||||||
import java.util.ResourceBundle;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author : octopus yan
|
* @author : octopus yan
|
||||||
@ -172,7 +161,13 @@ public class LoginController extends BaseController<StackPane> implements Initia
|
|||||||
public void initViewAction() {
|
public void initViewAction() {
|
||||||
|
|
||||||
// 注册
|
// 注册
|
||||||
registerBtn.setOnMouseClicked(event -> jumpTo(new RegisterController()));
|
registerBtn.setOnMouseClicked(event -> {
|
||||||
|
try {
|
||||||
|
jumpTo(new RegisterController());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// 查看密码
|
// 查看密码
|
||||||
seePwdIconBtn.setOnMouseClicked(event -> {
|
seePwdIconBtn.setOnMouseClicked(event -> {
|
||||||
@ -203,6 +198,7 @@ public class LoginController extends BaseController<StackPane> implements Initia
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void login() {
|
private void login() {
|
||||||
|
|
||||||
// 获取文本校验结果
|
// 获取文本校验结果
|
||||||
boolean pwdValidate = pwdParent.getChildren().contains(passwordTextField) ?
|
boolean pwdValidate = pwdParent.getChildren().contains(passwordTextField) ?
|
||||||
passwordTextField.validate() : seePwdTextField.validate();
|
passwordTextField.validate() : seePwdTextField.validate();
|
||||||
@ -215,15 +211,20 @@ public class LoginController extends BaseController<StackPane> implements Initia
|
|||||||
.request(new OnHttpListener<String>() {
|
.request(new OnHttpListener<String>() {
|
||||||
@Override
|
@Override
|
||||||
public void onSucceed(String result) {
|
public void onSucceed(String result) {
|
||||||
Document html = Jsoup.parse(result);
|
|
||||||
// 登录出错
|
// 登录出错
|
||||||
if (result.contains("alert-danger")) {
|
if (!JsoupUtil.isAlertSuccess(result)) {
|
||||||
Platform.runLater(() -> AlertUtil.error(getHtmlErrorMessage(html)).show());
|
Platform.runLater(() -> AlertUtil.error(JsoupUtil.getErrorMessage(result)).show());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// TODO 登录成功
|
// TODO 登录成功
|
||||||
setCsrf();
|
setCsrf();
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
try {
|
||||||
jumpTo(new MainController());
|
jumpTo(new MainController());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -242,10 +243,6 @@ public class LoginController extends BaseController<StackPane> implements Initia
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getHtmlErrorMessage(Document html) {
|
|
||||||
return html.body().getElementsByClass("alert alert-danger alert-dismissable").text().substring(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
EasyHttp.cancel();
|
EasyHttp.cancel();
|
||||||
|
@ -1,14 +1,22 @@
|
|||||||
package top.octopusyan.controller;
|
package top.octopusyan.controller;
|
||||||
|
|
||||||
import com.jfoenix.controls.*;
|
import com.jfoenix.controls.*;
|
||||||
|
import com.jfoenix.validation.IntegerValidator;
|
||||||
|
import com.jfoenix.validation.RequiredFieldValidator;
|
||||||
|
import javafx.application.HostServices;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
|
import javafx.beans.property.SimpleIntegerProperty;
|
||||||
import javafx.beans.value.ChangeListener;
|
import javafx.beans.value.ChangeListener;
|
||||||
import javafx.beans.value.ObservableValue;
|
import javafx.beans.value.ObservableValue;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.event.EventHandler;
|
||||||
import javafx.fxml.FXML;
|
import javafx.fxml.FXML;
|
||||||
import javafx.fxml.FXMLLoader;
|
import javafx.fxml.FXMLLoader;
|
||||||
import javafx.fxml.Initializable;
|
import javafx.fxml.Initializable;
|
||||||
import javafx.scene.control.*;
|
import javafx.scene.control.*;
|
||||||
|
import javafx.scene.control.Button;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
import javafx.scene.input.MouseEvent;
|
import javafx.scene.input.MouseEvent;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
@ -19,13 +27,18 @@ import top.octopusyan.config.ProxyConfig;
|
|||||||
import top.octopusyan.config.ProxyConfig.ProxyServer;
|
import top.octopusyan.config.ProxyConfig.ProxyServer;
|
||||||
import top.octopusyan.config.ProxyConfig.ProxyType;
|
import top.octopusyan.config.ProxyConfig.ProxyType;
|
||||||
import top.octopusyan.http.request.ProxySetup;
|
import top.octopusyan.http.request.ProxySetup;
|
||||||
|
import top.octopusyan.model.ProxySetupModel;
|
||||||
import top.octopusyan.utils.AlertUtil;
|
import top.octopusyan.utils.AlertUtil;
|
||||||
import top.octopusyan.utils.ApplicatonStore;
|
import top.octopusyan.utils.DomainUtil;
|
||||||
|
import top.octopusyan.utils.FrpUtil;
|
||||||
import top.octopusyan.utils.ProxyUtil;
|
import top.octopusyan.utils.ProxyUtil;
|
||||||
|
import top.octopusyan.config.TextValidate;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.datatransfer.Clipboard;
|
||||||
|
import java.awt.datatransfer.StringSelection;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,6 +53,9 @@ public class MainController extends BaseController<StackPane> implements Initial
|
|||||||
public static final String PROXY_LIST_ITEM_STOP_CLASS = "proxyListItem-stop";
|
public static final String PROXY_LIST_ITEM_STOP_CLASS = "proxyListItem-stop";
|
||||||
public static final String PROXY_LIST_ITEM_RUN_CLASS = "proxyListItem-run";
|
public static final String PROXY_LIST_ITEM_RUN_CLASS = "proxyListItem-run";
|
||||||
public static final String PROXY_LIST_ITEM_CLOSE_CLASS = "proxyListItem-close";
|
public static final String PROXY_LIST_ITEM_CLOSE_CLASS = "proxyListItem-close";
|
||||||
|
public static final String PROXY_LIST_ITEM_SELECT_CLASS = "proxyListItem-select";
|
||||||
|
public static final String INPUT_LEFT_CLASS = "inputText-left";
|
||||||
|
public static final String INPUT_CLASS = "inputText";
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public StackPane root;
|
public StackPane root;
|
||||||
@ -48,11 +64,9 @@ public class MainController extends BaseController<StackPane> implements Initial
|
|||||||
public JFXButton closeBtn, minimizeBtn;
|
public JFXButton closeBtn, minimizeBtn;
|
||||||
|
|
||||||
@FXML
|
@FXML
|
||||||
public JFXButton startProxyBtn;
|
public JFXButton startProxyBtn, addProxyBtn;
|
||||||
@FXML
|
@FXML
|
||||||
public JFXButton addProxyBtn;
|
public JFXComboBox<String> proxyProtocolComboBox;
|
||||||
@FXML
|
|
||||||
public JFXComboBox<Label> proxyProtocolCombox;
|
|
||||||
@FXML
|
@FXML
|
||||||
public JFXButton customizeDomainBtn;
|
public JFXButton customizeDomainBtn;
|
||||||
@FXML
|
@FXML
|
||||||
@ -62,17 +76,32 @@ public class MainController extends BaseController<StackPane> implements Initial
|
|||||||
@FXML
|
@FXML
|
||||||
public JFXTextField proxyNameTextField, localHostTextField, localPortTextField;
|
public JFXTextField proxyNameTextField, localHostTextField, localPortTextField;
|
||||||
@FXML
|
@FXML
|
||||||
public JFXComboBox<Label> proxyServerCB;
|
public JFXComboBox<String> proxyServerComboBox;
|
||||||
@FXML
|
@FXML
|
||||||
public JFXTabPane tabPane;
|
public JFXTabPane tabPane;
|
||||||
@FXML
|
@FXML
|
||||||
public JFXListView<Label> proxyListView;
|
public JFXListView<Label> proxyListView;
|
||||||
|
@FXML
|
||||||
|
public Label domainHtinTextField;
|
||||||
|
@FXML
|
||||||
|
public HBox domainPane;
|
||||||
|
@FXML
|
||||||
|
public JFXButton resetProxyBtn, clearLogBtn, copyDomainBtn;
|
||||||
|
@FXML
|
||||||
|
public Tab proxyLogPane;
|
||||||
|
@FXML
|
||||||
|
public Hyperlink domainLink;
|
||||||
|
@FXML
|
||||||
|
public HBox proxyStatusPane;
|
||||||
|
|
||||||
private ToggleGroup openProxyGroup = new ToggleGroup();
|
private ToggleGroup openProxyGroup = new ToggleGroup();
|
||||||
private boolean customizeDomain = false;
|
private SimpleBooleanProperty customizeDomain = new SimpleBooleanProperty(false);
|
||||||
private List<ProxySetup> proxyList;
|
private List<ProxySetup> proxyList = new ArrayList<>();
|
||||||
private int selectProxy = 0;
|
private Map<String, FrpUtil> frpUtilMap = new HashMap<>();
|
||||||
|
private SimpleIntegerProperty selectProxy = new SimpleIntegerProperty(0);
|
||||||
|
private ProxySetupModel proxySetupModel;
|
||||||
private ProxySetup proxySetup;
|
private ProxySetup proxySetup;
|
||||||
|
private SimpleBooleanProperty setting = new SimpleBooleanProperty(false);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean dragWindow() {
|
public boolean dragWindow() {
|
||||||
@ -107,194 +136,294 @@ public class MainController extends BaseController<StackPane> implements Initial
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initData() {
|
public void initData() {
|
||||||
|
// 初始化视图模型
|
||||||
|
proxySetup = ProxyUtil.initProxy(null);
|
||||||
|
proxySetupModel = new ProxySetupModel(proxySetup);
|
||||||
|
|
||||||
// 隧道类型
|
// 隧道类型
|
||||||
Arrays.asList(ProxyType.values()).forEach((type) -> proxyProtocolCombox.getItems().add(new Label(type.name())));
|
Arrays.asList(ProxyType.values()).forEach((type) -> proxyProtocolComboBox.getItems().add(type.name()));
|
||||||
|
|
||||||
// 服务器
|
// 服务器
|
||||||
Arrays.asList(ProxyServer.values()).forEach((server) -> proxyServerCB.getItems().add(new Label(server.name())));
|
Arrays.asList(ProxyServer.values()).forEach((server) -> proxyServerComboBox.getItems().add(server.getServerName()));
|
||||||
|
|
||||||
// 获取用户隧道列表
|
// 获取用户隧道列表
|
||||||
ProxyUtil.getList(setupList -> {
|
ProxyUtil.getList(setupList -> {
|
||||||
|
|
||||||
|
if (setupList != null)
|
||||||
proxyList = setupList;
|
proxyList = setupList;
|
||||||
|
|
||||||
// 主线程执行
|
// 如果用户隧道列表不为空
|
||||||
Platform.runLater(() -> {
|
|
||||||
// 设置隧道列表
|
|
||||||
ApplicatonStore.setProxySetupList(proxyList);
|
|
||||||
|
|
||||||
// 初始化隧道设置
|
|
||||||
if (proxyList != null && proxyList.size() > 0) {
|
if (proxyList != null && proxyList.size() > 0) {
|
||||||
// 显示隧道列表
|
// 显示隧道列表
|
||||||
initProxyList(proxyList);
|
initProxyList(proxyList);
|
||||||
// 显示隧道设置
|
// 默认选中第一个(配置隧道设置模型)
|
||||||
proxySetup = proxyList.get(0);
|
|
||||||
// 默认选中第一个
|
|
||||||
proxyListView.getSelectionModel().select(0);
|
proxyListView.getSelectionModel().select(0);
|
||||||
} else {
|
} else {
|
||||||
proxySetup = ProxyUtil.initProxy();
|
// 配置隧道设置模型
|
||||||
proxyList = new ArrayList<>();
|
proxyList = new ArrayList<>();
|
||||||
proxyList.add(proxySetup);
|
proxyList.add(proxySetup);
|
||||||
initProxySetupView(proxySetup);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
/* 数据绑定 */
|
||||||
|
|
||||||
|
// 服务器
|
||||||
|
proxyServerComboBox.valueProperty().bindBidirectional(proxySetupModel.serverProperty());
|
||||||
|
// 隧道名称
|
||||||
|
proxyNameTextField.textProperty().bindBidirectional(proxySetupModel.proxyNameProperty());
|
||||||
|
// 隧道类型
|
||||||
|
proxyProtocolComboBox.valueProperty().bindBidirectional(proxySetupModel.proxyTypeProperty());
|
||||||
|
// 内网地址
|
||||||
|
localHostTextField.textProperty().bindBidirectional(proxySetupModel.localIpProperty());
|
||||||
|
// 内网端口
|
||||||
|
localPortTextField.textProperty().bindBidirectional(proxySetupModel.localPortProperty());
|
||||||
|
// 外网访问子域名
|
||||||
|
domainTextField.textProperty().bindBidirectional(proxySetupModel.domainProperty());
|
||||||
|
// 外网访问主域名
|
||||||
|
domainSuffixTextField.textProperty().bindBidirectional(proxySetupModel.domainSuffixProperty());
|
||||||
|
// 是否自定义访问域名
|
||||||
|
customizeDomain.bindBidirectional(proxySetupModel.isCustomizeProperty());
|
||||||
|
// 启动成功提示
|
||||||
|
proxyStatusPane.visibleProperty().bindBidirectional(proxySetupModel.runningProperty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initViewStyle() {
|
public void initViewStyle() {
|
||||||
// 启用链接
|
// 启用链接
|
||||||
openProxyRBtn.setToggleGroup(openProxyGroup);
|
openProxyRBtn.setToggleGroup(openProxyGroup);
|
||||||
openProxyRBtn.setSelected(true);
|
|
||||||
closeProxyRBtn.setToggleGroup(openProxyGroup);
|
closeProxyRBtn.setToggleGroup(openProxyGroup);
|
||||||
openProxyRBtn.setUserData(true);
|
openProxyRBtn.setUserData(true);
|
||||||
closeProxyRBtn.setUserData(false);
|
closeProxyRBtn.setUserData(false);
|
||||||
|
openProxyRBtn.setSelected(true);
|
||||||
|
|
||||||
// 默认展示 常见问题
|
// 是否启用
|
||||||
tabPane.getSelectionModel().select(1);
|
proxySetupModel.statusProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
}
|
openProxyRBtn.setSelected(newValue);
|
||||||
|
closeProxyRBtn.setSelected(!newValue);
|
||||||
/**
|
closeProxy(!newValue);
|
||||||
* 设置外网访问域名
|
});
|
||||||
*/
|
proxySetupModel.proxyTypeProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
private void setDomain(ProxySetup setup) {
|
String newType = StringUtils.lowerCase(newValue);
|
||||||
|
String port, host;
|
||||||
if (setup != null) {
|
if (!newType.equals(proxySetup.getProxy_type())) {
|
||||||
String serverName = ProxyServer.values()[setup.getNode()].name();
|
host = "127.0.0.1";
|
||||||
String setupDomain = setup.getDomain();
|
port = ProxyConfig.getTypePort(newType).toString();
|
||||||
String domain = setupDomain;
|
|
||||||
String serverPath = ProxyConfig.getServerPath(serverName);
|
|
||||||
// 是否自定义
|
|
||||||
customizeDomain = setupDomain.contains(serverPath);
|
|
||||||
if (customizeDomain) domain = setupDomain.substring(0, setupDomain.indexOf("." + serverPath));
|
|
||||||
domainSuffixTextField.setText("." + serverPath);
|
|
||||||
domainTextField.setText(domain);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!customizeDomain) {
|
|
||||||
domainTextField.styleProperty().set("-fx-border-radius: 5");
|
|
||||||
domainSuffixTextField.setVisible(false);
|
|
||||||
domainTextField.setText("");
|
|
||||||
customizeDomainBtn.setText("系统分配");
|
|
||||||
} else {
|
} else {
|
||||||
domainTextField.styleProperty().set("-fx-border-radius: 5 0 0 5");
|
host = proxySetupModel.getLocalIp();
|
||||||
domainSuffixTextField.setVisible(true);
|
port = proxySetupModel.getLocalPort();
|
||||||
customizeDomainBtn.setText("自定义");
|
|
||||||
}
|
}
|
||||||
|
// 域名提示
|
||||||
|
domainPane.setVisible(DomainUtil.isHttp(proxySetupModel));
|
||||||
|
|
||||||
|
// 设置
|
||||||
|
localHostTextField.setText(host);
|
||||||
|
localPortTextField.setText(port);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 隧道名称
|
||||||
|
proxySetupModel.proxyNameProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
|
proxyListView.getItems().get(selectProxy.get()).setText(newValue);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 运行状态监听
|
||||||
|
proxySetupModel.runningProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
|
String startClass = "startProxyBtn";
|
||||||
|
String stopClass = "stopProxyBtn";
|
||||||
|
// 启动按钮
|
||||||
|
startProxyBtn.getStyleClass().remove(startClass);
|
||||||
|
startProxyBtn.getStyleClass().remove(stopClass);
|
||||||
|
startProxyBtn.getStyleClass().add(newValue ? stopClass : startClass);
|
||||||
|
startProxyBtn.setText(newValue ? "停止" : "启动");
|
||||||
|
// 列表显示
|
||||||
|
ObservableList<String> styleClass = proxyListView.getItems().get(selectProxy.get()).getStyleClass();
|
||||||
|
styleClass.remove(PROXY_LIST_ITEM_RUN_CLASS);
|
||||||
|
styleClass.remove(PROXY_LIST_ITEM_STOP_CLASS);
|
||||||
|
styleClass.add(newValue ? PROXY_LIST_ITEM_RUN_CLASS : PROXY_LIST_ITEM_STOP_CLASS);
|
||||||
|
|
||||||
|
// 外网访问连接
|
||||||
|
if (DomainUtil.isHttp(proxySetupModel)) {
|
||||||
|
// http / TODO https
|
||||||
|
// String prefix = DomainUtil.isHttps(proxySetupModel) ? "https://" : "http://";
|
||||||
|
// domainLink.textProperty().set(prefix + proxySetupModel.getDomain() + proxySetupModel.getDomainSuffix());
|
||||||
|
domainLink.textProperty().set(proxySetupModel.getDomain() + proxySetupModel.getDomainSuffix());
|
||||||
|
} else {
|
||||||
|
// ssh / tcp
|
||||||
|
domainLink.textProperty().set(ProxyConfig.getServerIP(ProxyConfig.getServerNode(proxySetupModel.getServer())) + ":" + proxySetupModel.getRemotePort());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 自定义外网访问地址按钮
|
||||||
|
customizeDomain.addListener((observable, oldValue, newValue) -> {
|
||||||
|
HBox parent = (HBox) domainTextField.getParent();
|
||||||
|
ObservableList<String> styleClass = domainTextField.getStyleClass();
|
||||||
|
styleClass.remove(INPUT_LEFT_CLASS);
|
||||||
|
styleClass.remove(INPUT_CLASS);
|
||||||
|
// 是否切换为自定义域名
|
||||||
|
if (newValue) {
|
||||||
|
// 隐藏系统域名
|
||||||
|
if (parent.getChildren().contains(domainSuffixTextField))
|
||||||
|
parent.getChildren().remove(domainSuffixTextField);
|
||||||
|
// 用户域名是否自定义
|
||||||
|
if (!DomainUtil.isCustomize(proxySetup)) {
|
||||||
|
proxySetupModel.setDomain("");
|
||||||
|
} else {
|
||||||
|
proxySetupModel.setDomain(proxySetup.getDomain());
|
||||||
|
}
|
||||||
|
proxySetupModel.setDomainSuffix("");
|
||||||
|
styleClass.add(INPUT_CLASS);
|
||||||
|
domainTextField.promptTextProperty().set("自定义域名");
|
||||||
|
customizeDomainBtn.setText("系统分配");
|
||||||
|
domainHtinTextField.setText("请输入您的域名,并解析至: " + ProxyConfig.getServerIP(proxySetupModel.getServer()));
|
||||||
|
} else {
|
||||||
|
// 显示系统域名
|
||||||
|
if (!parent.getChildren().contains(domainSuffixTextField))
|
||||||
|
parent.getChildren().add(domainSuffixTextField);
|
||||||
|
// 用户域名是否自定义
|
||||||
|
if (DomainUtil.isCustomize(proxySetup)) {
|
||||||
|
proxySetupModel.setDomain("");
|
||||||
|
proxySetupModel.setDomainSuffix("." + ProxyConfig.getServerPath(proxySetupModel.getServer()));
|
||||||
|
} else {
|
||||||
|
proxySetupModel.setDomain(DomainUtil.getCustomize(proxySetup));
|
||||||
|
proxySetupModel.setDomainSuffix(DomainUtil.getSuffix(proxySetup));
|
||||||
|
}
|
||||||
|
styleClass.add(INPUT_LEFT_CLASS);
|
||||||
|
domainTextField.promptTextProperty().set("自定义子域名 大于3位");
|
||||||
|
customizeDomainBtn.setText("自定义");
|
||||||
|
domainHtinTextField.setText("请输入子域名,长度不小于3个字符");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 默认展示 "常见问题" 面板
|
||||||
|
tabPane.getSelectionModel().select(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initViewAction() {
|
public void initViewAction() {
|
||||||
|
// 重置
|
||||||
|
resetProxyBtn.setOnMouseClicked(event -> proxySetupModel.set(proxySetup));
|
||||||
|
|
||||||
|
// 日志清理
|
||||||
|
clearLogBtn.setOnMouseClicked(event -> {
|
||||||
|
if (frpUtilMap.get(proxySetupModel.getProxyName()) != null)
|
||||||
|
frpUtilMap.get(proxySetupModel.getProxyName()).clearLog();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 更换服务器地址
|
||||||
|
proxyServerComboBox.valueProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
|
// 重新设置是否自定义
|
||||||
|
proxySetupModel.set(proxySetupModel.get());
|
||||||
|
if (!customizeDomain.get()) {
|
||||||
|
proxySetupModel.setDomainSuffix("." + ProxyConfig.getServerPath(newValue));
|
||||||
|
} else {
|
||||||
|
proxySetupModel.setDomainSuffix("");
|
||||||
|
// 域名检查
|
||||||
|
domainTextField.validate();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// 是否启用
|
// 是否启用
|
||||||
openProxyGroup.selectedToggleProperty().addListener(
|
openProxyGroup.selectedToggleProperty().addListener(
|
||||||
(ObservableValue<? extends Toggle> ov, Toggle old_toggle, Toggle new_toggle) -> {
|
(ObservableValue<? extends Toggle> ov, Toggle old_toggle, Toggle new_toggle) -> {
|
||||||
Toggle toggle = openProxyGroup.getSelectedToggle();
|
Toggle toggle = openProxyGroup.getSelectedToggle();
|
||||||
if (toggle != null) {
|
if (toggle != null) {
|
||||||
closeProxy(!(Boolean) toggle.getUserData());
|
// 设置状态
|
||||||
|
proxySetupModel.setStatus((Boolean) toggle.getUserData());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// 隧道类型
|
// 自定义访问域名
|
||||||
proxyProtocolCombox.valueProperty().addListener((observable, oldValue, newValue) -> {
|
customizeDomainBtn.setOnMouseClicked((event) -> customizeDomain.set(!customizeDomain.get()));
|
||||||
String newType = StringUtils.lowerCase(newValue.getText());
|
|
||||||
String port;
|
|
||||||
if (!newType.equals(proxySetup.getProxy_type()))
|
|
||||||
port = ProxyConfig.getTypePort(newType).toString();
|
|
||||||
else
|
|
||||||
port = proxySetup.getLocal_port().toString();
|
|
||||||
|
|
||||||
// 设置默认端口
|
// 本地IP检查
|
||||||
localPortTextField.setText(port);
|
localHostTextField.getValidators().add(TextValidate.IpRequired);
|
||||||
// 设置隧道类型
|
localHostTextField.getValidators().add(TextValidate.IpFormat);
|
||||||
proxySetup.setProxy_type(newType);
|
localHostTextField.textProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
|
localHostTextField.validate();
|
||||||
});
|
});
|
||||||
|
|
||||||
// 自定义访问域名
|
// 端口检查
|
||||||
customizeDomainBtn.setOnMouseClicked((event) -> {
|
localPortTextField.getValidators().add(TextValidate.PortRequired);
|
||||||
setDomain(proxySetup != null ? proxySetup : null);
|
localPortTextField.getValidators().add(TextValidate.PortFormat);
|
||||||
|
localPortTextField.textProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
|
localPortTextField.validate();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 域名检查
|
||||||
|
setting.addListener((observable, oldValue, newValue) -> {
|
||||||
|
if (newValue) domainTextField.validate();
|
||||||
|
});
|
||||||
|
domainTextField.textProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
|
if (!domainTextField.getValidators().contains(TextValidate.DomainRequired)) {
|
||||||
|
domainTextField.getValidators().add(TextValidate.DomainRequired);// 域名为空检查
|
||||||
|
domainTextField.getValidators().add(TextValidate.domainFormatValidator(proxySetupModel));// 域名格式检查
|
||||||
|
domainTextField.getValidators().add(TextValidate.domainLengthValidator(proxySetupModel));// 域名长度检查
|
||||||
|
domainTextField.getValidators().add(TextValidate.domainAddressValidator(proxySetupModel));// 自定义域名解析检查
|
||||||
|
} else
|
||||||
|
domainTextField.validate();
|
||||||
});
|
});
|
||||||
|
|
||||||
// 点击隧道列表
|
// 点击隧道列表
|
||||||
proxyListView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
|
proxyListView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
if (newValue != null) {
|
ObservableList<Label> items = proxyListView.getItems();
|
||||||
for (ProxySetup setup : proxyList) {
|
for (Label item : items) {
|
||||||
if (setup.getProxy_name().equals(newValue.getText()))
|
item.getStyleClass().remove(PROXY_LIST_ITEM_SELECT_CLASS);
|
||||||
initProxySetupView(setup);
|
|
||||||
}
|
}
|
||||||
|
if (newValue != null) {
|
||||||
|
newValue.getStyleClass().add(PROXY_LIST_ITEM_SELECT_CLASS);
|
||||||
|
int oldIndex = items.indexOf(oldValue);
|
||||||
|
int newIndex = items.indexOf(newValue);
|
||||||
|
if (oldIndex != -1) proxyList.set(oldIndex, proxySetupModel.get());
|
||||||
|
proxySetup = proxyList.get(newIndex);
|
||||||
|
selectProxy.set(newIndex);
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
setting.set(false);
|
||||||
|
proxySetupModel.set(proxySetup);
|
||||||
|
FrpUtil frpUtil = frpUtilMap.get(proxySetup.getProxy_name());
|
||||||
|
proxyLogPane.contentProperty().set(frpUtil == null ? null : frpUtil.getConsole());
|
||||||
|
setting.set(true);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 添加隧道
|
// 添加隧道
|
||||||
addProxyBtn.setOnMouseClicked(event -> {
|
addProxyBtn.setOnMouseClicked(event -> {
|
||||||
|
// 保存运行状态
|
||||||
|
proxyList.get(selectProxy.get()).setRuning(proxySetupModel.isRunning());
|
||||||
// 获取默认隧道设置
|
// 获取默认隧道设置
|
||||||
proxySetup = ProxyUtil.initProxy();
|
proxySetup = ProxyUtil.initProxy(proxyList.get(proxyList.size() - 1).getSort());
|
||||||
// 加入列表
|
// 加入列表
|
||||||
proxyList.add(proxySetup);
|
proxyList.add(proxySetup);
|
||||||
selectProxy = proxyList.indexOf(proxySetup);
|
initProxyList(proxyList);
|
||||||
// 展示
|
// 展示
|
||||||
initProxySetupView(proxySetup);
|
proxyListView.getSelectionModel().select(proxyList.size() - 1);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// 启动
|
||||||
* 显示隧道设置
|
startProxyBtn.setOnMouseClicked(event -> {
|
||||||
*/
|
if (proxySetupModel.isRunning())
|
||||||
private void initProxySetupView(ProxySetup setup) {
|
stopProxy();
|
||||||
|
else
|
||||||
|
startProxy();
|
||||||
|
});
|
||||||
|
|
||||||
int select = proxyList.indexOf(setup);
|
// 链接跳转
|
||||||
//
|
domainLink.setOnMouseClicked(event -> {
|
||||||
if (setup.getLocal_ip() == null && ProxyUtil.info(setup) == null) {
|
getApplication().getHostServices().showDocument(domainLink.getText());
|
||||||
AlertUtil.error("隧道设置获取失败!").show();
|
});
|
||||||
if (select != selectProxy) {
|
|
||||||
proxyListView.getSelectionModel().select(select);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 选中的隧道下标
|
// 复制外网访问地址
|
||||||
selectProxy = select;
|
copyDomainBtn.setOnMouseClicked(event -> {
|
||||||
|
//获取系统剪切板
|
||||||
// 隧道类型
|
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
|
||||||
for (Label label : proxyProtocolCombox.getItems()) {
|
//构建String数据类型
|
||||||
// 获取用户设置
|
StringSelection selection = new StringSelection(domainLink.getText());
|
||||||
if (StringUtils.lowerCase(label.getText()).equals(setup.getProxy_type()))
|
//添加文本到系统剪切板
|
||||||
proxyProtocolCombox.getSelectionModel().select(proxyProtocolCombox.getItems().indexOf(label));
|
clipboard.setContents(selection, null);
|
||||||
}
|
// 复制成功提示
|
||||||
|
AlertUtil.info("复制成功,快去分享给小伙伴吧!").show();
|
||||||
// 服务器
|
});
|
||||||
String serverName = ProxyServer.values()[setup.getNode()].name();
|
|
||||||
proxyServerCB.getItems().forEach((label -> {
|
|
||||||
if (label.getText().equals(serverName))
|
|
||||||
proxyServerCB.getSelectionModel().select(proxyServerCB.getItems().indexOf(label));
|
|
||||||
}));
|
|
||||||
|
|
||||||
// 隧道名称
|
|
||||||
proxyNameTextField.setText(setup.getProxy_name());
|
|
||||||
|
|
||||||
// 本地服务地址
|
|
||||||
localPortTextField.setText(setup.getLocal_port().toString());
|
|
||||||
localHostTextField.setText(setup.getLocal_ip());
|
|
||||||
|
|
||||||
// 公网访问地址
|
|
||||||
setDomain(setup);
|
|
||||||
|
|
||||||
// 启动按钮
|
|
||||||
if (setup.isRuning() && !setup.isClose()) {
|
|
||||||
startProxyBtn.setText("停止");
|
|
||||||
startProxyBtn.getStyleClass().remove("startProxyBtn");
|
|
||||||
startProxyBtn.getStyleClass().add("stopProxyBtn");
|
|
||||||
} else {
|
|
||||||
startProxyBtn.setText("启动");
|
|
||||||
startProxyBtn.getStyleClass().remove("stoptProxyBtn");
|
|
||||||
startProxyBtn.getStyleClass().add("startProxyBtn");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 是否停用
|
|
||||||
closeProxy(setup.isClose());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -307,8 +436,9 @@ public class MainController extends BaseController<StackPane> implements Initial
|
|||||||
for (ProxySetup proxy : proxyList) {
|
for (ProxySetup proxy : proxyList) {
|
||||||
try {
|
try {
|
||||||
Label label = FXMLLoader.load(getClass().getResource("/fxml/proxyItem.fxml"));
|
Label label = FXMLLoader.load(getClass().getResource("/fxml/proxyItem.fxml"));
|
||||||
label.setText(proxy.getProxy_name());
|
label.textProperty().set(proxy.getProxy_name());
|
||||||
label.getStyleClass().addAll(PROXY_LIST_ITEM_CLASS, PROXY_LIST_ITEM_STOP_CLASS);
|
ObservableList<String> styleClass = label.getStyleClass();
|
||||||
|
styleClass.addAll(PROXY_LIST_ITEM_CLASS, proxy.isRuning() ? PROXY_LIST_ITEM_RUN_CLASS : PROXY_LIST_ITEM_STOP_CLASS);
|
||||||
proxyListView.getItems().add(label);
|
proxyListView.getItems().add(label);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -320,23 +450,23 @@ public class MainController extends BaseController<StackPane> implements Initial
|
|||||||
* 是否启用当前隧道
|
* 是否启用当前隧道
|
||||||
*/
|
*/
|
||||||
private void closeProxy(boolean close) {
|
private void closeProxy(boolean close) {
|
||||||
if (close && proxySetup.isRuning()) stopProxy();
|
if (close && proxySetupModel.isRunning()) stopProxy();
|
||||||
|
|
||||||
proxyNameTextField.setDisable(close);// 隧道名称
|
proxyNameTextField.setDisable(close);// 隧道名称
|
||||||
proxyProtocolCombox.setDisable(close);// 隧道类型
|
proxyProtocolComboBox.setDisable(close);// 隧道类型
|
||||||
localHostTextField.setDisable(close);// 本地地址
|
localHostTextField.setDisable(close);// 本地地址
|
||||||
localPortTextField.setDisable(close);// 本地端口
|
localPortTextField.setDisable(close);// 本地端口
|
||||||
domainTextField.setDisable(close); // 外网子域名
|
domainTextField.setDisable(close); // 外网子域名
|
||||||
startProxyBtn.setDisable(close); // 启动按钮
|
startProxyBtn.setDisable(close); // 启动按钮
|
||||||
|
|
||||||
ObservableList<String> styleClass = proxyListView.getItems().get(selectProxy).getStyleClass();
|
ObservableList<String> styleClass = proxyListView.getItems().get(selectProxy.get()).getStyleClass();
|
||||||
if (close) {
|
|
||||||
styleClass.remove(PROXY_LIST_ITEM_STOP_CLASS);
|
styleClass.remove(PROXY_LIST_ITEM_STOP_CLASS);
|
||||||
styleClass.remove(PROXY_LIST_ITEM_RUN_CLASS);
|
styleClass.remove(PROXY_LIST_ITEM_RUN_CLASS);
|
||||||
|
styleClass.remove(PROXY_LIST_ITEM_CLOSE_CLASS);
|
||||||
|
if (close) {
|
||||||
styleClass.add(PROXY_LIST_ITEM_CLOSE_CLASS);
|
styleClass.add(PROXY_LIST_ITEM_CLOSE_CLASS);
|
||||||
} else {
|
} else {
|
||||||
styleClass.remove(PROXY_LIST_ITEM_CLOSE_CLASS);
|
styleClass.add(proxySetupModel.isRunning() ? PROXY_LIST_ITEM_RUN_CLASS : PROXY_LIST_ITEM_STOP_CLASS);
|
||||||
styleClass.add(proxySetup.isClose() ? PROXY_LIST_ITEM_CLOSE_CLASS : PROXY_LIST_ITEM_STOP_CLASS);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,21 +474,32 @@ public class MainController extends BaseController<StackPane> implements Initial
|
|||||||
* TODO 启动代理
|
* TODO 启动代理
|
||||||
*/
|
*/
|
||||||
private void startProxy() {
|
private void startProxy() {
|
||||||
|
// 非 http 隧道系统随机分配端口
|
||||||
|
if (!DomainUtil.isHttp(proxySetupModel)) {
|
||||||
|
proxySetupModel.setRemotePort(String.valueOf(ProxyUtil.randomPort()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proxySetupModel.getId() != null && !proxySetupModel.get().equals(proxySetup)) {
|
||||||
// 删除旧隧道
|
// 删除旧隧道
|
||||||
if (proxySetup.getId() != null) ProxyUtil.delete(proxySetup.getId());
|
ProxyUtil.delete(proxySetupModel.getId());
|
||||||
|
|
||||||
// 添加隧道
|
// 添加隧道
|
||||||
if (!ProxyUtil.add(result -> {
|
ProxyUtil.add(result -> {
|
||||||
}, proxySetup)) return;
|
proxySetup = result;
|
||||||
|
proxySetupModel.set(proxySetup);
|
||||||
|
}, proxySetupModel.get());
|
||||||
|
}
|
||||||
|
|
||||||
// TODO 修改设置
|
// 初始化frputil
|
||||||
// TODO 调用cmd
|
FrpUtil frpUtil;
|
||||||
|
if ((frpUtil = frpUtilMap.get(proxySetupModel.getProxyName())) == null)
|
||||||
|
frpUtilMap.put(proxySetupModel.getProxyName(), frpUtil = FrpUtil.init(proxySetupModel));
|
||||||
|
|
||||||
ObservableList<String> styleClass = proxyListView.getItems().get(selectProxy).getStyleClass();
|
// 设置文本域对象
|
||||||
styleClass.remove(PROXY_LIST_ITEM_STOP_CLASS);
|
if (proxyLogPane.getContent() == null) proxyLogPane.contentProperty().set(frpUtil.getConsole());
|
||||||
styleClass.add(PROXY_LIST_ITEM_RUN_CLASS);
|
|
||||||
proxySetup.setRuning(true);
|
// 开始
|
||||||
|
frpUtil.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -366,7 +507,7 @@ public class MainController extends BaseController<StackPane> implements Initial
|
|||||||
*/
|
*/
|
||||||
private void stopProxy() {
|
private void stopProxy() {
|
||||||
// 关闭CMD
|
// 关闭CMD
|
||||||
|
FrpUtil frpUtil = frpUtilMap.get(proxySetupModel.getProxyName());
|
||||||
proxySetup.setRuning(false);
|
if (frpUtil != null) frpUtil.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,18 +9,18 @@ import javafx.scene.control.Button;
|
|||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jsoup.Jsoup;
|
|
||||||
import org.jsoup.nodes.Document;
|
|
||||||
import top.octopusyan.base.BaseController;
|
import top.octopusyan.base.BaseController;
|
||||||
import top.octopusyan.common.http.EasyHttp;
|
import top.octopusyan.manager.http.EasyHttp;
|
||||||
import top.octopusyan.common.http.listener.OnHttpListener;
|
import top.octopusyan.manager.http.listener.OnHttpListener;
|
||||||
import top.octopusyan.http.Api;
|
import top.octopusyan.http.Api;
|
||||||
import top.octopusyan.http.request.RegisterParam;
|
import top.octopusyan.http.request.RegisterParam;
|
||||||
import top.octopusyan.http.request.SendEmailCheckParam;
|
import top.octopusyan.http.request.SendEmailCheckParam;
|
||||||
import top.octopusyan.utils.AlertUtil;
|
import top.octopusyan.utils.AlertUtil;
|
||||||
import top.octopusyan.utils.ApplicatonStore;
|
import top.octopusyan.utils.ApplicatonStore;
|
||||||
import top.octopusyan.utils.TextValidate;
|
import top.octopusyan.utils.JsoupUtil;
|
||||||
|
import top.octopusyan.config.TextValidate;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -127,7 +127,13 @@ public class RegisterController extends BaseController<StackPane> implements Ser
|
|||||||
@Override
|
@Override
|
||||||
public void initViewAction() {
|
public void initViewAction() {
|
||||||
// 登录
|
// 登录
|
||||||
loginBtn.setOnMouseClicked(event -> jumpTo(new LoginController()));
|
loginBtn.setOnMouseClicked(event -> {
|
||||||
|
try {
|
||||||
|
jumpTo(new LoginController());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// 点击了发送验证码
|
// 点击了发送验证码
|
||||||
sendCheckCodeBtn.setOnMouseClicked(event -> {
|
sendCheckCodeBtn.setOnMouseClicked(event -> {
|
||||||
@ -161,34 +167,29 @@ public class RegisterController extends BaseController<StackPane> implements Ser
|
|||||||
ApplicatonStore.getEmail(),
|
ApplicatonStore.getEmail(),
|
||||||
emailCheckCodeTf.getText()
|
emailCheckCodeTf.getText()
|
||||||
))
|
))
|
||||||
.request(new OnHttpListener<String>() {
|
.request(result -> {
|
||||||
@Override
|
|
||||||
public void onSucceed(String result) {
|
|
||||||
Document html = Jsoup.parse(result);
|
|
||||||
// 注册出错
|
// 注册出错
|
||||||
if(result.contains("alert-danger")) {
|
if (JsoupUtil.isAlertSuccess(result)) {
|
||||||
Platform.runLater(() -> AlertUtil.error(getHtmlErrorMessage(html)).header(null).show());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 注册成功
|
// 注册成功
|
||||||
if(result.contains("alert-success")){
|
Platform.runLater(() ->
|
||||||
Platform.runLater(() -> AlertUtil.info(getHtmlMessage(html)).header(null).show());
|
AlertUtil.info(JsoupUtil.getHtmlMessage(result)).header(null).show()
|
||||||
|
);
|
||||||
ApplicatonStore.setRegisterSuccess(true);
|
ApplicatonStore.setRegisterSuccess(true);
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
try {
|
||||||
jumpTo(new LoginController());
|
jumpTo(new LoginController());
|
||||||
}
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else
|
||||||
|
Platform.runLater(() ->
|
||||||
|
AlertUtil.error(JsoupUtil.getErrorMessage(result)).header(null).show()
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getHtmlErrorMessage(Document html) {
|
|
||||||
return html.body().getElementsByClass("alert alert-danger alert-dismissable").text().substring(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getHtmlMessage(Document html) {
|
|
||||||
return html.body().getElementsByClass("alert alert-success alert-dismissable").text().substring(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package top.octopusyan.http;
|
package top.octopusyan.http;
|
||||||
|
|
||||||
import top.octopusyan.common.http.api.NotParamApi;
|
import top.octopusyan.manager.http.api.NotParamApi;
|
||||||
import top.octopusyan.common.http.api.ParamApi;
|
import top.octopusyan.manager.http.api.ParamApi;
|
||||||
import top.octopusyan.common.http.api.PathParamApi;
|
import top.octopusyan.manager.http.api.PathParamApi;
|
||||||
import top.octopusyan.common.http.config.BodyType;
|
import top.octopusyan.manager.http.config.BodyType;
|
||||||
import top.octopusyan.common.http.config.HttpConstant;
|
import top.octopusyan.manager.http.config.HttpConstant;
|
||||||
import top.octopusyan.http.request.ProxySetup;
|
import top.octopusyan.http.request.ProxySetup;
|
||||||
import top.octopusyan.http.request.RegisterParam;
|
import top.octopusyan.http.request.RegisterParam;
|
||||||
import top.octopusyan.http.request.SendEmailCheckParam;
|
import top.octopusyan.http.request.SendEmailCheckParam;
|
||||||
@ -32,13 +32,19 @@ public class Api {
|
|||||||
BodyType.FORM
|
BodyType.FORM
|
||||||
);
|
);
|
||||||
|
|
||||||
/** 发送邮箱验证码 */
|
/** 用户注册 */
|
||||||
public static final ParamApi<RegisterParam, String> Register = new ParamApi<>(
|
public static final ParamApi<RegisterParam, String> Register = new ParamApi<>(
|
||||||
"/?action=register&page=register",
|
"/?action=register&page=register",
|
||||||
HttpConstant.Method.POST,
|
HttpConstant.Method.POST,
|
||||||
BodyType.FORM
|
BodyType.FORM
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/** 获取服务器配置 */
|
||||||
|
public static final PathParamApi<String> ServerConfiguration = new PathParamApi<>(
|
||||||
|
"/?page=panel&module=configuration&server={0}",
|
||||||
|
HttpConstant.Method.GET
|
||||||
|
);
|
||||||
|
|
||||||
/** 隧道列表 */
|
/** 隧道列表 */
|
||||||
public static final NotParamApi<String> ProxyList = new NotParamApi<>(
|
public static final NotParamApi<String> ProxyList = new NotParamApi<>(
|
||||||
"/?page=panel&module=proxies",
|
"/?page=panel&module=proxies",
|
||||||
@ -71,7 +77,7 @@ public class Api {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** 随机端口 */
|
/** 随机端口 */
|
||||||
public static NotParamApi<Integer> RandomPort() {
|
public static NotParamApi<String> RandomPort() {
|
||||||
return new NotParamApi<>(
|
return new NotParamApi<>(
|
||||||
"/?page=panel&module=addproxy&randomport&csrf=" + ProxyUtil.getCsrf(),
|
"/?page=panel&module=addproxy&randomport&csrf=" + ProxyUtil.getCsrf(),
|
||||||
HttpConstant.Method.GET
|
HttpConstant.Method.GET
|
||||||
|
@ -7,8 +7,8 @@ import okio.BufferedSource;
|
|||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import top.octopusyan.common.http.ssl.HttpSslConfig;
|
import top.octopusyan.manager.http.ssl.HttpSslConfig;
|
||||||
import top.octopusyan.common.http.ssl.HttpSslFactory;
|
import top.octopusyan.manager.http.ssl.HttpSslFactory;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
@ -70,7 +70,7 @@ public class OkHttpClientConfig {
|
|||||||
.cookieJar(cookieJar())
|
.cookieJar(cookieJar())
|
||||||
.connectionPool(new ConnectionPool(16, 5, TimeUnit.MINUTES))
|
.connectionPool(new ConnectionPool(16, 5, TimeUnit.MINUTES))
|
||||||
.connectTimeout(10L, TimeUnit.SECONDS)
|
.connectTimeout(10L, TimeUnit.SECONDS)
|
||||||
.readTimeout(500L, TimeUnit.SECONDS)
|
.readTimeout(30L, TimeUnit.SECONDS)
|
||||||
.writeTimeout(0L, TimeUnit.SECONDS)
|
.writeTimeout(0L, TimeUnit.SECONDS)
|
||||||
.pingInterval(60L, TimeUnit.SECONDS)
|
.pingInterval(60L, TimeUnit.SECONDS)
|
||||||
.sslSocketFactory(httpSslConfig.getSslSocketFactory(), httpSslConfig.getTrustManager())
|
.sslSocketFactory(httpSslConfig.getSslSocketFactory(), httpSslConfig.getTrustManager())
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package top.octopusyan.http.request;
|
package top.octopusyan.http.request;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author : octopus yan
|
* @author : octopus yan
|
||||||
@ -8,6 +10,8 @@ import lombok.Data;
|
|||||||
* @description :
|
* @description :
|
||||||
* @create : 2022-4-5 10:08
|
* @create : 2022-4-5 10:08
|
||||||
*/
|
*/
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
@Data
|
@Data
|
||||||
public class ProxySetup {
|
public class ProxySetup {
|
||||||
private Integer id;
|
private Integer id;
|
||||||
@ -16,7 +20,7 @@ public class ProxySetup {
|
|||||||
private String proxy_type;
|
private String proxy_type;
|
||||||
private String local_ip;
|
private String local_ip;
|
||||||
private Integer local_port;
|
private Integer local_port;
|
||||||
private Integer remote_port;
|
private String remote_port;
|
||||||
private String domain;
|
private String domain;
|
||||||
private Boolean use_encryption;
|
private Boolean use_encryption;
|
||||||
private Boolean use_compression;
|
private Boolean use_compression;
|
||||||
@ -24,8 +28,8 @@ public class ProxySetup {
|
|||||||
private String host_header_rewrite;
|
private String host_header_rewrite;
|
||||||
private String header_X_From_Where;
|
private String header_X_From_Where;
|
||||||
private String sk;
|
private String sk;
|
||||||
|
/** 是否启用 */
|
||||||
private Boolean status;
|
private Boolean status;
|
||||||
private int sort;
|
private Integer sort;
|
||||||
private boolean runing;
|
private boolean runing;
|
||||||
private boolean isClose;
|
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
package top.octopusyan.common.http;
|
package top.octopusyan.manager.http;
|
||||||
|
|
||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
import top.octopusyan.common.http.api.NotParamApi;
|
import top.octopusyan.manager.http.api.NotParamApi;
|
||||||
import top.octopusyan.common.http.api.ParamApi;
|
import top.octopusyan.manager.http.api.ParamApi;
|
||||||
import top.octopusyan.common.http.config.HttpConstant;
|
import top.octopusyan.manager.http.config.HttpConstant;
|
||||||
import top.octopusyan.common.http.config.LogStrategy;
|
import top.octopusyan.manager.http.config.LogStrategy;
|
||||||
import top.octopusyan.common.http.listener.OnHttpListener;
|
import top.octopusyan.manager.http.listener.OnHttpListener;
|
||||||
import top.octopusyan.common.http.model.ResponseClass;
|
import top.octopusyan.manager.http.model.ResponseClass;
|
||||||
import top.octopusyan.common.http.request.RequestHandler;
|
import top.octopusyan.manager.http.request.RequestHandler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author : octopus yan
|
* @author : octopus yan
|
@ -1,23 +1,23 @@
|
|||||||
package top.octopusyan.common.http;
|
package top.octopusyan.manager.http;
|
||||||
|
|
||||||
import okhttp3.*;
|
import okhttp3.*;
|
||||||
import top.octopusyan.common.http.annotation.HttpHeader;
|
import top.octopusyan.manager.http.annotation.HttpHeader;
|
||||||
import top.octopusyan.common.http.annotation.HttpIgnore;
|
import top.octopusyan.manager.http.annotation.HttpIgnore;
|
||||||
import top.octopusyan.common.http.annotation.HttpRename;
|
import top.octopusyan.manager.http.annotation.HttpRename;
|
||||||
import top.octopusyan.common.http.api.NotParamApi;
|
import top.octopusyan.manager.http.api.NotParamApi;
|
||||||
import top.octopusyan.common.http.api.ParamApi;
|
import top.octopusyan.manager.http.api.ParamApi;
|
||||||
import top.octopusyan.common.http.api.PathParamApi;
|
import top.octopusyan.manager.http.api.PathParamApi;
|
||||||
import top.octopusyan.common.http.api.RequestApi;
|
import top.octopusyan.manager.http.api.RequestApi;
|
||||||
import top.octopusyan.common.http.callback.NormalCallback;
|
import top.octopusyan.manager.http.callback.NormalCallback;
|
||||||
import top.octopusyan.common.http.listener.OnHttpListener;
|
import top.octopusyan.manager.http.listener.OnHttpListener;
|
||||||
import top.octopusyan.common.http.model.CallProxy;
|
import top.octopusyan.manager.http.model.CallProxy;
|
||||||
import top.octopusyan.common.http.model.HttpHeaders;
|
import top.octopusyan.manager.http.model.HttpHeaders;
|
||||||
import top.octopusyan.common.http.model.HttpParams;
|
import top.octopusyan.manager.http.model.HttpParams;
|
||||||
import top.octopusyan.common.http.model.JsonBody;
|
import top.octopusyan.manager.http.model.JsonBody;
|
||||||
import top.octopusyan.common.http.config.BodyType;
|
import top.octopusyan.manager.http.config.BodyType;
|
||||||
import top.octopusyan.common.http.config.HttpConstant;
|
import top.octopusyan.manager.http.config.HttpConstant;
|
||||||
import top.octopusyan.common.http.request.IRequestHandler;
|
import top.octopusyan.manager.http.request.IRequestHandler;
|
||||||
import top.octopusyan.common.http.model.ResponseClass;
|
import top.octopusyan.manager.http.model.ResponseClass;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@ -545,7 +545,7 @@ public class EasyHttp<Param, Result> {
|
|||||||
/**
|
/**
|
||||||
* @param params 路径参数
|
* @param params 路径参数
|
||||||
*/
|
*/
|
||||||
public RestfulRequest<Result> pathParam(Object... params) {
|
public RestfulRequest<Result> pathParam(String... params) {
|
||||||
super.path(MessageFormat.format(getPath(), params));
|
super.path(MessageFormat.format(getPath(), params));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package top.octopusyan.common.http;
|
package top.octopusyan.manager.http;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONArray;
|
||||||
import com.alibaba.fastjson.JSONException;
|
import com.alibaba.fastjson.JSONException;
|
||||||
@ -7,10 +7,10 @@ import okhttp3.MediaType;
|
|||||||
import okhttp3.MultipartBody;
|
import okhttp3.MultipartBody;
|
||||||
import okhttp3.RequestBody;
|
import okhttp3.RequestBody;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import top.octopusyan.common.http.annotation.HttpIgnore;
|
import top.octopusyan.manager.http.annotation.HttpIgnore;
|
||||||
import top.octopusyan.common.http.annotation.HttpRename;
|
import top.octopusyan.manager.http.annotation.HttpRename;
|
||||||
import top.octopusyan.common.http.config.ContentType;
|
import top.octopusyan.manager.http.config.ContentType;
|
||||||
import top.octopusyan.common.http.model.UpdateBody;
|
import top.octopusyan.manager.http.model.UpdateBody;
|
||||||
import top.octopusyan.manager.ThreadPoolManager;
|
import top.octopusyan.manager.ThreadPoolManager;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
@ -1,18 +1,12 @@
|
|||||||
package top.octopusyan.common.http;
|
package top.octopusyan.manager.http;
|
||||||
|
|
||||||
import okhttp3.*;
|
import okhttp3.*;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import top.octopusyan.manager.http.config.ILogStrategy;
|
||||||
import top.octopusyan.common.http.config.ILogStrategy;
|
import top.octopusyan.manager.http.request.IRequestHandler;
|
||||||
import top.octopusyan.common.http.request.IRequestHandler;
|
|
||||||
import top.octopusyan.common.http.ssl.HttpSslConfig;
|
|
||||||
import top.octopusyan.common.http.ssl.HttpSslFactory;
|
|
||||||
|
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author : octopus yan
|
* @author : octopus yan
|
@ -1,4 +1,4 @@
|
|||||||
package top.octopusyan.common.http;
|
package top.octopusyan.manager.http;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author : octopus yan
|
* @author : octopus yan
|
@ -1,4 +1,4 @@
|
|||||||
package top.octopusyan.common.http.annotation;
|
package top.octopusyan.manager.http.annotation;
|
||||||
|
|
||||||
import java.lang.annotation.*;
|
import java.lang.annotation.*;
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package top.octopusyan.common.http.annotation;
|
package top.octopusyan.manager.http.annotation;
|
||||||
|
|
||||||
import java.lang.annotation.*;
|
import java.lang.annotation.*;
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package top.octopusyan.common.http.annotation;
|
package top.octopusyan.manager.http.annotation;
|
||||||
|
|
||||||
import java.lang.annotation.*;
|
import java.lang.annotation.*;
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
package top.octopusyan.common.http.api;
|
package top.octopusyan.manager.http.api;
|
||||||
|
|
||||||
import top.octopusyan.common.http.config.BodyType;
|
import top.octopusyan.manager.http.config.BodyType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author : octopus yan
|
* @author : octopus yan
|
@ -1,6 +1,6 @@
|
|||||||
package top.octopusyan.common.http.api;
|
package top.octopusyan.manager.http.api;
|
||||||
|
|
||||||
import top.octopusyan.common.http.config.BodyType;
|
import top.octopusyan.manager.http.config.BodyType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author : octopus yan
|
* @author : octopus yan
|
@ -1,6 +1,6 @@
|
|||||||
package top.octopusyan.common.http.api;
|
package top.octopusyan.manager.http.api;
|
||||||
|
|
||||||
import top.octopusyan.common.http.config.BodyType;
|
import top.octopusyan.manager.http.config.BodyType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author : octopus yan
|
* @author : octopus yan
|
@ -1,7 +1,7 @@
|
|||||||
package top.octopusyan.common.http.api;
|
package top.octopusyan.manager.http.api;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import top.octopusyan.common.http.config.BodyType;
|
import top.octopusyan.manager.http.config.BodyType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author : octopus yan
|
* @author : octopus yan
|
@ -1,12 +1,12 @@
|
|||||||
package top.octopusyan.common.http.callback;
|
package top.octopusyan.manager.http.callback;
|
||||||
|
|
||||||
import okhttp3.Call;
|
import okhttp3.Call;
|
||||||
import okhttp3.Callback;
|
import okhttp3.Callback;
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
import top.octopusyan.common.http.HttpConfig;
|
import top.octopusyan.manager.http.HttpConfig;
|
||||||
import top.octopusyan.common.http.HttpLog;
|
import top.octopusyan.manager.http.HttpLog;
|
||||||
import top.octopusyan.common.http.model.CallProxy;
|
import top.octopusyan.manager.http.model.CallProxy;
|
||||||
import top.octopusyan.common.http.EasyUtils;
|
import top.octopusyan.manager.http.EasyUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.SocketTimeoutException;
|
import java.net.SocketTimeoutException;
|
@ -1,12 +1,13 @@
|
|||||||
package top.octopusyan.common.http.callback;
|
package top.octopusyan.manager.http.callback;
|
||||||
|
|
||||||
|
import javafx.application.Platform;
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
import top.octopusyan.common.http.listener.OnHttpListener;
|
import top.octopusyan.manager.http.listener.OnHttpListener;
|
||||||
import top.octopusyan.common.http.HttpLog;
|
import top.octopusyan.manager.http.HttpLog;
|
||||||
import top.octopusyan.common.http.model.CallProxy;
|
import top.octopusyan.manager.http.model.CallProxy;
|
||||||
import top.octopusyan.common.http.api.RequestApi;
|
import top.octopusyan.manager.http.api.RequestApi;
|
||||||
import top.octopusyan.common.http.request.IRequestHandler;
|
import top.octopusyan.manager.http.request.IRequestHandler;
|
||||||
import top.octopusyan.common.http.EasyUtils;
|
import top.octopusyan.manager.http.EasyUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author : octopus yan
|
* @author : octopus yan
|
||||||
@ -52,7 +53,7 @@ public final class NormalCallback extends BaseCallback {
|
|||||||
@Override
|
@Override
|
||||||
protected void onFailure(Exception e) {
|
protected void onFailure(Exception e) {
|
||||||
final Exception exception = mRequestHandler.requestFail(mRequestApi, e);
|
final Exception exception = mRequestHandler.requestFail(mRequestApi, e);
|
||||||
HttpLog.print(exception);
|
Platform.runLater(() -> HttpLog.print(exception));
|
||||||
EasyUtils.post(() -> {
|
EasyUtils.post(() -> {
|
||||||
mListener.onFail(exception);
|
mListener.onFail(exception);
|
||||||
mListener.onEnd(getCall());
|
mListener.onEnd(getCall());
|
@ -1,4 +1,4 @@
|
|||||||
package top.octopusyan.common.http.config;
|
package top.octopusyan.manager.http.config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author : octopus yan
|
* @author : octopus yan
|
@ -1,4 +1,4 @@
|
|||||||
package top.octopusyan.common.http.config;
|
package top.octopusyan.manager.http.config;
|
||||||
|
|
||||||
import okhttp3.MediaType;
|
import okhttp3.MediaType;
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package top.octopusyan.common.http.config;
|
package top.octopusyan.manager.http.config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author : octopus yan
|
* @author : octopus yan
|
@ -1,4 +1,4 @@
|
|||||||
package top.octopusyan.common.http.config;
|
package top.octopusyan.manager.http.config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author : octopus yan
|
* @author : octopus yan
|
@ -1,10 +1,10 @@
|
|||||||
package top.octopusyan.common.http.config;
|
package top.octopusyan.manager.http.config;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import top.octopusyan.common.http.EasyHttp;
|
import top.octopusyan.manager.http.EasyHttp;
|
||||||
import top.octopusyan.common.http.HttpConfig;
|
import top.octopusyan.manager.http.HttpConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author : octopus yan
|
* @author : octopus yan
|
@ -1,4 +1,4 @@
|
|||||||
package top.octopusyan.common.http.exception;
|
package top.octopusyan.manager.http.exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 请求取消异常
|
* 请求取消异常
|
@ -1,4 +1,4 @@
|
|||||||
package top.octopusyan.common.http.exception;
|
package top.octopusyan.manager.http.exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数据解析异常
|
* 数据解析异常
|
@ -1,4 +1,4 @@
|
|||||||
package top.octopusyan.common.http.exception;
|
package top.octopusyan.manager.http.exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 网络请求异常
|
* 网络请求异常
|
@ -1,4 +1,4 @@
|
|||||||
package top.octopusyan.common.http.exception;
|
package top.octopusyan.manager.http.exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 网络连接异常
|
* 网络连接异常
|
@ -1,4 +1,4 @@
|
|||||||
package top.octopusyan.common.http.exception;
|
package top.octopusyan.manager.http.exception;
|
||||||
|
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package top.octopusyan.common.http.exception;
|
package top.octopusyan.manager.http.exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回结果异常
|
* 返回结果异常
|
@ -1,4 +1,4 @@
|
|||||||
package top.octopusyan.common.http.exception;
|
package top.octopusyan.manager.http.exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 服务器连接异常
|
* 服务器连接异常
|
@ -1,4 +1,4 @@
|
|||||||
package top.octopusyan.common.http.exception;
|
package top.octopusyan.manager.http.exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 服务器超时异常
|
* 服务器超时异常
|
@ -1,4 +1,4 @@
|
|||||||
package top.octopusyan.common.http.exception;
|
package top.octopusyan.manager.http.exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Token 失效异常
|
* Token 失效异常
|
@ -1,6 +1,9 @@
|
|||||||
package top.octopusyan.common.http.listener;
|
package top.octopusyan.manager.http.listener;
|
||||||
|
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import okhttp3.Call;
|
import okhttp3.Call;
|
||||||
|
import top.octopusyan.utils.AlertUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author : octopus yan
|
* @author : octopus yan
|
||||||
@ -23,7 +26,8 @@ public interface OnHttpListener<T> {
|
|||||||
/**
|
/**
|
||||||
* 请求出错
|
* 请求出错
|
||||||
*/
|
*/
|
||||||
default void onFail(Exception e){};
|
default void onFail(Exception e) {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 请求结束
|
* 请求结束
|
@ -1,4 +1,4 @@
|
|||||||
package top.octopusyan.common.http.model;
|
package top.octopusyan.manager.http.model;
|
||||||
|
|
||||||
import okhttp3.Call;
|
import okhttp3.Call;
|
||||||
import okhttp3.Callback;
|
import okhttp3.Callback;
|
@ -1,6 +1,6 @@
|
|||||||
package top.octopusyan.common.http.model;
|
package top.octopusyan.manager.http.model;
|
||||||
|
|
||||||
import top.octopusyan.common.http.HttpConfig;
|
import top.octopusyan.manager.http.HttpConfig;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
@ -1,6 +1,6 @@
|
|||||||
package top.octopusyan.common.http.model;
|
package top.octopusyan.manager.http.model;
|
||||||
|
|
||||||
import top.octopusyan.common.http.HttpConfig;
|
import top.octopusyan.manager.http.HttpConfig;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
@ -1,4 +1,4 @@
|
|||||||
package top.octopusyan.common.http.model;
|
package top.octopusyan.manager.http.model;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONArray;
|
||||||
@ -7,7 +7,7 @@ import lombok.NonNull;
|
|||||||
import okhttp3.MediaType;
|
import okhttp3.MediaType;
|
||||||
import okhttp3.RequestBody;
|
import okhttp3.RequestBody;
|
||||||
import okio.BufferedSink;
|
import okio.BufferedSink;
|
||||||
import top.octopusyan.common.http.config.ContentType;
|
import top.octopusyan.manager.http.config.ContentType;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
@ -1,4 +1,4 @@
|
|||||||
package top.octopusyan.common.http.model;
|
package top.octopusyan.manager.http.model;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author : octopus yan
|
* @author : octopus yan
|
@ -1,12 +1,12 @@
|
|||||||
package top.octopusyan.common.http.model;
|
package top.octopusyan.manager.http.model;
|
||||||
|
|
||||||
import okhttp3.MediaType;
|
import okhttp3.MediaType;
|
||||||
import okhttp3.RequestBody;
|
import okhttp3.RequestBody;
|
||||||
import okio.BufferedSink;
|
import okio.BufferedSink;
|
||||||
import okio.Okio;
|
import okio.Okio;
|
||||||
import okio.Source;
|
import okio.Source;
|
||||||
import top.octopusyan.common.http.config.ContentType;
|
import top.octopusyan.manager.http.config.ContentType;
|
||||||
import top.octopusyan.common.http.EasyUtils;
|
import top.octopusyan.manager.http.EasyUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
@ -1,10 +1,10 @@
|
|||||||
package top.octopusyan.common.http.request;
|
package top.octopusyan.manager.http.request;
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
import okhttp3.Request;
|
import okhttp3.Request;
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
import top.octopusyan.common.http.api.RequestApi;
|
import top.octopusyan.manager.http.api.RequestApi;
|
||||||
|
|
||||||
public interface IRequestHandler {
|
public interface IRequestHandler {
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package top.octopusyan.common.http.request;
|
package top.octopusyan.manager.http.request;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONArray;
|
||||||
@ -8,10 +8,10 @@ import okhttp3.Headers;
|
|||||||
import okhttp3.Request;
|
import okhttp3.Request;
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
import okhttp3.ResponseBody;
|
import okhttp3.ResponseBody;
|
||||||
import top.octopusyan.common.http.api.RequestApi;
|
import top.octopusyan.manager.http.api.RequestApi;
|
||||||
import top.octopusyan.common.http.exception.*;
|
import top.octopusyan.manager.http.HttpLog;
|
||||||
import top.octopusyan.common.http.HttpLog;
|
import top.octopusyan.manager.http.exception.*;
|
||||||
import top.octopusyan.common.http.response.BaseRest;
|
import top.octopusyan.manager.http.response.BaseRest;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
@ -1,4 +1,4 @@
|
|||||||
package top.octopusyan.common.http.response;
|
package top.octopusyan.manager.http.response;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package top.octopusyan.common.http.ssl;
|
package top.octopusyan.manager.http.ssl;
|
||||||
|
|
||||||
import javax.net.ssl.SSLSocketFactory;
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
import javax.net.ssl.X509TrustManager;
|
import javax.net.ssl.X509TrustManager;
|
@ -1,6 +1,6 @@
|
|||||||
package top.octopusyan.common.http.ssl;
|
package top.octopusyan.manager.http.ssl;
|
||||||
|
|
||||||
import top.octopusyan.common.http.HttpLog;
|
import top.octopusyan.manager.http.HttpLog;
|
||||||
|
|
||||||
import javax.net.ssl.*;
|
import javax.net.ssl.*;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
@ -1,4 +1,4 @@
|
|||||||
package top.octopusyan.common.http.ssl;
|
package top.octopusyan.manager.http.ssl;
|
||||||
|
|
||||||
import javax.net.ssl.HostnameVerifier;
|
import javax.net.ssl.HostnameVerifier;
|
||||||
import javax.net.ssl.SSLSession;
|
import javax.net.ssl.SSLSession;
|
@ -1,4 +1,4 @@
|
|||||||
package top.octopusyan.common.http.ssl;
|
package top.octopusyan.manager.http.ssl;
|
||||||
|
|
||||||
import javax.net.ssl.X509TrustManager;
|
import javax.net.ssl.X509TrustManager;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
335
src/main/java/top/octopusyan/model/ProxySetupModel.java
Normal file
335
src/main/java/top/octopusyan/model/ProxySetupModel.java
Normal file
@ -0,0 +1,335 @@
|
|||||||
|
package top.octopusyan.model;
|
||||||
|
|
||||||
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
|
import javafx.beans.property.SimpleIntegerProperty;
|
||||||
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import top.octopusyan.config.ProxyConfig;
|
||||||
|
import top.octopusyan.http.request.ProxySetup;
|
||||||
|
import top.octopusyan.utils.DomainUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author : octopus yan
|
||||||
|
* @email : octopus_yan@foxmail.com
|
||||||
|
* @description : 用户隧道设置模型
|
||||||
|
* @create : 2022-4-6 16:45
|
||||||
|
*/
|
||||||
|
public class ProxySetupModel {
|
||||||
|
private final SimpleIntegerProperty id = new SimpleIntegerProperty();
|
||||||
|
private final SimpleStringProperty server = new SimpleStringProperty();
|
||||||
|
private final SimpleStringProperty proxyName = new SimpleStringProperty();
|
||||||
|
private final SimpleStringProperty proxyType = new SimpleStringProperty();
|
||||||
|
private final SimpleStringProperty localIp = new SimpleStringProperty();
|
||||||
|
private final SimpleStringProperty localPort = new SimpleStringProperty();
|
||||||
|
private final SimpleStringProperty remotePort = new SimpleStringProperty();
|
||||||
|
private final SimpleStringProperty domain = new SimpleStringProperty();
|
||||||
|
private final SimpleStringProperty domainSuffix = new SimpleStringProperty();
|
||||||
|
private final SimpleBooleanProperty useEncryption = new SimpleBooleanProperty();
|
||||||
|
private final SimpleBooleanProperty useCompression = new SimpleBooleanProperty();
|
||||||
|
private final SimpleStringProperty locations = new SimpleStringProperty();
|
||||||
|
private final SimpleStringProperty hostHeaderRewrite = new SimpleStringProperty();
|
||||||
|
private final SimpleStringProperty header_X_From_Where = new SimpleStringProperty();
|
||||||
|
private final SimpleStringProperty sk = new SimpleStringProperty();
|
||||||
|
private final SimpleBooleanProperty status = new SimpleBooleanProperty();
|
||||||
|
private final SimpleIntegerProperty sort = new SimpleIntegerProperty();
|
||||||
|
private final SimpleBooleanProperty running = new SimpleBooleanProperty();
|
||||||
|
private final SimpleBooleanProperty isCustomize = new SimpleBooleanProperty();
|
||||||
|
|
||||||
|
public ProxySetupModel(ProxySetup setup) {
|
||||||
|
String domainStr = setup.getDomain();
|
||||||
|
String suffix = "";
|
||||||
|
isCustomize.set(DomainUtil.isCustomize(setup));
|
||||||
|
if (!isCustomize.get()) {
|
||||||
|
domainStr = DomainUtil.getCustomize(setup);
|
||||||
|
suffix = DomainUtil.getSuffix(setup);
|
||||||
|
}
|
||||||
|
setId(setup.getId());
|
||||||
|
setServer(ProxyConfig.getServerName(setup.getNode()));
|
||||||
|
setProxyName(setup.getProxy_name());
|
||||||
|
setProxyType(setup.getProxy_type());
|
||||||
|
setLocalIp(setup.getLocal_ip());
|
||||||
|
setLocalPort(setup.getLocal_port());
|
||||||
|
setRemotePort(setup.getRemote_port());
|
||||||
|
setDomain(domainStr);
|
||||||
|
setDomainSuffix(suffix);
|
||||||
|
setLocations(setup.getLocations());
|
||||||
|
setUseEncryption(setup.getUse_encryption());
|
||||||
|
setUseCompression(setup.getUse_compression());
|
||||||
|
setHeader_X_From_Where(setup.getHost_header_rewrite());
|
||||||
|
setHostHeaderRewrite(setup.getHost_header_rewrite());
|
||||||
|
setStatus(setup.getStatus());
|
||||||
|
setSk(setup.getSk());
|
||||||
|
setSort(setup.getSort());
|
||||||
|
setRunning(setup.isRuning());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getServer() {
|
||||||
|
return server.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProxyName() {
|
||||||
|
return proxyName.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProxyType() {
|
||||||
|
return StringUtils.lowerCase(proxyType.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLocalPort() {
|
||||||
|
return localPort.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRemotePort() {
|
||||||
|
return remotePort.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getSort() {
|
||||||
|
return sort.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLocalIp() {
|
||||||
|
return localIp.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDomain() {
|
||||||
|
return domain.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDomainSuffix() {
|
||||||
|
return domainSuffix.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHeader_X_From_Where() {
|
||||||
|
return header_X_From_Where.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHostHeaderRewrite() {
|
||||||
|
return hostHeaderRewrite.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLocations() {
|
||||||
|
return locations.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSk() {
|
||||||
|
return sk.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRunning() {
|
||||||
|
return running.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getStatus() {
|
||||||
|
return status.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUseCompression() {
|
||||||
|
return useCompression.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isUseEncryption() {
|
||||||
|
return useEncryption.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
if(id != null) this.id.set(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProxyName(String proxyName) {
|
||||||
|
this.proxyName.set(proxyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProxyType(String proxyType) {
|
||||||
|
this.proxyType.set(StringUtils.upperCase(proxyType));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServer(String server) {
|
||||||
|
this.server.set(server);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLocalIp(String localIp) {
|
||||||
|
this.localIp.set(localIp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDomain(String domain) {
|
||||||
|
this.domain.set(domain);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDomainSuffix(String domainSuffix) {
|
||||||
|
this.domainSuffix.set(domainSuffix);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeader_X_From_Where(String header_X_From_Where) {
|
||||||
|
this.header_X_From_Where.set(header_X_From_Where);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHostHeaderRewrite(String hostHeaderRewrite) {
|
||||||
|
this.hostHeaderRewrite.set(hostHeaderRewrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLocalPort(Integer localPort) {
|
||||||
|
this.localPort.set(Integer.toString(localPort));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRemotePort(String remotePort) {
|
||||||
|
this.remotePort.set(remotePort);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLocations(String locations) {
|
||||||
|
this.locations.set(locations);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRunning(Boolean running) {
|
||||||
|
this.running.set(running);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUseCompression(Boolean useCompression) {
|
||||||
|
this.useCompression.set(useCompression);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSk(String sk) {
|
||||||
|
this.sk.set(sk);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSort(Integer sort) {
|
||||||
|
if(sort != null) this.sort.set(sort);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(boolean status) {
|
||||||
|
this.status.set(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUseEncryption(boolean useEncryption) {
|
||||||
|
this.useEncryption.set(useEncryption);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleStringProperty serverProperty() {
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleStringProperty proxyNameProperty() {
|
||||||
|
return proxyName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleStringProperty proxyTypeProperty() {
|
||||||
|
return proxyType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleBooleanProperty runningProperty() {
|
||||||
|
return running;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleBooleanProperty statusProperty() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleBooleanProperty useCompressionProperty() {
|
||||||
|
return useCompression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleBooleanProperty useEncryptionProperty() {
|
||||||
|
return useEncryption;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleIntegerProperty idProperty() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleStringProperty localPortProperty() {
|
||||||
|
return localPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleStringProperty remotePortProperty() {
|
||||||
|
return remotePort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleIntegerProperty sortProperty() {
|
||||||
|
return sort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleStringProperty domainProperty() {
|
||||||
|
return domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleStringProperty domainSuffixProperty() {
|
||||||
|
return domainSuffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleStringProperty header_X_From_WhereProperty() {
|
||||||
|
return header_X_From_Where;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleStringProperty localIpProperty() {
|
||||||
|
return localIp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleStringProperty locationsProperty() {
|
||||||
|
return locations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleStringProperty skProperty() {
|
||||||
|
return sk;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleStringProperty hostHeaderRewriteProperty() {
|
||||||
|
return hostHeaderRewrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleBooleanProperty isCustomizeProperty() {
|
||||||
|
return isCustomize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(ProxySetup setup) {
|
||||||
|
String domainStr = setup.getDomain();
|
||||||
|
String suffix = "";
|
||||||
|
isCustomize.set(DomainUtil.isCustomize(setup));
|
||||||
|
if (!isCustomize.get()) {
|
||||||
|
domainStr = DomainUtil.getCustomize(setup);
|
||||||
|
suffix = DomainUtil.getSuffix(setup);
|
||||||
|
}
|
||||||
|
setId(setup.getId());
|
||||||
|
setServer(ProxyConfig.getServerName(setup.getNode()));
|
||||||
|
setProxyName(setup.getProxy_name());
|
||||||
|
setProxyType(setup.getProxy_type());
|
||||||
|
setLocalIp(setup.getLocal_ip());
|
||||||
|
setLocalPort(setup.getLocal_port());
|
||||||
|
setRemotePort(setup.getRemote_port());
|
||||||
|
setDomain(domainStr);
|
||||||
|
setDomainSuffix(suffix);
|
||||||
|
setLocations(setup.getLocations());
|
||||||
|
setUseEncryption(setup.getUse_encryption());
|
||||||
|
setUseCompression(setup.getUse_compression());
|
||||||
|
setHeader_X_From_Where(setup.getHost_header_rewrite());
|
||||||
|
setHostHeaderRewrite(setup.getHost_header_rewrite());
|
||||||
|
setStatus(setup.getStatus());
|
||||||
|
setSk(setup.getSk());
|
||||||
|
setSort(setup.getSort());
|
||||||
|
setRunning(setup.isRuning());
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProxySetup get() {
|
||||||
|
return new ProxySetup(
|
||||||
|
getId(),
|
||||||
|
ProxyConfig.getServerNode(server.get()),
|
||||||
|
getProxyName(),
|
||||||
|
StringUtils.lowerCase(proxyType.getValue()),
|
||||||
|
getLocalIp(),
|
||||||
|
getLocalPort() == null ? null : Integer.parseInt(getLocalPort()),
|
||||||
|
getRemotePort() == null ? "" : getRemotePort(),
|
||||||
|
getDomain() + getDomainSuffix(),
|
||||||
|
isUseEncryption(),
|
||||||
|
isUseCompression(),
|
||||||
|
getLocations(),
|
||||||
|
getHostHeaderRewrite(),
|
||||||
|
getHeader_X_From_Where(),
|
||||||
|
getSk(),
|
||||||
|
getStatus(),
|
||||||
|
getSort(),
|
||||||
|
isRunning()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -8,7 +8,6 @@ import javafx.collections.FXCollections;
|
|||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import top.octopusyan.http.request.ProxySetup;
|
import top.octopusyan.http.request.ProxySetup;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -25,7 +24,7 @@ public class ApplicatonStore {
|
|||||||
private static SimpleBooleanProperty autoLogin = new SimpleBooleanProperty();
|
private static SimpleBooleanProperty autoLogin = new SimpleBooleanProperty();
|
||||||
private static SimpleBooleanProperty rememberMe = new SimpleBooleanProperty();
|
private static SimpleBooleanProperty rememberMe = new SimpleBooleanProperty();
|
||||||
private static SimpleBooleanProperty registerSuccess = new SimpleBooleanProperty();
|
private static SimpleBooleanProperty registerSuccess = new SimpleBooleanProperty();
|
||||||
private static SimpleListProperty<ProxySetup> proxySetupList = new SimpleListProperty<>();
|
private static SimpleListProperty<ProxySetup> proxyList = new SimpleListProperty<>();
|
||||||
private static SimpleIntegerProperty selectProxy = new SimpleIntegerProperty(0);
|
private static SimpleIntegerProperty selectProxy = new SimpleIntegerProperty(0);
|
||||||
|
|
||||||
public static void setAccount(String account) {
|
public static void setAccount(String account) {
|
||||||
@ -84,12 +83,12 @@ public class ApplicatonStore {
|
|||||||
return registerSuccess.get();
|
return registerSuccess.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ObservableList<ProxySetup> getProxySetupList() {
|
public static ObservableList<ProxySetup> getProxyList() {
|
||||||
return proxySetupList.get();
|
return proxyList.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setProxySetupList(List<ProxySetup> proxySetupList) {
|
public static void initProxyList(List<ProxySetup> proxySetupList) {
|
||||||
ApplicatonStore.proxySetupList = new SimpleListProperty<>(FXCollections.observableList(proxySetupList));
|
ApplicatonStore.proxyList = new SimpleListProperty<>(FXCollections.observableList(proxySetupList));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setSelectProxy(int selectProxy) {
|
public static void setSelectProxy(int selectProxy) {
|
||||||
|
61
src/main/java/top/octopusyan/utils/DomainUtil.java
Normal file
61
src/main/java/top/octopusyan/utils/DomainUtil.java
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package top.octopusyan.utils;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import top.octopusyan.config.ProxyConfig;
|
||||||
|
import top.octopusyan.http.request.ProxySetup;
|
||||||
|
import top.octopusyan.model.ProxySetupModel;
|
||||||
|
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author : octopus yan
|
||||||
|
* @email : octopus_yan@foxmail.com
|
||||||
|
* @description :
|
||||||
|
* @create : 2022-4-6 20:57
|
||||||
|
*/
|
||||||
|
public class DomainUtil {
|
||||||
|
|
||||||
|
public static String getCustomize(ProxySetup setup) {
|
||||||
|
String domain = setup.getDomain();
|
||||||
|
String serverPath = getServerPath(setup);
|
||||||
|
int end = domain.indexOf("." + serverPath);
|
||||||
|
if (domain.length() <= 0 || end == -1) return "";
|
||||||
|
return domain.substring(0, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getSuffix(ProxySetup setup) {
|
||||||
|
String serverPath = getServerPath(setup);
|
||||||
|
return "." + serverPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isHttp(ProxySetupModel model){
|
||||||
|
return ProxyConfig.getTypeIndex(model.getProxyType()) < 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isHttps(ProxySetupModel model){
|
||||||
|
return ProxyConfig.getTypeIndex(model.getProxyType()) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否自定义隧道
|
||||||
|
*/
|
||||||
|
public static boolean isCustomize(ProxySetup setup) {
|
||||||
|
return !setup.getDomain().contains(getServerPath(setup));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getServerPath(ProxySetup setup) {
|
||||||
|
return ProxyConfig.getServerPath(ProxyConfig.getServerName(setup.getNode()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getDomainAddress(String domain) {
|
||||||
|
try {
|
||||||
|
String hostAddress = InetAddress.getByName(domain).getHostAddress();
|
||||||
|
return hostAddress;
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
213
src/main/java/top/octopusyan/utils/FrpUtil.java
Normal file
213
src/main/java/top/octopusyan/utils/FrpUtil.java
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
package top.octopusyan.utils;
|
||||||
|
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.scene.control.TextArea;
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import top.octopusyan.manager.ThreadPoolManager;
|
||||||
|
import top.octopusyan.model.ProxySetupModel;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author : octopus yan
|
||||||
|
* @email : octopus_yan@foxmail.com
|
||||||
|
* @description : TODO frp 工具
|
||||||
|
* @create : 2022-4-7 23:19
|
||||||
|
*/
|
||||||
|
public class FrpUtil {
|
||||||
|
private static final String YAN_FRP_TEMP_DIR_NAME = "frpclienttmp";
|
||||||
|
private static final String FRPC_CLIENT_FILE_NAME = "frpclienttmpfile.exe";
|
||||||
|
private final String FRPC_CONF_PREFIX_NAME = "proxy_";
|
||||||
|
private final String FRPC_CONF_SUFFIX_NAME = ".ini";
|
||||||
|
private static final String YAN_FRP_TEMP_DIR_PATH = System.getProperty("java.io.tmpdir") + System.currentTimeMillis() + YAN_FRP_TEMP_DIR_NAME;
|
||||||
|
private static final String FRPC_CLIENT_FILE_PATH = YAN_FRP_TEMP_DIR_PATH + File.separator + FRPC_CLIENT_FILE_NAME;
|
||||||
|
private static final File frpcDir = new File(YAN_FRP_TEMP_DIR_PATH);
|
||||||
|
public static final File frpc = new File(FRPC_CLIENT_FILE_PATH);
|
||||||
|
public File frpcConfigFile;
|
||||||
|
|
||||||
|
private final ProxySetupModel model;
|
||||||
|
private final TextArea console;
|
||||||
|
private Thread thread;
|
||||||
|
private Process exec;
|
||||||
|
|
||||||
|
|
||||||
|
private FrpUtil(TextArea console, ProxySetupModel model) {
|
||||||
|
this.console = console;
|
||||||
|
this.model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FrpUtil init(ProxySetupModel model) {
|
||||||
|
TextArea console = new TextArea();
|
||||||
|
console.setPrefHeight(180);
|
||||||
|
console.setMinWidth(200);
|
||||||
|
return new FrpUtil(console, model);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化frpc客户端文件
|
||||||
|
*/
|
||||||
|
public static void initFrpc() throws IOException {
|
||||||
|
|
||||||
|
// 存在就删除
|
||||||
|
if (frpcDir.exists()) FrpUtil.clearTmp();
|
||||||
|
|
||||||
|
// 重新创建
|
||||||
|
frpcDir.mkdir();
|
||||||
|
frpc.createNewFile();
|
||||||
|
|
||||||
|
// 发送删除请求
|
||||||
|
frpcDir.deleteOnExit();
|
||||||
|
frpc.deleteOnExit();
|
||||||
|
|
||||||
|
// 复制 frpc
|
||||||
|
String fprcFilePath = FrpUtil.class.getResource("/static/frpc.exe").getFile();
|
||||||
|
System.out.println(fprcFilePath);
|
||||||
|
copyFileUsingFileStreams(FrpUtil.class.getResourceAsStream("/static/frpc.exe"), frpc);
|
||||||
|
// FileUtils.copyFile(new File(fprcFilePath), frpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清理缓存
|
||||||
|
*/
|
||||||
|
public static void clearTmp() {
|
||||||
|
try {
|
||||||
|
FileUtils.deleteDirectory(frpcDir);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
try {
|
||||||
|
Runtime.getRuntime().exec("taskkill /im " + FRPC_CLIENT_FILE_NAME + " /f");
|
||||||
|
Thread.sleep(2000);
|
||||||
|
FileUtils.deleteDirectory(frpcDir);
|
||||||
|
} catch (InterruptedException | IOException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextArea getConsole() {
|
||||||
|
return console;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始
|
||||||
|
*/
|
||||||
|
public void start() {
|
||||||
|
|
||||||
|
thread = new Thread(() -> {
|
||||||
|
|
||||||
|
Platform.runLater(() -> console.appendText("yan-frp-info:正在启动\n"));
|
||||||
|
try {
|
||||||
|
// 检查客户端文件
|
||||||
|
if (!frpc.exists()) initFrpc();
|
||||||
|
|
||||||
|
// 初始化配置文件
|
||||||
|
initProxyConfigFile();
|
||||||
|
|
||||||
|
// 执行命令
|
||||||
|
String command = FRPC_CLIENT_FILE_PATH + " -c " + getConfigFilePath();
|
||||||
|
System.out.println(command);
|
||||||
|
exec = Runtime.getRuntime().exec(command, null, frpcDir);
|
||||||
|
|
||||||
|
// 设置运行状态
|
||||||
|
Platform.runLater(() -> model.setRunning(true));
|
||||||
|
|
||||||
|
// 获取标准输出
|
||||||
|
BufferedReader readStdout = new BufferedReader(new InputStreamReader(exec.getInputStream()));
|
||||||
|
|
||||||
|
// 逐行读取
|
||||||
|
String line;
|
||||||
|
while ((line = readStdout.readLine()) != null) {
|
||||||
|
String finalLine = line;
|
||||||
|
Platform.runLater(() -> console.appendText("yan-frp-info:" + finalLine + "\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
//
|
||||||
|
Platform.runLater(() -> console.appendText("yan-frp-error:" + e.getMessage() + "\n"));
|
||||||
|
Platform.runLater(() -> console.appendText("yan-frp-error:启动失败\n"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止隧道
|
||||||
|
*/
|
||||||
|
public void stop() {
|
||||||
|
ThreadPoolManager.getInstance().execute(() -> {
|
||||||
|
if (thread != null) {
|
||||||
|
do {
|
||||||
|
if (exec != null && exec.isAlive())
|
||||||
|
exec.destroy();
|
||||||
|
|
||||||
|
thread.interrupt();
|
||||||
|
|
||||||
|
} while (!thread.isInterrupted());
|
||||||
|
|
||||||
|
Platform.runLater(() -> {
|
||||||
|
model.setRunning(false);
|
||||||
|
console.appendText("yan-frp-info:已停止\n");
|
||||||
|
});
|
||||||
|
|
||||||
|
// 尝试删除缓存配置文件
|
||||||
|
if (frpcConfigFile.exists()) frpcConfigFile.delete();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清理日志
|
||||||
|
*/
|
||||||
|
public void clearLog() {
|
||||||
|
if (console != null)
|
||||||
|
Platform.runLater(() -> console.clear());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 隧道配置文件地址
|
||||||
|
*/
|
||||||
|
private String getConfigFilePath() {
|
||||||
|
return YAN_FRP_TEMP_DIR_PATH + File.separator + FRPC_CONF_PREFIX_NAME + model.getProxyName() + FRPC_CONF_SUFFIX_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化隧道配置文件
|
||||||
|
*/
|
||||||
|
private void initProxyConfigFile() throws IOException {
|
||||||
|
// 创建配置文件
|
||||||
|
frpcConfigFile = new File(getConfigFilePath());
|
||||||
|
if (frpcConfigFile.exists()) {
|
||||||
|
frpcConfigFile.delete();
|
||||||
|
}
|
||||||
|
frpcConfigFile.createNewFile();
|
||||||
|
frpcConfigFile.deleteOnExit();
|
||||||
|
|
||||||
|
// 写入服务配置
|
||||||
|
FileUtils.write(frpcConfigFile, ProxyUtil.getUserServerConfig(model.get().getNode()), StandardCharsets.UTF_8);
|
||||||
|
// 写入隧道配置
|
||||||
|
FileUtils.write(frpcConfigFile, ProxyUtil.getProxyConfig(model), StandardCharsets.UTF_8, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void copyFileUsingFileStreams(InputStream input, File dest)
|
||||||
|
throws IOException {
|
||||||
|
OutputStream output = null;
|
||||||
|
try {
|
||||||
|
output = new FileOutputStream(dest);
|
||||||
|
byte[] buf = new byte[1024];
|
||||||
|
int bytesRead;
|
||||||
|
while ((bytesRead = input.read(buf)) > 0) {
|
||||||
|
output.write(buf, 0, bytesRead);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
input.close();
|
||||||
|
output.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
src/main/java/top/octopusyan/utils/FxmlUtil.java
Normal file
20
src/main/java/top/octopusyan/utils/FxmlUtil.java
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package top.octopusyan.utils;
|
||||||
|
|
||||||
|
import javafx.fxml.FXMLLoader;
|
||||||
|
import javafx.fxml.JavaFXBuilderFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p> author : octopus yan
|
||||||
|
* <p> email : octopus_yan@foxmail.com
|
||||||
|
* <p> description :
|
||||||
|
* <p> create : 2022-4-9 01:45 *
|
||||||
|
*/
|
||||||
|
public class FxmlUtil {
|
||||||
|
|
||||||
|
public static FXMLLoader init(String path) {
|
||||||
|
FXMLLoader fxmlLoader = new FXMLLoader();
|
||||||
|
fxmlLoader.setBuilderFactory(new JavaFXBuilderFactory());
|
||||||
|
fxmlLoader.setLocation(FxmlUtil.class.getResource(path));
|
||||||
|
return fxmlLoader;
|
||||||
|
}
|
||||||
|
}
|
43
src/main/java/top/octopusyan/utils/JsoupUtil.java
Normal file
43
src/main/java/top/octopusyan/utils/JsoupUtil.java
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package top.octopusyan.utils;
|
||||||
|
|
||||||
|
import org.jsoup.Jsoup;
|
||||||
|
import org.jsoup.nodes.Document;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author : octopus yan
|
||||||
|
* @email : octopus_yan@foxmail.com
|
||||||
|
* @description : html解析工具类
|
||||||
|
* @create : 2022-4-8 11:04
|
||||||
|
*/
|
||||||
|
public class JsoupUtil {
|
||||||
|
|
||||||
|
public static Document getDocument(String htmlStr) {
|
||||||
|
return Jsoup.parse(htmlStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isAlertSuccess(String htmlStr) {
|
||||||
|
return !htmlStr.contains("alert-danger");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getErrorMessage(String htmlStr) {
|
||||||
|
return getDocument(htmlStr).body().getElementsByClass("alert alert-danger alert-dismissable").text().substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getHtmlMessage(String htmlStr) {
|
||||||
|
return getDocument(htmlStr).getElementsByClass("alert alert-success alert-dismissable").text().substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getServerConfiguration(String htmlStr) {
|
||||||
|
Document document = getDocument(htmlStr);
|
||||||
|
String configuration = document.getElementsByTag("pre").get(0).text();
|
||||||
|
int end = configuration.indexOf("\n\n");
|
||||||
|
// 服务器配置获取失败
|
||||||
|
if (end == -1 && !configuration.contains("[common]")) return null;
|
||||||
|
// 没有
|
||||||
|
if (end == -1) {
|
||||||
|
configuration += "\n\n";
|
||||||
|
return configuration;
|
||||||
|
}
|
||||||
|
return configuration.substring(0, end + 2);
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +1,24 @@
|
|||||||
package top.octopusyan.utils;
|
package top.octopusyan.utils;
|
||||||
|
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.jsoup.Jsoup;
|
import org.jsoup.Jsoup;
|
||||||
import org.jsoup.nodes.Document;
|
import org.jsoup.nodes.Document;
|
||||||
import org.jsoup.select.Elements;
|
import org.jsoup.select.Elements;
|
||||||
import top.octopusyan.common.http.EasyHttp;
|
import top.octopusyan.manager.http.EasyHttp;
|
||||||
import top.octopusyan.common.http.listener.OnHttpListener;
|
import top.octopusyan.manager.http.listener.OnHttpListener;
|
||||||
import top.octopusyan.common.http.model.ResponseClass;
|
import top.octopusyan.manager.http.model.ResponseClass;
|
||||||
import top.octopusyan.config.ProxyConfig.*;
|
import top.octopusyan.config.ProxyConfig;
|
||||||
|
import top.octopusyan.config.ProxyConfig.ProxyServer;
|
||||||
|
import top.octopusyan.config.ProxyConfig.ProxyType;
|
||||||
import top.octopusyan.http.Api;
|
import top.octopusyan.http.Api;
|
||||||
import top.octopusyan.http.request.ProxySetup;
|
import top.octopusyan.http.request.ProxySetup;
|
||||||
|
import top.octopusyan.model.ProxySetupModel;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -22,32 +29,38 @@ import java.util.stream.Collectors;
|
|||||||
*/
|
*/
|
||||||
public class ProxyUtil {
|
public class ProxyUtil {
|
||||||
private static String csrf;
|
private static String csrf;
|
||||||
|
private static Map<Integer, String> serverConfigraution = new HashMap<>(3);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化隧道设置
|
* 初始化隧道设置
|
||||||
*/
|
*/
|
||||||
public static ProxySetup initProxy() {
|
public static ProxySetup initProxy(Integer maxsort) {
|
||||||
ProxySetup setup = new ProxySetup();
|
ProxySetup setup = new ProxySetup();
|
||||||
setup.setNode(3);// 上海服务器
|
setup.setNode(3);// 上海服务器
|
||||||
setup.setLocal_ip("127.0.0.1");
|
setup.setLocal_ip("127.0.0.1");
|
||||||
setup.setLocal_port(80);
|
setup.setLocal_port(80);
|
||||||
setup.setProxy_name("默认连接");
|
setup.setProxy_name("默认连接");
|
||||||
setup.setProxy_type(ProxyType.HTTP.name());
|
setup.setProxy_type(StringUtils.lowerCase(ProxyType.HTTP.name()));
|
||||||
|
setup.setDomain(".frp.octopusyan.top");
|
||||||
|
setup.setSort(1);
|
||||||
|
if (maxsort != null) setup.setSort(maxsort + 1);
|
||||||
setup.setUse_compression(true);
|
setup.setUse_compression(true);
|
||||||
setup.setUse_encryption(true);
|
setup.setUse_encryption(true);
|
||||||
|
setup.setStatus(true);
|
||||||
|
setup.setRuning(false);
|
||||||
return setup;
|
return setup;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void delete(Integer id) {
|
public static void delete(Integer id) {
|
||||||
EasyHttp.builder()
|
EasyHttp.builder()
|
||||||
.api(Api.DeleteProxy())
|
.api(Api.DeleteProxy())
|
||||||
.pathParam(id, csrf)
|
.pathParam(String.valueOf(id), csrf)
|
||||||
.request(result -> { });
|
.request(result -> {
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取隧道详情信息
|
* 获取隧道详情信息
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
public static ProxySetup info(ProxySetup setup) {
|
public static ProxySetup info(ProxySetup setup) {
|
||||||
|
|
||||||
@ -55,7 +68,7 @@ public class ProxyUtil {
|
|||||||
try {
|
try {
|
||||||
html = EasyHttp.builder()
|
html = EasyHttp.builder()
|
||||||
.api(Api.ProxyInfo())
|
.api(Api.ProxyInfo())
|
||||||
.pathParam(setup.getId())
|
.pathParam(String.valueOf(setup.getId()))
|
||||||
.execute(new ResponseClass<String>() {
|
.execute(new ResponseClass<String>() {
|
||||||
});
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -75,14 +88,14 @@ public class ProxyUtil {
|
|||||||
String domain = select.get(8).text();
|
String domain = select.get(8).text();
|
||||||
String status = select.get(13).text();
|
String status = select.get(13).text();
|
||||||
|
|
||||||
Arrays.stream(ProxyServer.values()).forEach(server -> {
|
for (ProxyServer value : ProxyServer.values()) {
|
||||||
if (serverStr.contains(server.name()))
|
String name = value.getServerName();
|
||||||
setup.setNode(Arrays.asList(ProxyServer.values()).indexOf(server));
|
if (serverStr.contains(name))
|
||||||
});
|
setup.setNode(ProxyConfig.getServerNode(name));
|
||||||
|
}
|
||||||
setup.setLocal_ip(localIp);
|
setup.setLocal_ip(localIp);
|
||||||
setup.setLocal_port(Integer.parseInt(localPort));
|
setup.setLocal_port(Integer.parseInt(localPort));
|
||||||
setup.setRemote_port("无".equals(webPort) ? null : Integer.parseInt(webPort));
|
setup.setRemote_port("无".equals(webPort) ? "" : webPort);
|
||||||
setup.setDomain(domain);
|
setup.setDomain(domain);
|
||||||
setup.setUse_compression(useCom.equals("启用"));
|
setup.setUse_compression(useCom.equals("启用"));
|
||||||
setup.setUse_encryption(useEnc.equals("启用"));
|
setup.setUse_encryption(useEnc.equals("启用"));
|
||||||
@ -93,12 +106,13 @@ public class ProxyUtil {
|
|||||||
|
|
||||||
public static int randomPort() {
|
public static int randomPort() {
|
||||||
try {
|
try {
|
||||||
return EasyHttp.builder()
|
return Integer.parseInt(EasyHttp.builder()
|
||||||
.api(Api.RandomPort())
|
.api(Api.RandomPort())
|
||||||
.execute(new ResponseClass<Integer>() { });
|
.execute(new ResponseClass<String>() {
|
||||||
|
}));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return (int) (Math.random() * 31000);
|
return (int) (Math.random() * 1000 + 30000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,33 +135,35 @@ public class ProxyUtil {
|
|||||||
proxySetup.setProxy_name(tds.get(1).text());
|
proxySetup.setProxy_name(tds.get(1).text());
|
||||||
proxySetup.setProxy_type(tds.get(2).text());
|
proxySetup.setProxy_type(tds.get(2).text());
|
||||||
proxySetup.setSort(Integer.parseInt(tds.get(5).text()));
|
proxySetup.setSort(Integer.parseInt(tds.get(5).text()));
|
||||||
|
|
||||||
|
ProxySetup info = info(proxySetup);
|
||||||
|
if (info != null) return info;
|
||||||
return proxySetup;
|
return proxySetup;
|
||||||
}).collect(Collectors.toList());
|
}).collect(Collectors.toList());
|
||||||
|
|
||||||
listener.onSucceed(proxySetupList);
|
Platform.runLater(() -> listener.onSucceed(proxySetupList));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFail(Exception e) {
|
||||||
|
AlertUtil.exception(e).show();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean add(OnHttpListener<ProxySetup> listener, ProxySetup setup) {
|
public static void add(OnHttpListener<ProxySetup> listener, ProxySetup setup) {
|
||||||
String result = null;
|
EasyHttp.builder()
|
||||||
try {
|
|
||||||
result = EasyHttp.builder()
|
|
||||||
.api(Api.AddProxy())
|
.api(Api.AddProxy())
|
||||||
.param(setup)
|
.param(setup)
|
||||||
.execute(new ResponseClass<String>() {
|
.request(result -> getList(result1 -> {
|
||||||
});
|
if (result1 != null && result1.size() > 0) {
|
||||||
} catch (Exception e) {
|
for (ProxySetup proxySetup : result1) {
|
||||||
e.printStackTrace();
|
if (Objects.equals(proxySetup.getSort(), proxySetup.getSort())) {
|
||||||
return false;
|
listener.onSucceed(proxySetup);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(result.equals("隧道创建成功")){
|
|
||||||
getList(result1 -> listener.onSucceed(result1.get(result1.size()-1)));
|
|
||||||
} else {
|
|
||||||
AlertUtil.error(result).show();
|
|
||||||
}
|
}
|
||||||
return result.equals("隧道创建成功");
|
}
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getCsrf() {
|
public static String getCsrf() {
|
||||||
@ -159,4 +175,53 @@ public class ProxyUtil {
|
|||||||
int i1 = htmlStr.indexOf("\"", i + 18);
|
int i1 = htmlStr.indexOf("\"", i + 18);
|
||||||
ProxyUtil.csrf = htmlStr.substring(i + 18, i1);
|
ProxyUtil.csrf = htmlStr.substring(i + 18, i1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getUserServerConfig(int node) {
|
||||||
|
String config = serverConfigraution.get(node);
|
||||||
|
if (StringUtils.isNotEmpty(config)) return config;
|
||||||
|
try {
|
||||||
|
String result = EasyHttp.builder()
|
||||||
|
.api(Api.ServerConfiguration)
|
||||||
|
.pathParam(String.valueOf(node))
|
||||||
|
.execute(new ResponseClass<String>() {
|
||||||
|
});
|
||||||
|
config = JsoupUtil.getServerConfiguration(result);
|
||||||
|
if (StringUtils.isNotEmpty(config)) serverConfigraution.put(node, config);
|
||||||
|
return config;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getProxyConfig(ProxySetupModel setup) {
|
||||||
|
String n = "\n";
|
||||||
|
// 基础配置
|
||||||
|
StringBuffer stringBuffer = new StringBuffer("[" + setup.getProxyName() + "]\n");
|
||||||
|
stringBuffer.append("privilege_mode = true\n")
|
||||||
|
.append("type = ").append(setup.getProxyType()).append(n)
|
||||||
|
.append("local_ip = ").append(setup.getLocalIp()).append(n)
|
||||||
|
.append("local_port = ").append(setup.getLocalPort()).append(n).append(n);
|
||||||
|
|
||||||
|
if ("http".equals(setup.getProxyType()) || "https".equals(setup.getProxyType())) {
|
||||||
|
// HTTP / HTTPS
|
||||||
|
stringBuffer.append("custom_domains = ").append(setup.getDomain()).append(setup.getDomainSuffix()).append(n);
|
||||||
|
if (!StringUtils.isEmpty(setup.getLocations()))
|
||||||
|
stringBuffer.append("locations = ").append(setup.getLocations()).append(n);
|
||||||
|
if (!StringUtils.isEmpty(setup.getLocations()))
|
||||||
|
stringBuffer.append("host_header_rewrite = ").append(setup.getHostHeaderRewrite()).append(n);
|
||||||
|
if (!StringUtils.isEmpty(setup.getLocations()))
|
||||||
|
stringBuffer.append("header_X-From-Where = ").append(setup.getHeader_X_From_Where()).append(n);
|
||||||
|
} else {
|
||||||
|
// TCP / UDP / XTCP / STCP
|
||||||
|
stringBuffer.append("remote_port = ").append(setup.getRemotePort()).append(n);
|
||||||
|
if (!StringUtils.isEmpty(setup.getSk()))
|
||||||
|
stringBuffer.append("sk = ").append(setup.getSk()).append(n);
|
||||||
|
}
|
||||||
|
// 压缩和加密
|
||||||
|
stringBuffer.append("use_encryption = ").append(setup.isUseEncryption()).append(n)
|
||||||
|
.append("use_compression = ").append(setup.isUseCompression()).append(n).append(n);
|
||||||
|
|
||||||
|
return stringBuffer.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,64 +0,0 @@
|
|||||||
package top.octopusyan.utils;
|
|
||||||
|
|
||||||
import com.jfoenix.validation.RegexValidator;
|
|
||||||
import com.jfoenix.validation.RequiredFieldValidator;
|
|
||||||
import com.jfoenix.validation.StringLengthValidator;
|
|
||||||
import com.jfoenix.validation.base.ValidatorBase;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author : octopus yan
|
|
||||||
* @email : octopus_yan@foxmail.com
|
|
||||||
* @description : JFX文本校验
|
|
||||||
* @create : 2022-4-2 17:03
|
|
||||||
*/
|
|
||||||
public class TextValidate {
|
|
||||||
// /**
|
|
||||||
// * 账号格式错误
|
|
||||||
// */
|
|
||||||
// public static ValidatorBase AccountFail = new ValidatorBase() {
|
|
||||||
// @Override
|
|
||||||
// protected void eval() {
|
|
||||||
// setMessage("账号格式错误");
|
|
||||||
// hasErrors.set(true);
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
/** 账号不能为空 */
|
|
||||||
public static RequiredFieldValidator AccoountRequired = new RequiredFieldValidator("账号不能为空!");
|
|
||||||
|
|
||||||
/** 账号格式 */
|
|
||||||
public static RegexValidator AccoountValidator = new RegexValidator("账号格式有误!");
|
|
||||||
/** 密码不能为空 */
|
|
||||||
public static RequiredFieldValidator PasswordRequired = new RequiredFieldValidator("密码不能为空!");
|
|
||||||
|
|
||||||
/** 邮箱地址格式验证 */
|
|
||||||
public static RegexValidator EmailFormat = new RegexValidator("邮箱地址格式错误");
|
|
||||||
|
|
||||||
static {
|
|
||||||
EmailFormat.setRegexPattern("^\\s*\\w+(?:\\.{0,1}[\\w-]+)*@[a-zA-Z0-9]+(?:[-.][a-zA-Z0-9]+)*\\.[a-zA-Z]+\\s*$");
|
|
||||||
AccoountValidator.setRegexPattern("^[a-zA-Z0-9_-]*$");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文本长度校验
|
|
||||||
* <p/> message > name + "长度有误"
|
|
||||||
*/
|
|
||||||
public static StringLengthValidator getLengthValidator(String name, int length){
|
|
||||||
return new StringLengthValidator(name+"长度有误", length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文本长度校验
|
|
||||||
* <p/> message > name + "长度有误,应在" + min + "到" + max + "之间"
|
|
||||||
*/
|
|
||||||
public static RegexValidator getLengthValidator(int min, int max, String name){
|
|
||||||
String message = name + "长度有误,应在" + min + "到" + max + "之间";
|
|
||||||
|
|
||||||
RegexValidator validator = new RegexValidator(message);
|
|
||||||
|
|
||||||
validator.setRegexPattern("[a-zA-Z0-9_-]{" + min + "," + max + "}$");
|
|
||||||
|
|
||||||
return validator;
|
|
||||||
}
|
|
||||||
}
|
|
@ -38,16 +38,23 @@
|
|||||||
-fx-border-radius: 0 5 5 0;
|
-fx-border-radius: 0 5 5 0;
|
||||||
}
|
}
|
||||||
/* 服务线路 */
|
/* 服务线路 */
|
||||||
#proxyServerCB {
|
#proxyServerComboBox {
|
||||||
-fx-font-size: 16;
|
-fx-font-size: 16;
|
||||||
-fx-text-fill: #757575;
|
-fx-text-fill: #757575;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO 隧道列表 */
|
/* TODO 隧道列表 */
|
||||||
#proxyListView .list-cell:selected {
|
#proxyListView .list-cell:selected {
|
||||||
-fx-text-fill: white;
|
|
||||||
-fx-background-color: linear-gradient(#9198e5, #57b4f2);
|
-fx-background-color: linear-gradient(#9198e5, #57b4f2);
|
||||||
}
|
}
|
||||||
|
#proxyListView .list-cell:hover {
|
||||||
|
-fx-opacity: 0.7;
|
||||||
|
-fx-background-color: linear-gradient(#9198e5, #57b4f2);
|
||||||
|
}
|
||||||
|
#proxyListView .list-cell:hover lable, #proxyListView .list-cell:selected label, .proxyListItem-select{
|
||||||
|
-fx-text-fill: white;
|
||||||
|
}
|
||||||
|
|
||||||
.proxyListItem-run FontIcon {
|
.proxyListItem-run FontIcon {
|
||||||
-fx-icon-color: linear-gradient(#95f257, #91e5ac);
|
-fx-icon-color: linear-gradient(#95f257, #91e5ac);
|
||||||
}
|
}
|
||||||
@ -73,18 +80,20 @@
|
|||||||
-fx-font-family: "Microsoft YaHei";
|
-fx-font-family: "Microsoft YaHei";
|
||||||
}
|
}
|
||||||
/* 隧道类型 */
|
/* 隧道类型 */
|
||||||
#proxyProtocolCombox {
|
#proxyProtocolComboBox {
|
||||||
-fx-font-size: 14px;
|
-fx-font-size: 14px;
|
||||||
-fx-font-family: "Microsoft YaHei";
|
-fx-font-family: "Microsoft YaHei";
|
||||||
}
|
}
|
||||||
/* 自定义域名 */
|
/* 自定义域名 */
|
||||||
#customizeDomainBtn {
|
#customizeDomainBtn, #resetProxyBtn, #copyDomainBtn {
|
||||||
-fx-text-fill: linear-gradient(#57b4f2, #9198e5);
|
-fx-text-fill: linear-gradient(#57b4f2, #9198e5);
|
||||||
}
|
}
|
||||||
/* 添加隧道 */
|
/* 添加隧道 */
|
||||||
#addProxyBtn {
|
#addProxyBtn {
|
||||||
-fx-border-width: 0 1 1;
|
-fx-border-width: 0 1 1;
|
||||||
-fx-font-size: 14px;
|
-fx-font-size: 14px;
|
||||||
|
-fx-text-fill: white;
|
||||||
|
-fx-background-color: linear-gradient(rgba(87, 180, 242, 0.7), rgba(145, 152, 229, 0.71));
|
||||||
-fx-font-family: "Microsoft YaHei";
|
-fx-font-family: "Microsoft YaHei";
|
||||||
}
|
}
|
||||||
/* 启动 */
|
/* 启动 */
|
||||||
@ -105,4 +114,9 @@
|
|||||||
.jfx-tab-pane .tab-header-background {
|
.jfx-tab-pane .tab-header-background {
|
||||||
-fx-background-color: linear-gradient(#57b4f2, #9198e5);
|
-fx-background-color: linear-gradient(#57b4f2, #9198e5);
|
||||||
}
|
}
|
||||||
|
/* 日志 */
|
||||||
|
.text-area {
|
||||||
|
-fx-font-size: 15;
|
||||||
|
-fx-font-family: monospace;
|
||||||
|
-fx-background-color: white;
|
||||||
|
}
|
||||||
|
@ -28,8 +28,13 @@
|
|||||||
|
|
||||||
#closeBtn:hover {
|
#closeBtn:hover {
|
||||||
-fx-background-color: rgba(255, 0, 0, 0.70);
|
-fx-background-color: rgba(255, 0, 0, 0.70);
|
||||||
|
-fx-text-fill: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
#minimizeBtn:hover {
|
#minimizeBtn:hover {
|
||||||
-fx-background-color: rgba(243, 242, 242, 0.20);
|
-fx-background-color: rgba(243, 242, 242, 0.20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button:hover, .jfx-button:hover {
|
||||||
|
-fx-opacity: 0.8;
|
||||||
|
}
|
@ -5,8 +5,10 @@
|
|||||||
<?import com.jfoenix.controls.JFXListView?>
|
<?import com.jfoenix.controls.JFXListView?>
|
||||||
<?import com.jfoenix.controls.JFXRadioButton?>
|
<?import com.jfoenix.controls.JFXRadioButton?>
|
||||||
<?import com.jfoenix.controls.JFXTabPane?>
|
<?import com.jfoenix.controls.JFXTabPane?>
|
||||||
|
<?import com.jfoenix.controls.JFXTextArea?>
|
||||||
<?import com.jfoenix.controls.JFXTextField?>
|
<?import com.jfoenix.controls.JFXTextField?>
|
||||||
<?import javafx.geometry.Insets?>
|
<?import javafx.geometry.Insets?>
|
||||||
|
<?import javafx.scene.Cursor?>
|
||||||
<?import javafx.scene.control.Hyperlink?>
|
<?import javafx.scene.control.Hyperlink?>
|
||||||
<?import javafx.scene.control.Label?>
|
<?import javafx.scene.control.Label?>
|
||||||
<?import javafx.scene.control.Tab?>
|
<?import javafx.scene.control.Tab?>
|
||||||
@ -20,14 +22,21 @@
|
|||||||
<?import javafx.scene.text.Font?>
|
<?import javafx.scene.text.Font?>
|
||||||
<?import org.kordamp.ikonli.javafx.FontIcon?>
|
<?import org.kordamp.ikonli.javafx.FontIcon?>
|
||||||
|
|
||||||
<StackPane fx:id="root" prefHeight="700.0" prefWidth="750.0" stylesheets="@../css/main.css" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="top.octopusyan.controller.MainController">
|
<StackPane fx:id="root" prefHeight="700.0" prefWidth="750.0" stylesheets="@../css/main.css"
|
||||||
|
xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1"
|
||||||
|
fx:controller="top.octopusyan.controller.MainController">
|
||||||
|
|
||||||
<VBox fx:id="MainPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="700.0" prefWidth="750.0">
|
<VBox fx:id="MainPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity"
|
||||||
|
prefHeight="700.0" prefWidth="750.0">
|
||||||
<AnchorPane fx:id="MainTopPane" prefHeight="35.0" prefWidth="750.0">
|
<AnchorPane fx:id="MainTopPane" prefHeight="35.0" prefWidth="750.0">
|
||||||
<JFXButton fx:id="titleLable" disable="true" prefHeight="35.0" prefWidth="90.0" text="Yan Frp"/>
|
<JFXButton fx:id="titleLable" disable="true" prefHeight="35.0" prefWidth="90.0" text="Yan Frp"/>
|
||||||
<JFXButton fx:id="minimizeBtn" layoutX="678.0" prefHeight="35.0" prefWidth="36.0" text="—"/>
|
<JFXButton fx:id="minimizeBtn" layoutX="678.0" prefHeight="35.0" prefWidth="36.0" text="—"/>
|
||||||
<JFXButton fx:id="closeBtn" layoutX="714.0" prefHeight="35.0" prefWidth="36.0" text="X"/>
|
<JFXButton fx:id="closeBtn" layoutX="714.0" prefHeight="35.0" prefWidth="36.0" text="X"/>
|
||||||
<JFXComboBox fx:id="proxyServerCB" layoutX="90.0" prefHeight="36.0" prefWidth="100.0" />
|
<JFXComboBox fx:id="proxyServerComboBox" layoutX="90.0" prefHeight="36.0" prefWidth="90.0">
|
||||||
|
<cursor>
|
||||||
|
<Cursor fx:constant="HAND"/>
|
||||||
|
</cursor>
|
||||||
|
</JFXComboBox>
|
||||||
</AnchorPane>
|
</AnchorPane>
|
||||||
<GridPane fx:id="MainBottomPane" hgap="10.0" prefHeight="684.0" prefWidth="750.0" vgap="10.0">
|
<GridPane fx:id="MainBottomPane" hgap="10.0" prefHeight="684.0" prefWidth="750.0" vgap="10.0">
|
||||||
<columnConstraints>
|
<columnConstraints>
|
||||||
@ -40,13 +49,34 @@
|
|||||||
</rowConstraints>
|
</rowConstraints>
|
||||||
<children>
|
<children>
|
||||||
<VBox fx:id="proxySetupPane" prefHeight="200.0" prefWidth="100.0" styleClass="mainPane">
|
<VBox fx:id="proxySetupPane" prefHeight="200.0" prefWidth="100.0" styleClass="mainPane">
|
||||||
|
<padding>
|
||||||
|
<Insets left="10.0"/>
|
||||||
|
</padding>
|
||||||
|
<HBox alignment="CENTER_RIGHT" prefHeight="50.0" prefWidth="520.0">
|
||||||
|
<padding>
|
||||||
|
<Insets bottom="10.0" top="10.0"/>
|
||||||
|
</padding>
|
||||||
|
<JFXButton fx:id="resetProxyBtn" prefHeight="Infinity" text="重置">
|
||||||
|
<HBox.margin>
|
||||||
|
<Insets right="10.0"/>
|
||||||
|
</HBox.margin>
|
||||||
|
<cursor>
|
||||||
|
<Cursor fx:constant="HAND"/>
|
||||||
|
</cursor>
|
||||||
|
</JFXButton>
|
||||||
|
</HBox>
|
||||||
<HBox alignment="CENTER_LEFT" prefHeight="50.0" prefWidth="520.0">
|
<HBox alignment="CENTER_LEFT" prefHeight="50.0" prefWidth="520.0">
|
||||||
<Label alignment="CENTER_RIGHT" prefHeight="Infinity" prefWidth="100.0" styleClass="proxySetupLabel" text="隧道名称">
|
<padding>
|
||||||
|
<Insets bottom="10.0" top="10.0"/>
|
||||||
|
</padding>
|
||||||
|
<Label alignment="CENTER_RIGHT" prefHeight="Infinity" prefWidth="100.0"
|
||||||
|
styleClass="proxySetupLabel" text="隧道名称">
|
||||||
<HBox.margin>
|
<HBox.margin>
|
||||||
<Insets right="20.0"/>
|
<Insets right="20.0"/>
|
||||||
</HBox.margin>
|
</HBox.margin>
|
||||||
</Label>
|
</Label>
|
||||||
<JFXTextField fx:id="proxyNameTextField" prefHeight="Infinity" prefWidth="320.0" styleClass="inputText">
|
<JFXTextField fx:id="proxyNameTextField" prefHeight="Infinity" prefWidth="320.0"
|
||||||
|
styleClass="inputText">
|
||||||
<HBox.margin>
|
<HBox.margin>
|
||||||
<Insets right="20.0"/>
|
<Insets right="20.0"/>
|
||||||
</HBox.margin>
|
</HBox.margin>
|
||||||
@ -57,12 +87,13 @@
|
|||||||
<Font size="14.0"/>
|
<Font size="14.0"/>
|
||||||
</font>
|
</font>
|
||||||
</JFXTextField>
|
</JFXTextField>
|
||||||
|
</HBox>
|
||||||
|
<HBox alignment="CENTER_LEFT" prefHeight="50.0" prefWidth="520.0">
|
||||||
<padding>
|
<padding>
|
||||||
<Insets bottom="10.0" top="10.0"/>
|
<Insets bottom="10.0" top="10.0"/>
|
||||||
</padding>
|
</padding>
|
||||||
</HBox>
|
<Label alignment="CENTER_RIGHT" prefHeight="Infinity" prefWidth="100.0"
|
||||||
<HBox alignment="CENTER_LEFT" prefHeight="50.0" prefWidth="520.0">
|
styleClass="proxySetupLabel" text="是否启用">
|
||||||
<Label alignment="CENTER_RIGHT" prefHeight="Infinity" prefWidth="100.0" styleClass="proxySetupLabel" text="是否启用">
|
|
||||||
<HBox.margin>
|
<HBox.margin>
|
||||||
<Insets right="20.0"/>
|
<Insets right="20.0"/>
|
||||||
</HBox.margin>
|
</HBox.margin>
|
||||||
@ -72,64 +103,79 @@
|
|||||||
<HBox.margin>
|
<HBox.margin>
|
||||||
<Insets right="20.0"/>
|
<Insets right="20.0"/>
|
||||||
</HBox.margin>
|
</HBox.margin>
|
||||||
|
<cursor>
|
||||||
|
<Cursor fx:constant="HAND"/>
|
||||||
|
</cursor>
|
||||||
|
</JFXRadioButton>
|
||||||
|
<JFXRadioButton fx:id="closeProxyRBtn" text="停用">
|
||||||
|
<cursor>
|
||||||
|
<Cursor fx:constant="HAND"/>
|
||||||
|
</cursor>
|
||||||
</JFXRadioButton>
|
</JFXRadioButton>
|
||||||
<JFXRadioButton fx:id="closeProxyRBtn" text="停用" />
|
|
||||||
</HBox>
|
</HBox>
|
||||||
<VBox.margin>
|
</HBox>
|
||||||
<Insets />
|
<HBox alignment="CENTER_LEFT" prefHeight="50.0" prefWidth="520.0">
|
||||||
</VBox.margin>
|
|
||||||
<padding>
|
<padding>
|
||||||
<Insets bottom="10.0" top="10.0"/>
|
<Insets bottom="10.0" top="10.0"/>
|
||||||
</padding>
|
</padding>
|
||||||
</HBox>
|
<Label alignment="CENTER_RIGHT" prefHeight="Infinity" prefWidth="100.0"
|
||||||
<HBox alignment="CENTER_LEFT" prefHeight="50.0" prefWidth="520.0">
|
styleClass="proxySetupLabel" text="协议类型">
|
||||||
<Label alignment="CENTER_RIGHT" prefHeight="Infinity" prefWidth="100.0" styleClass="proxySetupLabel" text="协议类型">
|
|
||||||
<HBox.margin>
|
<HBox.margin>
|
||||||
<Insets right="20.0"/>
|
<Insets right="20.0"/>
|
||||||
</HBox.margin>
|
</HBox.margin>
|
||||||
</Label>
|
</Label>
|
||||||
<JFXComboBox fx:id="proxyProtocolCombox" prefHeight="Infinity" prefWidth="320.0" styleClass="inputText" />
|
<JFXComboBox fx:id="proxyProtocolComboBox" prefHeight="Infinity" prefWidth="320.0"
|
||||||
|
styleClass="inputText">
|
||||||
|
<cursor>
|
||||||
|
<Cursor fx:constant="HAND"/>
|
||||||
|
</cursor>
|
||||||
|
</JFXComboBox>
|
||||||
|
</HBox>
|
||||||
|
<HBox alignment="CENTER_LEFT" prefHeight="50.0" prefWidth="520.0">
|
||||||
<padding>
|
<padding>
|
||||||
<Insets bottom="10.0" top="10.0"/>
|
<Insets bottom="10.0" top="10.0"/>
|
||||||
</padding>
|
</padding>
|
||||||
</HBox>
|
<Label alignment="CENTER_RIGHT" prefHeight="Infinity" prefWidth="100.0"
|
||||||
<HBox alignment="CENTER_LEFT" prefHeight="50.0" prefWidth="520.0">
|
styleClass="proxySetupLabel" text="内网服务地址">
|
||||||
<Label alignment="CENTER_RIGHT" prefHeight="Infinity" prefWidth="100.0" styleClass="proxySetupLabel" text="内网服务地址">
|
|
||||||
<HBox.margin>
|
<HBox.margin>
|
||||||
<Insets right="20.0"/>
|
<Insets right="20.0"/>
|
||||||
</HBox.margin>
|
</HBox.margin>
|
||||||
</Label>
|
</Label>
|
||||||
<HBox prefHeight="Infinity" prefWidth="320.0">
|
<HBox prefHeight="Infinity" prefWidth="320.0">
|
||||||
<children>
|
<JFXTextField fx:id="localHostTextField" alignment="CENTER" prefWidth="220.0"
|
||||||
<JFXTextField fx:id="localHostTextField" alignment="CENTER" prefWidth="250.0" promptText="内网服务IP (IPV4)" styleClass="inputText-left" text="127.0.0.1">
|
promptText="内网服务IP (IPV4)" styleClass="inputText-left" text="127.0.0.1">
|
||||||
<font>
|
<font>
|
||||||
<Font size="14.0"/>
|
<Font size="14.0"/>
|
||||||
</font>
|
</font>
|
||||||
</JFXTextField>
|
</JFXTextField>
|
||||||
<JFXTextField fx:id="localPortTextField" alignment="CENTER" prefWidth="70.0" promptText="端口" styleClass="inputText-right" text="80">
|
<JFXTextField fx:id="localPortTextField" alignment="CENTER" minWidth="70.0"
|
||||||
|
prefWidth="100.0" promptText="端口" styleClass="inputText-right" text="80">
|
||||||
<font>
|
<font>
|
||||||
<Font size="14.0"/>
|
<Font size="14.0"/>
|
||||||
</font>
|
</font>
|
||||||
</JFXTextField>
|
</JFXTextField>
|
||||||
</children>
|
|
||||||
</HBox>
|
</HBox>
|
||||||
|
</HBox>
|
||||||
|
<HBox fx:id="domainPane" alignment="CENTER_LEFT" prefHeight="40.0" prefWidth="520.0">
|
||||||
<padding>
|
<padding>
|
||||||
<Insets bottom="10.0" top="10.0" />
|
<Insets top="10.0"/>
|
||||||
</padding>
|
</padding>
|
||||||
</HBox>
|
<Label alignment="CENTER_RIGHT" prefHeight="Infinity" prefWidth="100.0"
|
||||||
<HBox alignment="CENTER_LEFT" prefHeight="50.0" prefWidth="520.0">
|
styleClass="proxySetupLabel" text="外网访问地址">
|
||||||
<Label alignment="CENTER_RIGHT" prefHeight="Infinity" prefWidth="100.0" styleClass="proxySetupLabel" text="外网访问地址">
|
|
||||||
<HBox.margin>
|
<HBox.margin>
|
||||||
<Insets right="20.0"/>
|
<Insets right="20.0"/>
|
||||||
</HBox.margin>
|
</HBox.margin>
|
||||||
</Label>
|
</Label>
|
||||||
<HBox prefWidth="320.0">
|
<HBox prefWidth="320.0">
|
||||||
<JFXTextField fx:id="domainTextField" alignment="CENTER" prefHeight="30.0" prefWidth="280.0" promptText="自定义子域名大于3位" styleClass="inputText-left">
|
<JFXTextField fx:id="domainTextField" alignment="CENTER" prefHeight="30.0" prefWidth="320.0"
|
||||||
|
promptText="自定义子域名大于3位" styleClass="inputText-left">
|
||||||
<font>
|
<font>
|
||||||
<Font size="14.0"/>
|
<Font size="14.0"/>
|
||||||
</font>
|
</font>
|
||||||
</JFXTextField>
|
</JFXTextField>
|
||||||
<JFXTextField fx:id="domainSuffixTextField" alignment="CENTER" disable="true" minWidth="155.0" prefHeight="30.0" styleClass="inputText-right" text=".frp.octopusyan.top">
|
<JFXTextField fx:id="domainSuffixTextField" alignment="CENTER" disable="true"
|
||||||
|
minWidth="155.0" prefHeight="30.0" styleClass="inputText-right"
|
||||||
|
text=".frp.octopusyan.top">
|
||||||
<font>
|
<font>
|
||||||
<Font size="14.0"/>
|
<Font size="14.0"/>
|
||||||
</font>
|
</font>
|
||||||
@ -137,48 +183,58 @@
|
|||||||
</HBox>
|
</HBox>
|
||||||
<JFXButton fx:id="customizeDomainBtn" prefHeight="Infinity" text="自定义">
|
<JFXButton fx:id="customizeDomainBtn" prefHeight="Infinity" text="自定义">
|
||||||
<HBox.margin>
|
<HBox.margin>
|
||||||
<Insets left="10.0" />
|
<Insets left="5.0"/>
|
||||||
</HBox.margin>
|
</HBox.margin>
|
||||||
|
<cursor>
|
||||||
|
<Cursor fx:constant="HAND"/>
|
||||||
|
</cursor>
|
||||||
</JFXButton>
|
</JFXButton>
|
||||||
<padding>
|
|
||||||
<Insets bottom="10.0" top="10.0" />
|
|
||||||
</padding>
|
|
||||||
</HBox>
|
</HBox>
|
||||||
<HBox alignment="CENTER_LEFT" prefHeight="50.0" prefWidth="520.0">
|
<Label fx:id="domainHtinTextField" alignment="CENTER" prefHeight="20.0" prefWidth="320.0"
|
||||||
<Label alignment="CENTER_RIGHT" prefHeight="Infinity" prefWidth="100.0" styleClass="proxySetupLabel" text="用户名 (可选)">
|
text="Label" visible="false">
|
||||||
|
<VBox.margin>
|
||||||
|
<Insets left="120.0"/>
|
||||||
|
</VBox.margin>
|
||||||
|
<font>
|
||||||
|
<Font size="14.0"/>
|
||||||
|
</font>
|
||||||
|
</Label>
|
||||||
|
<HBox fx:id="proxyStatusPane" alignment="CENTER" prefHeight="40.0" prefWidth="520.0">
|
||||||
|
<padding>
|
||||||
|
<Insets bottom="10.0"/>
|
||||||
|
</padding>
|
||||||
|
<Label alignment="CENTER_RIGHT" prefHeight="30.0" styleClass="proxySetupLabel"
|
||||||
|
text="启动成功!立即访问 ">
|
||||||
<HBox.margin>
|
<HBox.margin>
|
||||||
<Insets right="20.0" />
|
<Insets/>
|
||||||
</HBox.margin>
|
</HBox.margin>
|
||||||
</Label>
|
</Label>
|
||||||
<JFXTextField prefHeight="Infinity" prefWidth="320.0" styleClass="inputText">
|
<Hyperlink fx:id="domainLink" prefHeight="30.0"/>
|
||||||
<padding>
|
<JFXButton fx:id="copyDomainBtn" prefHeight="30.0" text="复制"/>
|
||||||
<Insets left="10.0" />
|
|
||||||
</padding>
|
|
||||||
</JFXTextField>
|
|
||||||
<padding>
|
|
||||||
<Insets bottom="10.0" top="10.0" />
|
|
||||||
</padding>
|
|
||||||
</HBox>
|
</HBox>
|
||||||
<padding>
|
|
||||||
<Insets left="10.0" top="40.0" />
|
|
||||||
</padding>
|
|
||||||
</VBox>
|
</VBox>
|
||||||
<VBox fx:id="proxyListPane" prefHeight="Infinity" prefWidth="Infinity" GridPane.columnIndex="1">
|
<VBox fx:id="proxyListPane" prefHeight="Infinity" prefWidth="Infinity" GridPane.columnIndex="1">
|
||||||
<JFXListView fx:id="proxyListView" prefHeight="360.0" prefWidth="Infinity"/>
|
<JFXListView fx:id="proxyListView" prefHeight="360.0" prefWidth="Infinity"/>
|
||||||
<JFXButton fx:id="addProxyBtn" prefHeight="45.0" prefWidth="Infinity" text="新增连接">
|
<JFXButton fx:id="addProxyBtn" prefHeight="45.0" prefWidth="Infinity" text="新增连接">
|
||||||
<graphic>
|
<graphic>
|
||||||
<FontIcon iconLiteral="fa-plus" />
|
<FontIcon iconColor="white" iconLiteral="fa-plus"/>
|
||||||
</graphic>
|
</graphic>
|
||||||
|
<cursor>
|
||||||
|
<Cursor fx:constant="HAND"/>
|
||||||
|
</cursor>
|
||||||
</JFXButton>
|
</JFXButton>
|
||||||
</VBox>
|
</VBox>
|
||||||
<AnchorPane prefHeight="Infinity" prefWidth="Infinity" GridPane.rowIndex="1">
|
<AnchorPane prefHeight="Infinity" prefWidth="Infinity" GridPane.rowIndex="1">
|
||||||
<JFXTabPane fx:id="tabPane" prefHeight="230" prefWidth="520.0" styleClass="mainPane">
|
<JFXTabPane fx:id="tabPane" prefHeight="230" prefWidth="520.0" styleClass="mainPane">
|
||||||
<tabs>
|
<tabs>
|
||||||
<Tab text=" 日志 ">
|
<Tab fx:id="proxyLogPane" text=" 日志 ">
|
||||||
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" />
|
<JFXTextArea prefWidth="Infinity"/>
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab text="常见问题">
|
<Tab text="常见问题">
|
||||||
<VBox minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
|
<VBox minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
|
||||||
|
<padding>
|
||||||
|
<Insets left="20.0" top="20.0"/>
|
||||||
|
</padding>
|
||||||
<HBox prefHeight="30.0" prefWidth="Infinity">
|
<HBox prefHeight="30.0" prefWidth="Infinity">
|
||||||
<Label prefHeight="Infinity" text="* 若启动后无法通过外网访问,请点击"/>
|
<Label prefHeight="Infinity" text="* 若启动后无法通过外网访问,请点击"/>
|
||||||
<Hyperlink prefHeight="Infinity" text="此处"/>
|
<Hyperlink prefHeight="Infinity" text="此处"/>
|
||||||
@ -188,9 +244,6 @@
|
|||||||
<Label prefHeight="30" text="* 只有启动或重启内网穿透服务时,配置信息才会被保存"/>
|
<Label prefHeight="30" text="* 只有启动或重启内网穿透服务时,配置信息才会被保存"/>
|
||||||
<Label prefHeight="30" text="* 同一个账号在同一时间只能在一台电脑上登录使用"/>
|
<Label prefHeight="30" text="* 同一个账号在同一时间只能在一台电脑上登录使用"/>
|
||||||
<Label prefHeight="30" text="* 请勿将非法、暴力、色情等信息映射到外网上去,一经发现立即封号"/>
|
<Label prefHeight="30" text="* 请勿将非法、暴力、色情等信息映射到外网上去,一经发现立即封号"/>
|
||||||
<padding>
|
|
||||||
<Insets left="20.0" top="20.0" />
|
|
||||||
</padding>
|
|
||||||
</VBox>
|
</VBox>
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab text="使用场景">
|
<Tab text="使用场景">
|
||||||
@ -200,16 +253,23 @@
|
|||||||
</Tab>
|
</Tab>
|
||||||
</tabs>
|
</tabs>
|
||||||
</JFXTabPane>
|
</JFXTabPane>
|
||||||
<JFXButton layoutX="480.0" layoutY="-1.0" prefHeight="35.0" prefWidth="26.0" text="">
|
<JFXButton fx:id="clearLogBtn" layoutX="480.0" layoutY="-1.0" prefHeight="35.0" prefWidth="26.0"
|
||||||
|
text="">
|
||||||
<graphic>
|
<graphic>
|
||||||
<FontIcon iconColor="white" iconLiteral="fa-trash-o" iconSize="18"/>
|
<FontIcon iconColor="white" iconLiteral="fa-trash-o" iconSize="18"/>
|
||||||
</graphic>
|
</graphic>
|
||||||
|
<cursor>
|
||||||
|
<Cursor fx:constant="HAND"/>
|
||||||
|
</cursor>
|
||||||
</JFXButton>
|
</JFXButton>
|
||||||
</AnchorPane>
|
</AnchorPane>
|
||||||
<VBox prefHeight="200.0" prefWidth="100.0" GridPane.columnIndex="1" GridPane.rowIndex="1">
|
<VBox prefHeight="200.0" prefWidth="100.0" GridPane.columnIndex="1" GridPane.rowIndex="1">
|
||||||
<children>
|
<JFXButton fx:id="startProxyBtn" buttonType="RAISED" prefHeight="44.0" prefWidth="202.0"
|
||||||
<JFXButton fx:id="startProxyBtn" buttonType="RAISED" prefHeight="44.0" prefWidth="202.0" text="启动" />
|
styleClass="startProxyBtn" text="启动">
|
||||||
</children>
|
<cursor>
|
||||||
|
<Cursor fx:constant="HAND"/>
|
||||||
|
</cursor>
|
||||||
|
</JFXButton>
|
||||||
</VBox>
|
</VBox>
|
||||||
</children>
|
</children>
|
||||||
</GridPane>
|
</GridPane>
|
||||||
|
BIN
src/main/resources/static/frpc.exe
Normal file
BIN
src/main/resources/static/frpc.exe
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user