commit
This commit is contained in:
parent
8c41c8392b
commit
13fa56b76f
71
pom.xml
71
pom.xml
@ -55,6 +55,7 @@
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.14</version>
|
||||
<scope>compile</scope> <!-- 解决 slf4j 冲突问题 -->
|
||||
</dependency>
|
||||
|
||||
<!-- slf4j -->
|
||||
@ -70,12 +71,19 @@
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- commons-lang3 -->
|
||||
<!-- commons -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.12.0</version>
|
||||
</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>
|
||||
<groupId>cn.hutool</groupId>
|
||||
@ -157,25 +165,60 @@
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.openjfx</groupId>
|
||||
<groupId>com.zenjava</groupId>
|
||||
<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>
|
||||
<execution>
|
||||
<!-- Default configuration for running with: mvn clean javafx:run -->
|
||||
<id>default-cli</id>
|
||||
<configuration>
|
||||
<mainClass>top.octopusyan/top.octopusyan.YanFrpLauncher</mainClass>
|
||||
<launcher>app</launcher>
|
||||
<jlinkZipName>app</jlinkZipName>
|
||||
<jlinkImageName>app</jlinkImageName>
|
||||
<noManPages>true</noManPages>
|
||||
<stripDebug>true</stripDebug>
|
||||
<noHeaderFiles>true</noHeaderFiles>
|
||||
</configuration>
|
||||
<id>make-assembly</id>
|
||||
<!-- 绑定到package生命周期 -->
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<!-- 只运行一次 -->
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>top.octopusyan.YanFrpLuncher</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
</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>
|
||||
</build>
|
||||
|
||||
|
@ -1,21 +1,25 @@
|
||||
package top.octopusyan;
|
||||
|
||||
import com.sun.org.slf4j.internal.Logger;
|
||||
import com.sun.org.slf4j.internal.LoggerFactory;
|
||||
import javafx.application.Application;
|
||||
import javafx.application.Platform;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.fxml.JavaFXBuilderFactory;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.StageStyle;
|
||||
import top.octopusyan.common.http.HttpConfig;
|
||||
import top.octopusyan.common.http.config.LogStrategy;
|
||||
import top.octopusyan.common.http.request.RequestHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
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.utils.AlertUtil;
|
||||
import top.octopusyan.utils.ApplicatonStore;
|
||||
import top.octopusyan.utils.FrpUtil;
|
||||
import top.octopusyan.utils.FxmlUtil;
|
||||
|
||||
/**
|
||||
* @author : octopus yan
|
||||
@ -24,12 +28,15 @@ import top.octopusyan.utils.ApplicatonStore;
|
||||
* @create : 2022-3-29 15:00
|
||||
*/
|
||||
public class YanFrpApplication extends Application {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(YanFrpApplication.class);
|
||||
private static final Logger logger = LoggerFactory.getLogger(YanFrpApplication.class);
|
||||
|
||||
@Override
|
||||
public void init() throws Exception {
|
||||
super.init();
|
||||
LOGGER.debug("init...");
|
||||
logger.info("init...");
|
||||
|
||||
// 初始化frp客户端临时文件
|
||||
FrpUtil.initFrpc();
|
||||
|
||||
// 网络请求设置
|
||||
HttpConfig.with(OkHttpClientConfig.httpClient())
|
||||
@ -49,7 +56,7 @@ public class YanFrpApplication extends Application {
|
||||
|
||||
@Override
|
||||
public void start(Stage stage) {
|
||||
LOGGER.debug("start...");
|
||||
logger.info("start...");
|
||||
|
||||
// TODO 全局异常处理... (emm有点草率,先这样了。。)
|
||||
Thread.setDefaultUncaughtExceptionHandler((t, e) -> Platform.runLater(() -> showErrorDialog(t, e)));
|
||||
@ -61,8 +68,12 @@ public class YanFrpApplication extends Application {
|
||||
ApplicatonStore.setRegisterSuccess(false);
|
||||
|
||||
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);
|
||||
StackPane root = new FXMLLoader(this.getClass().getResource("/fxml/login.fxml")).load();//底层面板
|
||||
Scene scene = new Scene(
|
||||
root,
|
||||
root.getPrefWidth() + 20,
|
||||
@ -73,22 +84,26 @@ public class YanFrpApplication extends Application {
|
||||
stage.setScene(scene);
|
||||
stage.show();
|
||||
|
||||
BaseController controller = fxmlLoader.getController();
|
||||
controller.setApplication(this);
|
||||
|
||||
} catch (Throwable t) {
|
||||
showErrorDialog(Thread.currentThread(), t);
|
||||
}
|
||||
|
||||
LOGGER.debug("start end...");
|
||||
logger.debug("start end...");
|
||||
}
|
||||
|
||||
private void showErrorDialog(Thread t, Throwable e) {
|
||||
e.printStackTrace();
|
||||
AlertUtil.exceptionAlert(new Exception(e)).show();
|
||||
Platform.runLater(() -> AlertUtil.exceptionAlert(new Exception(e)).show());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() throws Exception {
|
||||
super.stop();
|
||||
LOGGER.debug("stop...");
|
||||
FrpUtil.clearTmp();
|
||||
logger.info("stop...");
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
import com.jfoenix.controls.JFXButton;
|
||||
import javafx.application.Application;
|
||||
import javafx.application.Platform;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.fxml.Initializable;
|
||||
@ -11,6 +12,7 @@ import javafx.scene.layout.Pane;
|
||||
import javafx.stage.Stage;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import top.octopusyan.utils.FxmlUtil;
|
||||
import top.octopusyan.utils.Loading;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -25,21 +27,35 @@ import java.util.ResourceBundle;
|
||||
*/
|
||||
public abstract class BaseController<P extends Pane> implements Initializable {
|
||||
|
||||
private Application application;
|
||||
|
||||
private double xOffSet = 0, yOffSet = 0;
|
||||
|
||||
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();
|
||||
try {
|
||||
Pane root = FXMLLoader.load(getClass().getResource(controller.getRootFxmlPath()));
|
||||
scene.setRoot(root);
|
||||
Stage stage = (Stage) scene.getWindow();
|
||||
stage.setWidth(root.getPrefWidth() + 20);
|
||||
stage.setHeight(root.getPrefHeight() + 20);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
double oldHeight = getRootPanel().getPrefHeight();
|
||||
double oldWidth = getRootPanel().getPrefWidth();
|
||||
|
||||
Pane root = fxmlLoader.load();
|
||||
Stage stage = (Stage) scene.getWindow();
|
||||
// 窗口大小
|
||||
double newWidth = root.getPrefWidth() + 20;
|
||||
double newHeight = root.getPrefHeight() + 20;
|
||||
// 窗口位置
|
||||
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
|
||||
@ -86,21 +102,29 @@ public abstract class BaseController<P extends Pane> implements Initializable {
|
||||
initViewAction();
|
||||
}
|
||||
|
||||
public void showLoading(){
|
||||
public void showLoading() {
|
||||
showLoading(null);
|
||||
}
|
||||
|
||||
public void showLoading(String message){
|
||||
if(loading == null) loading = new Loading((Stage) getRootPanel().getScene().getWindow());
|
||||
if(!StringUtils.isEmpty(message))loading.showMessage(message);
|
||||
public void showLoading(String message) {
|
||||
if (loading == null) loading = new Loading((Stage) getRootPanel().getScene().getWindow());
|
||||
if (!StringUtils.isEmpty(message)) loading.showMessage(message);
|
||||
loading.show();
|
||||
}
|
||||
|
||||
public boolean isLoadShowing(){
|
||||
public void setApplication(Application application) {
|
||||
this.application = application;
|
||||
}
|
||||
|
||||
public Application getApplication() {
|
||||
return application;
|
||||
}
|
||||
|
||||
public boolean isLoadShowing() {
|
||||
return loading != null && loading.showing();
|
||||
}
|
||||
|
||||
public void stopLoading(){
|
||||
public void stopLoading() {
|
||||
loading.closeStage();
|
||||
}
|
||||
|
||||
@ -159,11 +183,16 @@ public abstract class BaseController<P extends Pane> implements Initializable {
|
||||
/**
|
||||
* 关闭窗口
|
||||
*/
|
||||
public void onDestroy(){
|
||||
public void onDestroy() {
|
||||
Stage stage = (Stage) getRootPanel().getScene().getWindow();
|
||||
stage.hide();
|
||||
stage.close();
|
||||
Platform.exit();
|
||||
System.exit(0);
|
||||
try {
|
||||
Thread.sleep(2000);
|
||||
Platform.exit();
|
||||
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;
|
||||
|
||||
import lombok.Getter;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@ -10,14 +14,19 @@ import java.util.Map;
|
||||
* @create : 2022-4-5 18:14
|
||||
*/
|
||||
public class ProxyConfig {
|
||||
private static Map<String, String> serverPath = new HashMap<>();
|
||||
private static Map<String, Integer> typePort = new HashMap<>();
|
||||
private static final Map<String, String> serverPath = new HashMap<>();
|
||||
private static final Map<String, String> serverIp = new HashMap<>();
|
||||
private static final Map<String, Integer> typePort = new HashMap<>();
|
||||
|
||||
static {
|
||||
serverPath.put("香港", "xg.frp.octopusyan.top");
|
||||
serverPath.put("北京", "bj.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("https", 80);
|
||||
typePort.put("ssh", 22);
|
||||
@ -25,8 +34,25 @@ public class ProxyConfig {
|
||||
}
|
||||
|
||||
|
||||
@Getter
|
||||
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 {
|
||||
@ -36,7 +62,7 @@ public class ProxyConfig {
|
||||
TCP("tcp"),
|
||||
;
|
||||
|
||||
private String type;
|
||||
private final String type;
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
@ -51,7 +77,49 @@ public class ProxyConfig {
|
||||
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) {
|
||||
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.JFXTextField;
|
||||
import javafx.application.Platform;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import javafx.scene.paint.Color;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
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 top.octopusyan.base.BaseController;
|
||||
import top.octopusyan.common.http.EasyHttp;
|
||||
import top.octopusyan.common.http.api.NotParamApi;
|
||||
import top.octopusyan.common.http.config.HttpConstant;
|
||||
import top.octopusyan.common.http.listener.OnHttpListener;
|
||||
import top.octopusyan.manager.http.EasyHttp;
|
||||
import top.octopusyan.manager.http.api.NotParamApi;
|
||||
import top.octopusyan.manager.http.config.HttpConstant;
|
||||
import top.octopusyan.manager.http.listener.OnHttpListener;
|
||||
import top.octopusyan.config.TextValidate;
|
||||
import top.octopusyan.http.Api;
|
||||
import top.octopusyan.http.request.LoginParam;
|
||||
import top.octopusyan.http.request.ProxySetup;
|
||||
import top.octopusyan.utils.AlertUtil;
|
||||
import top.octopusyan.utils.ApplicatonStore;
|
||||
import top.octopusyan.utils.ProxyUtil;
|
||||
import top.octopusyan.utils.TextValidate;
|
||||
import top.octopusyan.utils.*;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.stream.Collectors;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author : octopus yan
|
||||
@ -119,8 +108,8 @@ public class LoginController extends BaseController<StackPane> implements Initia
|
||||
String account = ApplicatonStore.getAccount();
|
||||
String password = ApplicatonStore.getPassword();
|
||||
|
||||
if(!StringUtils.isEmpty(account)) accountTextField.setText(account);
|
||||
if(!StringUtils.isEmpty(password)) {
|
||||
if (!StringUtils.isEmpty(account)) accountTextField.setText(account);
|
||||
if (!StringUtils.isEmpty(password)) {
|
||||
passwordTextField.setText(password);
|
||||
seePwdTextField.setText(password);
|
||||
}
|
||||
@ -172,7 +161,13 @@ public class LoginController extends BaseController<StackPane> implements Initia
|
||||
public void initViewAction() {
|
||||
|
||||
// 注册
|
||||
registerBtn.setOnMouseClicked(event -> jumpTo(new RegisterController()));
|
||||
registerBtn.setOnMouseClicked(event -> {
|
||||
try {
|
||||
jumpTo(new RegisterController());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
|
||||
// 查看密码
|
||||
seePwdIconBtn.setOnMouseClicked(event -> {
|
||||
@ -187,22 +182,23 @@ public class LoginController extends BaseController<StackPane> implements Initia
|
||||
// 登录
|
||||
loginBtn.setOnMouseClicked(event -> login());
|
||||
accountTextField.setOnKeyPressed(event -> {
|
||||
if(event.getCode() == KeyCode.ENTER) login();
|
||||
if (event.getCode() == KeyCode.ENTER) login();
|
||||
});
|
||||
passwordTextField.setOnKeyPressed(event -> {
|
||||
if(event.getCode() == KeyCode.ENTER) login();
|
||||
if (event.getCode() == KeyCode.ENTER) login();
|
||||
});
|
||||
|
||||
// 自动登录
|
||||
if((ApplicatonStore.isAutoLogin() || ApplicatonStore.isRegisterSuccess()) &&
|
||||
if ((ApplicatonStore.isAutoLogin() || ApplicatonStore.isRegisterSuccess()) &&
|
||||
!StringUtils.isEmpty(ApplicatonStore.getAccount()) &&
|
||||
!StringUtils.isEmpty(ApplicatonStore.getPassword())
|
||||
){
|
||||
) {
|
||||
login();
|
||||
}
|
||||
}
|
||||
|
||||
private void login(){
|
||||
private void login() {
|
||||
|
||||
// 获取文本校验结果
|
||||
boolean pwdValidate = pwdParent.getChildren().contains(passwordTextField) ?
|
||||
passwordTextField.validate() : seePwdTextField.validate();
|
||||
@ -215,15 +211,20 @@ public class LoginController extends BaseController<StackPane> implements Initia
|
||||
.request(new OnHttpListener<String>() {
|
||||
@Override
|
||||
public void onSucceed(String result) {
|
||||
Document html = Jsoup.parse(result);
|
||||
// 登录出错
|
||||
if (result.contains("alert-danger")) {
|
||||
Platform.runLater(() -> AlertUtil.error(getHtmlErrorMessage(html)).show());
|
||||
if (!JsoupUtil.isAlertSuccess(result)) {
|
||||
Platform.runLater(() -> AlertUtil.error(JsoupUtil.getErrorMessage(result)).show());
|
||||
return;
|
||||
}
|
||||
// TODO 登录成功
|
||||
setCsrf();
|
||||
jumpTo(new MainController());
|
||||
Platform.runLater(() -> {
|
||||
try {
|
||||
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
|
||||
public void onDestroy() {
|
||||
EasyHttp.cancel();
|
||||
|
@ -1,14 +1,22 @@
|
||||
package top.octopusyan.controller;
|
||||
|
||||
import com.jfoenix.controls.*;
|
||||
import com.jfoenix.validation.IntegerValidator;
|
||||
import com.jfoenix.validation.RequiredFieldValidator;
|
||||
import javafx.application.HostServices;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.property.SimpleIntegerProperty;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.layout.HBox;
|
||||
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.ProxyType;
|
||||
import top.octopusyan.http.request.ProxySetup;
|
||||
import top.octopusyan.model.ProxySetupModel;
|
||||
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.config.TextValidate;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.datatransfer.Clipboard;
|
||||
import java.awt.datatransfer.StringSelection;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.*;
|
||||
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_RUN_CLASS = "proxyListItem-run";
|
||||
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
|
||||
public StackPane root;
|
||||
@ -48,11 +64,9 @@ public class MainController extends BaseController<StackPane> implements Initial
|
||||
public JFXButton closeBtn, minimizeBtn;
|
||||
|
||||
@FXML
|
||||
public JFXButton startProxyBtn;
|
||||
public JFXButton startProxyBtn, addProxyBtn;
|
||||
@FXML
|
||||
public JFXButton addProxyBtn;
|
||||
@FXML
|
||||
public JFXComboBox<Label> proxyProtocolCombox;
|
||||
public JFXComboBox<String> proxyProtocolComboBox;
|
||||
@FXML
|
||||
public JFXButton customizeDomainBtn;
|
||||
@FXML
|
||||
@ -62,17 +76,32 @@ public class MainController extends BaseController<StackPane> implements Initial
|
||||
@FXML
|
||||
public JFXTextField proxyNameTextField, localHostTextField, localPortTextField;
|
||||
@FXML
|
||||
public JFXComboBox<Label> proxyServerCB;
|
||||
public JFXComboBox<String> proxyServerComboBox;
|
||||
@FXML
|
||||
public JFXTabPane tabPane;
|
||||
@FXML
|
||||
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 boolean customizeDomain = false;
|
||||
private List<ProxySetup> proxyList;
|
||||
private int selectProxy = 0;
|
||||
private SimpleBooleanProperty customizeDomain = new SimpleBooleanProperty(false);
|
||||
private List<ProxySetup> proxyList = new ArrayList<>();
|
||||
private Map<String, FrpUtil> frpUtilMap = new HashMap<>();
|
||||
private SimpleIntegerProperty selectProxy = new SimpleIntegerProperty(0);
|
||||
private ProxySetupModel proxySetupModel;
|
||||
private ProxySetup proxySetup;
|
||||
private SimpleBooleanProperty setting = new SimpleBooleanProperty(false);
|
||||
|
||||
@Override
|
||||
public boolean dragWindow() {
|
||||
@ -107,194 +136,294 @@ public class MainController extends BaseController<StackPane> implements Initial
|
||||
|
||||
@Override
|
||||
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 -> {
|
||||
proxyList = setupList;
|
||||
|
||||
// 主线程执行
|
||||
Platform.runLater(() -> {
|
||||
// 设置隧道列表
|
||||
ApplicatonStore.setProxySetupList(proxyList);
|
||||
if (setupList != null)
|
||||
proxyList = setupList;
|
||||
|
||||
// 初始化隧道设置
|
||||
if (proxyList != null && proxyList.size() > 0) {
|
||||
// 显示隧道列表
|
||||
initProxyList(proxyList);
|
||||
// 显示隧道设置
|
||||
proxySetup = proxyList.get(0);
|
||||
// 默认选中第一个
|
||||
proxyListView.getSelectionModel().select(0);
|
||||
} else {
|
||||
proxySetup = ProxyUtil.initProxy();
|
||||
proxyList = new ArrayList<>();
|
||||
proxyList.add(proxySetup);
|
||||
initProxySetupView(proxySetup);
|
||||
}
|
||||
});
|
||||
// 如果用户隧道列表不为空
|
||||
if (proxyList != null && proxyList.size() > 0) {
|
||||
// 显示隧道列表
|
||||
initProxyList(proxyList);
|
||||
// 默认选中第一个(配置隧道设置模型)
|
||||
proxyListView.getSelectionModel().select(0);
|
||||
} else {
|
||||
// 配置隧道设置模型
|
||||
proxyList = new ArrayList<>();
|
||||
proxyList.add(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
|
||||
public void initViewStyle() {
|
||||
// 启用链接
|
||||
openProxyRBtn.setToggleGroup(openProxyGroup);
|
||||
openProxyRBtn.setSelected(true);
|
||||
closeProxyRBtn.setToggleGroup(openProxyGroup);
|
||||
openProxyRBtn.setUserData(true);
|
||||
closeProxyRBtn.setUserData(false);
|
||||
openProxyRBtn.setSelected(true);
|
||||
|
||||
// 默认展示 常见问题
|
||||
// 是否启用
|
||||
proxySetupModel.statusProperty().addListener((observable, oldValue, newValue) -> {
|
||||
openProxyRBtn.setSelected(newValue);
|
||||
closeProxyRBtn.setSelected(!newValue);
|
||||
closeProxy(!newValue);
|
||||
});
|
||||
proxySetupModel.proxyTypeProperty().addListener((observable, oldValue, newValue) -> {
|
||||
String newType = StringUtils.lowerCase(newValue);
|
||||
String port, host;
|
||||
if (!newType.equals(proxySetup.getProxy_type())) {
|
||||
host = "127.0.0.1";
|
||||
port = ProxyConfig.getTypePort(newType).toString();
|
||||
} else {
|
||||
host = proxySetupModel.getLocalIp();
|
||||
port = proxySetupModel.getLocalPort();
|
||||
}
|
||||
// 域名提示
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置外网访问域名
|
||||
*/
|
||||
private void setDomain(ProxySetup setup) {
|
||||
|
||||
if (setup != null) {
|
||||
String serverName = ProxyServer.values()[setup.getNode()].name();
|
||||
String setupDomain = setup.getDomain();
|
||||
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 {
|
||||
domainTextField.styleProperty().set("-fx-border-radius: 5 0 0 5");
|
||||
domainSuffixTextField.setVisible(true);
|
||||
customizeDomainBtn.setText("自定义");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
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(
|
||||
(ObservableValue<? extends Toggle> ov, Toggle old_toggle, Toggle new_toggle) -> {
|
||||
Toggle toggle = openProxyGroup.getSelectedToggle();
|
||||
if (toggle != null) {
|
||||
closeProxy(!(Boolean) toggle.getUserData());
|
||||
// 设置状态
|
||||
proxySetupModel.setStatus((Boolean) toggle.getUserData());
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// 隧道类型
|
||||
proxyProtocolCombox.valueProperty().addListener((observable, oldValue, newValue) -> {
|
||||
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();
|
||||
// 自定义访问域名
|
||||
customizeDomainBtn.setOnMouseClicked((event) -> customizeDomain.set(!customizeDomain.get()));
|
||||
|
||||
// 设置默认端口
|
||||
localPortTextField.setText(port);
|
||||
// 设置隧道类型
|
||||
proxySetup.setProxy_type(newType);
|
||||
// 本地IP检查
|
||||
localHostTextField.getValidators().add(TextValidate.IpRequired);
|
||||
localHostTextField.getValidators().add(TextValidate.IpFormat);
|
||||
localHostTextField.textProperty().addListener((observable, oldValue, newValue) -> {
|
||||
localHostTextField.validate();
|
||||
});
|
||||
|
||||
// 自定义访问域名
|
||||
customizeDomainBtn.setOnMouseClicked((event) -> {
|
||||
setDomain(proxySetup != null ? proxySetup : null);
|
||||
// 端口检查
|
||||
localPortTextField.getValidators().add(TextValidate.PortRequired);
|
||||
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) -> {
|
||||
ObservableList<Label> items = proxyListView.getItems();
|
||||
for (Label item : items) {
|
||||
item.getStyleClass().remove(PROXY_LIST_ITEM_SELECT_CLASS);
|
||||
}
|
||||
if (newValue != null) {
|
||||
for (ProxySetup setup : proxyList) {
|
||||
if (setup.getProxy_name().equals(newValue.getText()))
|
||||
initProxySetupView(setup);
|
||||
}
|
||||
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 -> {
|
||||
// 保存运行状态
|
||||
proxyList.get(selectProxy.get()).setRuning(proxySetupModel.isRunning());
|
||||
// 获取默认隧道设置
|
||||
proxySetup = ProxyUtil.initProxy();
|
||||
proxySetup = ProxyUtil.initProxy(proxyList.get(proxyList.size() - 1).getSort());
|
||||
// 加入列表
|
||||
proxyList.add(proxySetup);
|
||||
selectProxy = proxyList.indexOf(proxySetup);
|
||||
initProxyList(proxyList);
|
||||
// 展示
|
||||
initProxySetupView(proxySetup);
|
||||
proxyListView.getSelectionModel().select(proxyList.size() - 1);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示隧道设置
|
||||
*/
|
||||
private void initProxySetupView(ProxySetup setup) {
|
||||
// 启动
|
||||
startProxyBtn.setOnMouseClicked(event -> {
|
||||
if (proxySetupModel.isRunning())
|
||||
stopProxy();
|
||||
else
|
||||
startProxy();
|
||||
});
|
||||
|
||||
int select = proxyList.indexOf(setup);
|
||||
//
|
||||
if (setup.getLocal_ip() == null && ProxyUtil.info(setup) == null) {
|
||||
AlertUtil.error("隧道设置获取失败!").show();
|
||||
if (select != selectProxy) {
|
||||
proxyListView.getSelectionModel().select(select);
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 链接跳转
|
||||
domainLink.setOnMouseClicked(event -> {
|
||||
getApplication().getHostServices().showDocument(domainLink.getText());
|
||||
});
|
||||
|
||||
// 选中的隧道下标
|
||||
selectProxy = select;
|
||||
|
||||
// 隧道类型
|
||||
for (Label label : proxyProtocolCombox.getItems()) {
|
||||
// 获取用户设置
|
||||
if (StringUtils.lowerCase(label.getText()).equals(setup.getProxy_type()))
|
||||
proxyProtocolCombox.getSelectionModel().select(proxyProtocolCombox.getItems().indexOf(label));
|
||||
}
|
||||
|
||||
// 服务器
|
||||
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());
|
||||
// 复制外网访问地址
|
||||
copyDomainBtn.setOnMouseClicked(event -> {
|
||||
//获取系统剪切板
|
||||
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
|
||||
//构建String数据类型
|
||||
StringSelection selection = new StringSelection(domainLink.getText());
|
||||
//添加文本到系统剪切板
|
||||
clipboard.setContents(selection, null);
|
||||
// 复制成功提示
|
||||
AlertUtil.info("复制成功,快去分享给小伙伴吧!").show();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -307,8 +436,9 @@ public class MainController extends BaseController<StackPane> implements Initial
|
||||
for (ProxySetup proxy : proxyList) {
|
||||
try {
|
||||
Label label = FXMLLoader.load(getClass().getResource("/fxml/proxyItem.fxml"));
|
||||
label.setText(proxy.getProxy_name());
|
||||
label.getStyleClass().addAll(PROXY_LIST_ITEM_CLASS, PROXY_LIST_ITEM_STOP_CLASS);
|
||||
label.textProperty().set(proxy.getProxy_name());
|
||||
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);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
@ -320,23 +450,23 @@ public class MainController extends BaseController<StackPane> implements Initial
|
||||
* 是否启用当前隧道
|
||||
*/
|
||||
private void closeProxy(boolean close) {
|
||||
if (close && proxySetup.isRuning()) stopProxy();
|
||||
if (close && proxySetupModel.isRunning()) stopProxy();
|
||||
|
||||
proxyNameTextField.setDisable(close);// 隧道名称
|
||||
proxyProtocolCombox.setDisable(close);// 隧道类型
|
||||
proxyProtocolComboBox.setDisable(close);// 隧道类型
|
||||
localHostTextField.setDisable(close);// 本地地址
|
||||
localPortTextField.setDisable(close);// 本地端口
|
||||
domainTextField.setDisable(close); // 外网子域名
|
||||
startProxyBtn.setDisable(close); // 启动按钮
|
||||
|
||||
ObservableList<String> styleClass = proxyListView.getItems().get(selectProxy).getStyleClass();
|
||||
ObservableList<String> styleClass = proxyListView.getItems().get(selectProxy.get()).getStyleClass();
|
||||
styleClass.remove(PROXY_LIST_ITEM_STOP_CLASS);
|
||||
styleClass.remove(PROXY_LIST_ITEM_RUN_CLASS);
|
||||
styleClass.remove(PROXY_LIST_ITEM_CLOSE_CLASS);
|
||||
if (close) {
|
||||
styleClass.remove(PROXY_LIST_ITEM_STOP_CLASS);
|
||||
styleClass.remove(PROXY_LIST_ITEM_RUN_CLASS);
|
||||
styleClass.add(PROXY_LIST_ITEM_CLOSE_CLASS);
|
||||
} else {
|
||||
styleClass.remove(PROXY_LIST_ITEM_CLOSE_CLASS);
|
||||
styleClass.add(proxySetup.isClose() ? PROXY_LIST_ITEM_CLOSE_CLASS : PROXY_LIST_ITEM_STOP_CLASS);
|
||||
styleClass.add(proxySetupModel.isRunning() ? PROXY_LIST_ITEM_RUN_CLASS : PROXY_LIST_ITEM_STOP_CLASS);
|
||||
}
|
||||
}
|
||||
|
||||
@ -344,21 +474,32 @@ public class MainController extends BaseController<StackPane> implements Initial
|
||||
* TODO 启动代理
|
||||
*/
|
||||
private void startProxy() {
|
||||
// 非 http 隧道系统随机分配端口
|
||||
if (!DomainUtil.isHttp(proxySetupModel)) {
|
||||
proxySetupModel.setRemotePort(String.valueOf(ProxyUtil.randomPort()));
|
||||
}
|
||||
|
||||
// 删除旧隧道
|
||||
if (proxySetup.getId() != null) ProxyUtil.delete(proxySetup.getId());
|
||||
if (proxySetupModel.getId() != null && !proxySetupModel.get().equals(proxySetup)) {
|
||||
// 删除旧隧道
|
||||
ProxyUtil.delete(proxySetupModel.getId());
|
||||
|
||||
// 添加隧道
|
||||
if (!ProxyUtil.add(result -> {
|
||||
}, proxySetup)) return;
|
||||
// 添加隧道
|
||||
ProxyUtil.add(result -> {
|
||||
proxySetup = result;
|
||||
proxySetupModel.set(proxySetup);
|
||||
}, proxySetupModel.get());
|
||||
}
|
||||
|
||||
// TODO 修改设置
|
||||
// TODO 调用cmd
|
||||
// 初始化frputil
|
||||
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);
|
||||
styleClass.add(PROXY_LIST_ITEM_RUN_CLASS);
|
||||
proxySetup.setRuning(true);
|
||||
// 设置文本域对象
|
||||
if (proxyLogPane.getContent() == null) proxyLogPane.contentProperty().set(frpUtil.getConsole());
|
||||
|
||||
// 开始
|
||||
frpUtil.start();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -366,7 +507,7 @@ public class MainController extends BaseController<StackPane> implements Initial
|
||||
*/
|
||||
private void stopProxy() {
|
||||
// 关闭CMD
|
||||
|
||||
proxySetup.setRuning(false);
|
||||
FrpUtil frpUtil = frpUtilMap.get(proxySetupModel.getProxyName());
|
||||
if (frpUtil != null) frpUtil.stop();
|
||||
}
|
||||
}
|
||||
|
@ -9,18 +9,18 @@ import javafx.scene.control.Button;
|
||||
import javafx.scene.layout.StackPane;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import top.octopusyan.base.BaseController;
|
||||
import top.octopusyan.common.http.EasyHttp;
|
||||
import top.octopusyan.common.http.listener.OnHttpListener;
|
||||
import top.octopusyan.manager.http.EasyHttp;
|
||||
import top.octopusyan.manager.http.listener.OnHttpListener;
|
||||
import top.octopusyan.http.Api;
|
||||
import top.octopusyan.http.request.RegisterParam;
|
||||
import top.octopusyan.http.request.SendEmailCheckParam;
|
||||
import top.octopusyan.utils.AlertUtil;
|
||||
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;
|
||||
|
||||
/**
|
||||
@ -81,8 +81,8 @@ public class RegisterController extends BaseController<StackPane> implements Ser
|
||||
String account = ApplicatonStore.getAccount();
|
||||
String password = ApplicatonStore.getPassword();
|
||||
|
||||
if(!StringUtils.isEmpty(account)) accooundTextField.setText(account);
|
||||
if(!StringUtils.isEmpty(password)) passwordTextField.setText(password);
|
||||
if (!StringUtils.isEmpty(account)) accooundTextField.setText(account);
|
||||
if (!StringUtils.isEmpty(password)) passwordTextField.setText(password);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -127,7 +127,13 @@ public class RegisterController extends BaseController<StackPane> implements Ser
|
||||
@Override
|
||||
public void initViewAction() {
|
||||
// 登录
|
||||
loginBtn.setOnMouseClicked(event -> jumpTo(new LoginController()));
|
||||
loginBtn.setOnMouseClicked(event -> {
|
||||
try {
|
||||
jumpTo(new LoginController());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
|
||||
// 点击了发送验证码
|
||||
sendCheckCodeBtn.setOnMouseClicked(event -> {
|
||||
@ -150,9 +156,9 @@ public class RegisterController extends BaseController<StackPane> implements Ser
|
||||
registerBtn.setOnMouseClicked(event -> register());
|
||||
}
|
||||
|
||||
private void register(){
|
||||
private void register() {
|
||||
// 文本校验
|
||||
if(accooundTextField.validate() && passwordTextField.validate() && emailTf.validate() && emailCheckCodeTf.validate()){
|
||||
if (accooundTextField.validate() && passwordTextField.validate() && emailTf.validate() && emailCheckCodeTf.validate()) {
|
||||
EasyHttp.builder()
|
||||
.api(Api.Register)
|
||||
.param(new RegisterParam(
|
||||
@ -161,34 +167,29 @@ public class RegisterController extends BaseController<StackPane> implements Ser
|
||||
ApplicatonStore.getEmail(),
|
||||
emailCheckCodeTf.getText()
|
||||
))
|
||||
.request(new OnHttpListener<String>() {
|
||||
@Override
|
||||
public void onSucceed(String result) {
|
||||
Document html = Jsoup.parse(result);
|
||||
// 注册出错
|
||||
if(result.contains("alert-danger")) {
|
||||
Platform.runLater(() -> AlertUtil.error(getHtmlErrorMessage(html)).header(null).show());
|
||||
return;
|
||||
}
|
||||
.request(result -> {
|
||||
// 注册出错
|
||||
if (JsoupUtil.isAlertSuccess(result)) {
|
||||
// 注册成功
|
||||
if(result.contains("alert-success")){
|
||||
Platform.runLater(() -> AlertUtil.info(getHtmlMessage(html)).header(null).show());
|
||||
ApplicatonStore.setRegisterSuccess(true);
|
||||
jumpTo(new LoginController());
|
||||
}
|
||||
}
|
||||
Platform.runLater(() ->
|
||||
AlertUtil.info(JsoupUtil.getHtmlMessage(result)).header(null).show()
|
||||
);
|
||||
ApplicatonStore.setRegisterSuccess(true);
|
||||
Platform.runLater(() -> {
|
||||
try {
|
||||
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
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
@ -1,10 +1,10 @@
|
||||
package top.octopusyan.http;
|
||||
|
||||
import top.octopusyan.common.http.api.NotParamApi;
|
||||
import top.octopusyan.common.http.api.ParamApi;
|
||||
import top.octopusyan.common.http.api.PathParamApi;
|
||||
import top.octopusyan.common.http.config.BodyType;
|
||||
import top.octopusyan.common.http.config.HttpConstant;
|
||||
import top.octopusyan.manager.http.api.NotParamApi;
|
||||
import top.octopusyan.manager.http.api.ParamApi;
|
||||
import top.octopusyan.manager.http.api.PathParamApi;
|
||||
import top.octopusyan.manager.http.config.BodyType;
|
||||
import top.octopusyan.manager.http.config.HttpConstant;
|
||||
import top.octopusyan.http.request.ProxySetup;
|
||||
import top.octopusyan.http.request.RegisterParam;
|
||||
import top.octopusyan.http.request.SendEmailCheckParam;
|
||||
@ -32,13 +32,19 @@ public class Api {
|
||||
BodyType.FORM
|
||||
);
|
||||
|
||||
/** 发送邮箱验证码 */
|
||||
/** 用户注册 */
|
||||
public static final ParamApi<RegisterParam, String> Register = new ParamApi<>(
|
||||
"/?action=register&page=register",
|
||||
HttpConstant.Method.POST,
|
||||
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<>(
|
||||
"/?page=panel&module=proxies",
|
||||
@ -71,7 +77,7 @@ public class Api {
|
||||
}
|
||||
|
||||
/** 随机端口 */
|
||||
public static NotParamApi<Integer> RandomPort() {
|
||||
public static NotParamApi<String> RandomPort() {
|
||||
return new NotParamApi<>(
|
||||
"/?page=panel&module=addproxy&randomport&csrf=" + ProxyUtil.getCsrf(),
|
||||
HttpConstant.Method.GET
|
||||
|
@ -7,8 +7,8 @@ import okio.BufferedSource;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import top.octopusyan.common.http.ssl.HttpSslConfig;
|
||||
import top.octopusyan.common.http.ssl.HttpSslFactory;
|
||||
import top.octopusyan.manager.http.ssl.HttpSslConfig;
|
||||
import top.octopusyan.manager.http.ssl.HttpSslFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
@ -70,7 +70,7 @@ public class OkHttpClientConfig {
|
||||
.cookieJar(cookieJar())
|
||||
.connectionPool(new ConnectionPool(16, 5, TimeUnit.MINUTES))
|
||||
.connectTimeout(10L, TimeUnit.SECONDS)
|
||||
.readTimeout(500L, TimeUnit.SECONDS)
|
||||
.readTimeout(30L, TimeUnit.SECONDS)
|
||||
.writeTimeout(0L, TimeUnit.SECONDS)
|
||||
.pingInterval(60L, TimeUnit.SECONDS)
|
||||
.sslSocketFactory(httpSslConfig.getSslSocketFactory(), httpSslConfig.getTrustManager())
|
||||
|
@ -1,6 +1,8 @@
|
||||
package top.octopusyan.http.request;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author : octopus yan
|
||||
@ -8,6 +10,8 @@ import lombok.Data;
|
||||
* @description :
|
||||
* @create : 2022-4-5 10:08
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public class ProxySetup {
|
||||
private Integer id;
|
||||
@ -16,7 +20,7 @@ public class ProxySetup {
|
||||
private String proxy_type;
|
||||
private String local_ip;
|
||||
private Integer local_port;
|
||||
private Integer remote_port;
|
||||
private String remote_port;
|
||||
private String domain;
|
||||
private Boolean use_encryption;
|
||||
private Boolean use_compression;
|
||||
@ -24,8 +28,8 @@ public class ProxySetup {
|
||||
private String host_header_rewrite;
|
||||
private String header_X_From_Where;
|
||||
private String sk;
|
||||
/** 是否启用 */
|
||||
private Boolean status;
|
||||
private int sort;
|
||||
private Integer sort;
|
||||
private boolean runing;
|
||||
private boolean isClose;
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
package top.octopusyan.common.http;
|
||||
package top.octopusyan.manager.http;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
import top.octopusyan.common.http.api.NotParamApi;
|
||||
import top.octopusyan.common.http.api.ParamApi;
|
||||
import top.octopusyan.common.http.config.HttpConstant;
|
||||
import top.octopusyan.common.http.config.LogStrategy;
|
||||
import top.octopusyan.common.http.listener.OnHttpListener;
|
||||
import top.octopusyan.common.http.model.ResponseClass;
|
||||
import top.octopusyan.common.http.request.RequestHandler;
|
||||
import top.octopusyan.manager.http.api.NotParamApi;
|
||||
import top.octopusyan.manager.http.api.ParamApi;
|
||||
import top.octopusyan.manager.http.config.HttpConstant;
|
||||
import top.octopusyan.manager.http.config.LogStrategy;
|
||||
import top.octopusyan.manager.http.listener.OnHttpListener;
|
||||
import top.octopusyan.manager.http.model.ResponseClass;
|
||||
import top.octopusyan.manager.http.request.RequestHandler;
|
||||
|
||||
/**
|
||||
* @author : octopus yan
|
@ -1,23 +1,23 @@
|
||||
package top.octopusyan.common.http;
|
||||
package top.octopusyan.manager.http;
|
||||
|
||||
import okhttp3.*;
|
||||
import top.octopusyan.common.http.annotation.HttpHeader;
|
||||
import top.octopusyan.common.http.annotation.HttpIgnore;
|
||||
import top.octopusyan.common.http.annotation.HttpRename;
|
||||
import top.octopusyan.common.http.api.NotParamApi;
|
||||
import top.octopusyan.common.http.api.ParamApi;
|
||||
import top.octopusyan.common.http.api.PathParamApi;
|
||||
import top.octopusyan.common.http.api.RequestApi;
|
||||
import top.octopusyan.common.http.callback.NormalCallback;
|
||||
import top.octopusyan.common.http.listener.OnHttpListener;
|
||||
import top.octopusyan.common.http.model.CallProxy;
|
||||
import top.octopusyan.common.http.model.HttpHeaders;
|
||||
import top.octopusyan.common.http.model.HttpParams;
|
||||
import top.octopusyan.common.http.model.JsonBody;
|
||||
import top.octopusyan.common.http.config.BodyType;
|
||||
import top.octopusyan.common.http.config.HttpConstant;
|
||||
import top.octopusyan.common.http.request.IRequestHandler;
|
||||
import top.octopusyan.common.http.model.ResponseClass;
|
||||
import top.octopusyan.manager.http.annotation.HttpHeader;
|
||||
import top.octopusyan.manager.http.annotation.HttpIgnore;
|
||||
import top.octopusyan.manager.http.annotation.HttpRename;
|
||||
import top.octopusyan.manager.http.api.NotParamApi;
|
||||
import top.octopusyan.manager.http.api.ParamApi;
|
||||
import top.octopusyan.manager.http.api.PathParamApi;
|
||||
import top.octopusyan.manager.http.api.RequestApi;
|
||||
import top.octopusyan.manager.http.callback.NormalCallback;
|
||||
import top.octopusyan.manager.http.listener.OnHttpListener;
|
||||
import top.octopusyan.manager.http.model.CallProxy;
|
||||
import top.octopusyan.manager.http.model.HttpHeaders;
|
||||
import top.octopusyan.manager.http.model.HttpParams;
|
||||
import top.octopusyan.manager.http.model.JsonBody;
|
||||
import top.octopusyan.manager.http.config.BodyType;
|
||||
import top.octopusyan.manager.http.config.HttpConstant;
|
||||
import top.octopusyan.manager.http.request.IRequestHandler;
|
||||
import top.octopusyan.manager.http.model.ResponseClass;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
@ -545,7 +545,7 @@ public class EasyHttp<Param, Result> {
|
||||
/**
|
||||
* @param params 路径参数
|
||||
*/
|
||||
public RestfulRequest<Result> pathParam(Object... params) {
|
||||
public RestfulRequest<Result> pathParam(String... params) {
|
||||
super.path(MessageFormat.format(getPath(), params));
|
||||
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.JSONException;
|
||||
@ -7,10 +7,10 @@ import okhttp3.MediaType;
|
||||
import okhttp3.MultipartBody;
|
||||
import okhttp3.RequestBody;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import top.octopusyan.common.http.annotation.HttpIgnore;
|
||||
import top.octopusyan.common.http.annotation.HttpRename;
|
||||
import top.octopusyan.common.http.config.ContentType;
|
||||
import top.octopusyan.common.http.model.UpdateBody;
|
||||
import top.octopusyan.manager.http.annotation.HttpIgnore;
|
||||
import top.octopusyan.manager.http.annotation.HttpRename;
|
||||
import top.octopusyan.manager.http.config.ContentType;
|
||||
import top.octopusyan.manager.http.model.UpdateBody;
|
||||
import top.octopusyan.manager.ThreadPoolManager;
|
||||
|
||||
import java.io.*;
|
@ -1,18 +1,12 @@
|
||||
package top.octopusyan.common.http;
|
||||
package top.octopusyan.manager.http;
|
||||
|
||||
import okhttp3.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import top.octopusyan.common.http.config.ILogStrategy;
|
||||
import top.octopusyan.common.http.request.IRequestHandler;
|
||||
import top.octopusyan.common.http.ssl.HttpSslConfig;
|
||||
import top.octopusyan.common.http.ssl.HttpSslFactory;
|
||||
import top.octopusyan.manager.http.config.ILogStrategy;
|
||||
import top.octopusyan.manager.http.request.IRequestHandler;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author : octopus yan
|
@ -1,4 +1,4 @@
|
||||
package top.octopusyan.common.http;
|
||||
package top.octopusyan.manager.http;
|
||||
|
||||
/**
|
||||
* @author : octopus yan
|
@ -1,4 +1,4 @@
|
||||
package top.octopusyan.common.http.annotation;
|
||||
package top.octopusyan.manager.http.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.*;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package top.octopusyan.common.http.annotation;
|
||||
package top.octopusyan.manager.http.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
|
@ -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
|
@ -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
|
@ -1,7 +1,7 @@
|
||||
package top.octopusyan.common.http.api;
|
||||
package top.octopusyan.manager.http.api;
|
||||
|
||||
import lombok.Data;
|
||||
import top.octopusyan.common.http.config.BodyType;
|
||||
import top.octopusyan.manager.http.config.BodyType;
|
||||
|
||||
/**
|
||||
* @author : octopus yan
|
@ -1,12 +1,12 @@
|
||||
package top.octopusyan.common.http.callback;
|
||||
package top.octopusyan.manager.http.callback;
|
||||
|
||||
import okhttp3.Call;
|
||||
import okhttp3.Callback;
|
||||
import okhttp3.Response;
|
||||
import top.octopusyan.common.http.HttpConfig;
|
||||
import top.octopusyan.common.http.HttpLog;
|
||||
import top.octopusyan.common.http.model.CallProxy;
|
||||
import top.octopusyan.common.http.EasyUtils;
|
||||
import top.octopusyan.manager.http.HttpConfig;
|
||||
import top.octopusyan.manager.http.HttpLog;
|
||||
import top.octopusyan.manager.http.model.CallProxy;
|
||||
import top.octopusyan.manager.http.EasyUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
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 top.octopusyan.common.http.listener.OnHttpListener;
|
||||
import top.octopusyan.common.http.HttpLog;
|
||||
import top.octopusyan.common.http.model.CallProxy;
|
||||
import top.octopusyan.common.http.api.RequestApi;
|
||||
import top.octopusyan.common.http.request.IRequestHandler;
|
||||
import top.octopusyan.common.http.EasyUtils;
|
||||
import top.octopusyan.manager.http.listener.OnHttpListener;
|
||||
import top.octopusyan.manager.http.HttpLog;
|
||||
import top.octopusyan.manager.http.model.CallProxy;
|
||||
import top.octopusyan.manager.http.api.RequestApi;
|
||||
import top.octopusyan.manager.http.request.IRequestHandler;
|
||||
import top.octopusyan.manager.http.EasyUtils;
|
||||
|
||||
/**
|
||||
* @author : octopus yan
|
||||
@ -52,7 +53,7 @@ public final class NormalCallback extends BaseCallback {
|
||||
@Override
|
||||
protected void onFailure(Exception e) {
|
||||
final Exception exception = mRequestHandler.requestFail(mRequestApi, e);
|
||||
HttpLog.print(exception);
|
||||
Platform.runLater(() -> HttpLog.print(exception));
|
||||
EasyUtils.post(() -> {
|
||||
mListener.onFail(exception);
|
||||
mListener.onEnd(getCall());
|
@ -1,4 +1,4 @@
|
||||
package top.octopusyan.common.http.config;
|
||||
package top.octopusyan.manager.http.config;
|
||||
|
||||
/**
|
||||
* @author : octopus yan
|
@ -1,4 +1,4 @@
|
||||
package top.octopusyan.common.http.config;
|
||||
package top.octopusyan.manager.http.config;
|
||||
|
||||
import okhttp3.MediaType;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package top.octopusyan.common.http.config;
|
||||
package top.octopusyan.manager.http.config;
|
||||
|
||||
/**
|
||||
* @author : octopus yan
|
@ -1,4 +1,4 @@
|
||||
package top.octopusyan.common.http.config;
|
||||
package top.octopusyan.manager.http.config;
|
||||
|
||||
/**
|
||||
* @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.LoggerFactory;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import top.octopusyan.common.http.EasyHttp;
|
||||
import top.octopusyan.common.http.HttpConfig;
|
||||
import top.octopusyan.manager.http.EasyHttp;
|
||||
import top.octopusyan.manager.http.HttpConfig;
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
@ -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 失效异常
|
@ -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 top.octopusyan.utils.AlertUtil;
|
||||
|
||||
/**
|
||||
* @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.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.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.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.JSONArray;
|
||||
@ -7,7 +7,7 @@ import lombok.NonNull;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.RequestBody;
|
||||
import okio.BufferedSink;
|
||||
import top.octopusyan.common.http.config.ContentType;
|
||||
import top.octopusyan.manager.http.config.ContentType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
@ -1,4 +1,4 @@
|
||||
package top.octopusyan.common.http.model;
|
||||
package top.octopusyan.manager.http.model;
|
||||
|
||||
/**
|
||||
* @author : octopus yan
|
@ -1,12 +1,12 @@
|
||||
package top.octopusyan.common.http.model;
|
||||
package top.octopusyan.manager.http.model;
|
||||
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.RequestBody;
|
||||
import okio.BufferedSink;
|
||||
import okio.Okio;
|
||||
import okio.Source;
|
||||
import top.octopusyan.common.http.config.ContentType;
|
||||
import top.octopusyan.common.http.EasyUtils;
|
||||
import top.octopusyan.manager.http.config.ContentType;
|
||||
import top.octopusyan.manager.http.EasyUtils;
|
||||
|
||||
import java.io.File;
|
||||
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 okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import top.octopusyan.common.http.api.RequestApi;
|
||||
import top.octopusyan.manager.http.api.RequestApi;
|
||||
|
||||
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.JSONArray;
|
||||
@ -8,10 +8,10 @@ import okhttp3.Headers;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
import top.octopusyan.common.http.api.RequestApi;
|
||||
import top.octopusyan.common.http.exception.*;
|
||||
import top.octopusyan.common.http.HttpLog;
|
||||
import top.octopusyan.common.http.response.BaseRest;
|
||||
import top.octopusyan.manager.http.api.RequestApi;
|
||||
import top.octopusyan.manager.http.HttpLog;
|
||||
import top.octopusyan.manager.http.exception.*;
|
||||
import top.octopusyan.manager.http.response.BaseRest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
@ -1,4 +1,4 @@
|
||||
package top.octopusyan.common.http.response;
|
||||
package top.octopusyan.manager.http.response;
|
||||
|
||||
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.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 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.SSLSession;
|
@ -1,4 +1,4 @@
|
||||
package top.octopusyan.common.http.ssl;
|
||||
package top.octopusyan.manager.http.ssl;
|
||||
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
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 top.octopusyan.http.request.ProxySetup;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -25,7 +24,7 @@ public class ApplicatonStore {
|
||||
private static SimpleBooleanProperty autoLogin = new SimpleBooleanProperty();
|
||||
private static SimpleBooleanProperty rememberMe = 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);
|
||||
|
||||
public static void setAccount(String account) {
|
||||
@ -84,12 +83,12 @@ public class ApplicatonStore {
|
||||
return registerSuccess.get();
|
||||
}
|
||||
|
||||
public static ObservableList<ProxySetup> getProxySetupList() {
|
||||
return proxySetupList.get();
|
||||
public static ObservableList<ProxySetup> getProxyList() {
|
||||
return proxyList.get();
|
||||
}
|
||||
|
||||
public static void setProxySetupList(List<ProxySetup> proxySetupList) {
|
||||
ApplicatonStore.proxySetupList = new SimpleListProperty<>(FXCollections.observableList(proxySetupList));
|
||||
public static void initProxyList(List<ProxySetup> proxySetupList) {
|
||||
ApplicatonStore.proxyList = new SimpleListProperty<>(FXCollections.observableList(proxySetupList));
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
import javafx.application.Platform;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.select.Elements;
|
||||
import top.octopusyan.common.http.EasyHttp;
|
||||
import top.octopusyan.common.http.listener.OnHttpListener;
|
||||
import top.octopusyan.common.http.model.ResponseClass;
|
||||
import top.octopusyan.config.ProxyConfig.*;
|
||||
import top.octopusyan.manager.http.EasyHttp;
|
||||
import top.octopusyan.manager.http.listener.OnHttpListener;
|
||||
import top.octopusyan.manager.http.model.ResponseClass;
|
||||
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.request.ProxySetup;
|
||||
import top.octopusyan.model.ProxySetupModel;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@ -22,32 +29,38 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
public class ProxyUtil {
|
||||
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();
|
||||
setup.setNode(3);// 上海服务器
|
||||
setup.setLocal_ip("127.0.0.1");
|
||||
setup.setLocal_port(80);
|
||||
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_encryption(true);
|
||||
setup.setStatus(true);
|
||||
setup.setRuning(false);
|
||||
return setup;
|
||||
}
|
||||
|
||||
public static void delete(Integer id) {
|
||||
EasyHttp.builder()
|
||||
.api(Api.DeleteProxy())
|
||||
.pathParam(id, csrf)
|
||||
.request(result -> { });
|
||||
.pathParam(String.valueOf(id), csrf)
|
||||
.request(result -> {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取隧道详情信息
|
||||
* @return
|
||||
*/
|
||||
public static ProxySetup info(ProxySetup setup) {
|
||||
|
||||
@ -55,7 +68,7 @@ public class ProxyUtil {
|
||||
try {
|
||||
html = EasyHttp.builder()
|
||||
.api(Api.ProxyInfo())
|
||||
.pathParam(setup.getId())
|
||||
.pathParam(String.valueOf(setup.getId()))
|
||||
.execute(new ResponseClass<String>() {
|
||||
});
|
||||
} catch (Exception e) {
|
||||
@ -75,14 +88,14 @@ public class ProxyUtil {
|
||||
String domain = select.get(8).text();
|
||||
String status = select.get(13).text();
|
||||
|
||||
Arrays.stream(ProxyServer.values()).forEach(server -> {
|
||||
if (serverStr.contains(server.name()))
|
||||
setup.setNode(Arrays.asList(ProxyServer.values()).indexOf(server));
|
||||
});
|
||||
|
||||
for (ProxyServer value : ProxyServer.values()) {
|
||||
String name = value.getServerName();
|
||||
if (serverStr.contains(name))
|
||||
setup.setNode(ProxyConfig.getServerNode(name));
|
||||
}
|
||||
setup.setLocal_ip(localIp);
|
||||
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.setUse_compression(useCom.equals("启用"));
|
||||
setup.setUse_encryption(useEnc.equals("启用"));
|
||||
@ -91,14 +104,15 @@ public class ProxyUtil {
|
||||
return setup;
|
||||
}
|
||||
|
||||
public static int randomPort(){
|
||||
public static int randomPort() {
|
||||
try {
|
||||
return EasyHttp.builder()
|
||||
return Integer.parseInt(EasyHttp.builder()
|
||||
.api(Api.RandomPort())
|
||||
.execute(new ResponseClass<Integer>() { });
|
||||
.execute(new ResponseClass<String>() {
|
||||
}));
|
||||
} catch (Exception e) {
|
||||
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_type(tds.get(2).text());
|
||||
proxySetup.setSort(Integer.parseInt(tds.get(5).text()));
|
||||
|
||||
ProxySetup info = info(proxySetup);
|
||||
if (info != null) return info;
|
||||
return proxySetup;
|
||||
}).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) {
|
||||
String result = null;
|
||||
try {
|
||||
result = EasyHttp.builder()
|
||||
.api(Api.AddProxy())
|
||||
.param(setup)
|
||||
.execute(new ResponseClass<String>() {
|
||||
});
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
|
||||
if(result.equals("隧道创建成功")){
|
||||
getList(result1 -> listener.onSucceed(result1.get(result1.size()-1)));
|
||||
} else {
|
||||
AlertUtil.error(result).show();
|
||||
}
|
||||
return result.equals("隧道创建成功");
|
||||
public static void add(OnHttpListener<ProxySetup> listener, ProxySetup setup) {
|
||||
EasyHttp.builder()
|
||||
.api(Api.AddProxy())
|
||||
.param(setup)
|
||||
.request(result -> getList(result1 -> {
|
||||
if (result1 != null && result1.size() > 0) {
|
||||
for (ProxySetup proxySetup : result1) {
|
||||
if (Objects.equals(proxySetup.getSort(), proxySetup.getSort())) {
|
||||
listener.onSucceed(proxySetup);
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public static String getCsrf() {
|
||||
@ -159,4 +175,53 @@ public class ProxyUtil {
|
||||
int i1 = htmlStr.indexOf("\"", i + 18);
|
||||
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;
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@
|
||||
-fx-opacity: 0.4;
|
||||
}
|
||||
/* 布局边框 */
|
||||
.mainPane, #addProxyBtn , .jfx-list-view{
|
||||
.mainPane, #addProxyBtn, .jfx-list-view{
|
||||
-fx-border-color: linear-gradient(#57b4f2, #9198e5);
|
||||
}
|
||||
|
||||
@ -38,16 +38,23 @@
|
||||
-fx-border-radius: 0 5 5 0;
|
||||
}
|
||||
/* 服务线路 */
|
||||
#proxyServerCB {
|
||||
#proxyServerComboBox {
|
||||
-fx-font-size: 16;
|
||||
-fx-text-fill: #757575;
|
||||
}
|
||||
|
||||
/* TODO 隧道列表 */
|
||||
#proxyListView .list-cell:selected {
|
||||
-fx-text-fill: white;
|
||||
-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 {
|
||||
-fx-icon-color: linear-gradient(#95f257, #91e5ac);
|
||||
}
|
||||
@ -73,18 +80,20 @@
|
||||
-fx-font-family: "Microsoft YaHei";
|
||||
}
|
||||
/* 隧道类型 */
|
||||
#proxyProtocolCombox {
|
||||
#proxyProtocolComboBox {
|
||||
-fx-font-size: 14px;
|
||||
-fx-font-family: "Microsoft YaHei";
|
||||
}
|
||||
/* 自定义域名 */
|
||||
#customizeDomainBtn {
|
||||
#customizeDomainBtn, #resetProxyBtn, #copyDomainBtn {
|
||||
-fx-text-fill: linear-gradient(#57b4f2, #9198e5);
|
||||
}
|
||||
/* 添加隧道 */
|
||||
#addProxyBtn {
|
||||
-fx-border-width: 0 1 1;
|
||||
-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";
|
||||
}
|
||||
/* 启动 */
|
||||
@ -102,7 +111,12 @@
|
||||
}
|
||||
|
||||
/* 修改Tab的背景颜色 */
|
||||
.jfx-tab-pane .tab-header-background {
|
||||
.jfx-tab-pane .tab-header-background {
|
||||
-fx-background-color: linear-gradient(#57b4f2, #9198e5);
|
||||
}
|
||||
|
||||
/* 日志 */
|
||||
.text-area {
|
||||
-fx-font-size: 15;
|
||||
-fx-font-family: monospace;
|
||||
-fx-background-color: white;
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
.root, #root{
|
||||
.root, #root {
|
||||
-fx-background-radius: 14;
|
||||
}
|
||||
|
||||
#titleLable, #closeBtn, #minimizeBtn{
|
||||
#titleLable, #closeBtn, #minimizeBtn {
|
||||
-fx-font-family: "Microsoft YaHei";
|
||||
-fx-text-fill: white;
|
||||
}
|
||||
@ -28,8 +28,13 @@
|
||||
|
||||
#closeBtn:hover {
|
||||
-fx-background-color: rgba(255, 0, 0, 0.70);
|
||||
-fx-text-fill: white;
|
||||
}
|
||||
|
||||
#minimizeBtn:hover {
|
||||
-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.JFXRadioButton?>
|
||||
<?import com.jfoenix.controls.JFXTabPane?>
|
||||
<?import com.jfoenix.controls.JFXTextArea?>
|
||||
<?import com.jfoenix.controls.JFXTextField?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.Cursor?>
|
||||
<?import javafx.scene.control.Hyperlink?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.Tab?>
|
||||
@ -20,177 +22,228 @@
|
||||
<?import javafx.scene.text.Font?>
|
||||
<?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">
|
||||
<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="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" />
|
||||
<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="closeBtn" layoutX="714.0" prefHeight="35.0" prefWidth="36.0" text="X"/>
|
||||
<JFXComboBox fx:id="proxyServerComboBox" layoutX="90.0" prefHeight="36.0" prefWidth="90.0">
|
||||
<cursor>
|
||||
<Cursor fx:constant="HAND"/>
|
||||
</cursor>
|
||||
</JFXComboBox>
|
||||
</AnchorPane>
|
||||
<GridPane fx:id="MainBottomPane" hgap="10.0" prefHeight="684.0" prefWidth="750.0" vgap="10.0">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="539.0" minWidth="10.0" prefWidth="520.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="370.0" minWidth="10.0" prefWidth="200.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="539.0" minWidth="10.0" prefWidth="520.0"/>
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="370.0" minWidth="10.0" prefWidth="200.0"/>
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints maxHeight="493.0" minHeight="10.0" prefHeight="404.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="337.0" minHeight="10.0" prefHeight="231.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints maxHeight="493.0" minHeight="10.0" prefHeight="404.0" vgrow="SOMETIMES"/>
|
||||
<RowConstraints maxHeight="337.0" minHeight="10.0" prefHeight="231.0" vgrow="SOMETIMES"/>
|
||||
</rowConstraints>
|
||||
<children>
|
||||
<VBox fx:id="proxySetupPane" prefHeight="200.0" prefWidth="100.0" styleClass="mainPane">
|
||||
<HBox alignment="CENTER_LEFT" prefHeight="50.0" prefWidth="520.0">
|
||||
<Label alignment="CENTER_RIGHT" prefHeight="Infinity" prefWidth="100.0" styleClass="proxySetupLabel" text="隧道名称">
|
||||
<HBox.margin>
|
||||
<Insets right="20.0" />
|
||||
</HBox.margin>
|
||||
</Label>
|
||||
<JFXTextField fx:id="proxyNameTextField" prefHeight="Infinity" prefWidth="320.0" styleClass="inputText">
|
||||
<HBox.margin>
|
||||
<Insets right="20.0" />
|
||||
</HBox.margin>
|
||||
<padding>
|
||||
<Insets left="15.0" />
|
||||
</padding>
|
||||
<font>
|
||||
<Font size="14.0" />
|
||||
</font>
|
||||
</JFXTextField>
|
||||
<padding>
|
||||
<Insets left="10.0"/>
|
||||
</padding>
|
||||
<HBox alignment="CENTER_RIGHT" prefHeight="50.0" prefWidth="520.0">
|
||||
<padding>
|
||||
<Insets bottom="10.0" top="10.0" />
|
||||
<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">
|
||||
<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>
|
||||
<Insets right="20.0" />
|
||||
<Insets right="20.0"/>
|
||||
</HBox.margin>
|
||||
</Label>
|
||||
<JFXTextField fx:id="proxyNameTextField" prefHeight="Infinity" prefWidth="320.0"
|
||||
styleClass="inputText">
|
||||
<HBox.margin>
|
||||
<Insets right="20.0"/>
|
||||
</HBox.margin>
|
||||
<padding>
|
||||
<Insets left="15.0"/>
|
||||
</padding>
|
||||
<font>
|
||||
<Font size="14.0"/>
|
||||
</font>
|
||||
</JFXTextField>
|
||||
</HBox>
|
||||
<HBox alignment="CENTER_LEFT" prefHeight="50.0" prefWidth="520.0">
|
||||
<padding>
|
||||
<Insets bottom="10.0" top="10.0"/>
|
||||
</padding>
|
||||
<Label alignment="CENTER_RIGHT" prefHeight="Infinity" prefWidth="100.0"
|
||||
styleClass="proxySetupLabel" text="是否启用">
|
||||
<HBox.margin>
|
||||
<Insets right="20.0"/>
|
||||
</HBox.margin>
|
||||
</Label>
|
||||
<HBox alignment="CENTER_LEFT" prefHeight="Infinity" prefWidth="320.0">
|
||||
<JFXRadioButton fx:id="openProxyRBtn" text="启用">
|
||||
<HBox.margin>
|
||||
<Insets right="20.0" />
|
||||
<Insets right="20.0"/>
|
||||
</HBox.margin>
|
||||
<cursor>
|
||||
<Cursor fx:constant="HAND"/>
|
||||
</cursor>
|
||||
</JFXRadioButton>
|
||||
<JFXRadioButton fx:id="closeProxyRBtn" text="停用">
|
||||
<cursor>
|
||||
<Cursor fx:constant="HAND"/>
|
||||
</cursor>
|
||||
</JFXRadioButton>
|
||||
<JFXRadioButton fx:id="closeProxyRBtn" text="停用" />
|
||||
</HBox>
|
||||
<VBox.margin>
|
||||
<Insets />
|
||||
</VBox.margin>
|
||||
<padding>
|
||||
<Insets bottom="10.0" top="10.0" />
|
||||
</padding>
|
||||
</HBox>
|
||||
<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>
|
||||
<Insets right="20.0" />
|
||||
<Insets right="20.0"/>
|
||||
</HBox.margin>
|
||||
</Label>
|
||||
<JFXComboBox fx:id="proxyProtocolCombox" prefHeight="Infinity" prefWidth="320.0" styleClass="inputText" />
|
||||
<padding>
|
||||
<Insets bottom="10.0" top="10.0" />
|
||||
</padding>
|
||||
<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">
|
||||
<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>
|
||||
<Insets right="20.0" />
|
||||
<Insets right="20.0"/>
|
||||
</HBox.margin>
|
||||
</Label>
|
||||
<HBox prefHeight="Infinity" prefWidth="320.0">
|
||||
<children>
|
||||
<JFXTextField fx:id="localHostTextField" alignment="CENTER" prefWidth="250.0" promptText="内网服务IP (IPV4)" styleClass="inputText-left" text="127.0.0.1">
|
||||
<font>
|
||||
<Font size="14.0" />
|
||||
</font>
|
||||
</JFXTextField>
|
||||
<JFXTextField fx:id="localPortTextField" alignment="CENTER" prefWidth="70.0" promptText="端口" styleClass="inputText-right" text="80">
|
||||
<font>
|
||||
<Font size="14.0" />
|
||||
</font>
|
||||
</JFXTextField>
|
||||
</children>
|
||||
<JFXTextField fx:id="localHostTextField" alignment="CENTER" prefWidth="220.0"
|
||||
promptText="内网服务IP (IPV4)" styleClass="inputText-left" text="127.0.0.1">
|
||||
<font>
|
||||
<Font size="14.0"/>
|
||||
</font>
|
||||
</JFXTextField>
|
||||
<JFXTextField fx:id="localPortTextField" alignment="CENTER" minWidth="70.0"
|
||||
prefWidth="100.0" promptText="端口" styleClass="inputText-right" text="80">
|
||||
<font>
|
||||
<Font size="14.0"/>
|
||||
</font>
|
||||
</JFXTextField>
|
||||
</HBox>
|
||||
<padding>
|
||||
<Insets bottom="10.0" top="10.0" />
|
||||
</padding>
|
||||
</HBox>
|
||||
<HBox alignment="CENTER_LEFT" prefHeight="50.0" prefWidth="520.0">
|
||||
<Label alignment="CENTER_RIGHT" prefHeight="Infinity" prefWidth="100.0" styleClass="proxySetupLabel" text="外网访问地址">
|
||||
<HBox fx:id="domainPane" alignment="CENTER_LEFT" prefHeight="40.0" prefWidth="520.0">
|
||||
<padding>
|
||||
<Insets top="10.0"/>
|
||||
</padding>
|
||||
<Label alignment="CENTER_RIGHT" prefHeight="Infinity" prefWidth="100.0"
|
||||
styleClass="proxySetupLabel" text="外网访问地址">
|
||||
<HBox.margin>
|
||||
<Insets right="20.0" />
|
||||
<Insets right="20.0"/>
|
||||
</HBox.margin>
|
||||
</Label>
|
||||
<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 size="14.0" />
|
||||
<Font size="14.0"/>
|
||||
</font>
|
||||
</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 size="14.0" />
|
||||
<Font size="14.0"/>
|
||||
</font>
|
||||
</JFXTextField>
|
||||
</HBox>
|
||||
<JFXButton fx:id="customizeDomainBtn" prefHeight="Infinity" text="自定义">
|
||||
<HBox.margin>
|
||||
<Insets left="10.0" />
|
||||
<Insets left="5.0"/>
|
||||
</HBox.margin>
|
||||
<cursor>
|
||||
<Cursor fx:constant="HAND"/>
|
||||
</cursor>
|
||||
</JFXButton>
|
||||
<padding>
|
||||
<Insets bottom="10.0" top="10.0" />
|
||||
</padding>
|
||||
</HBox>
|
||||
<HBox alignment="CENTER_LEFT" prefHeight="50.0" prefWidth="520.0">
|
||||
<Label alignment="CENTER_RIGHT" prefHeight="Infinity" prefWidth="100.0" styleClass="proxySetupLabel" text="用户名 (可选)">
|
||||
<Label fx:id="domainHtinTextField" alignment="CENTER" prefHeight="20.0" prefWidth="320.0"
|
||||
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>
|
||||
<Insets right="20.0" />
|
||||
<Insets/>
|
||||
</HBox.margin>
|
||||
</Label>
|
||||
<JFXTextField prefHeight="Infinity" prefWidth="320.0" styleClass="inputText">
|
||||
<padding>
|
||||
<Insets left="10.0" />
|
||||
</padding>
|
||||
</JFXTextField>
|
||||
<padding>
|
||||
<Insets bottom="10.0" top="10.0" />
|
||||
</padding>
|
||||
<Hyperlink fx:id="domainLink" prefHeight="30.0"/>
|
||||
<JFXButton fx:id="copyDomainBtn" prefHeight="30.0" text="复制"/>
|
||||
</HBox>
|
||||
<padding>
|
||||
<Insets left="10.0" top="40.0" />
|
||||
</padding>
|
||||
</VBox>
|
||||
<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="新增连接">
|
||||
<graphic>
|
||||
<FontIcon iconLiteral="fa-plus" />
|
||||
<FontIcon iconColor="white" iconLiteral="fa-plus"/>
|
||||
</graphic>
|
||||
<cursor>
|
||||
<Cursor fx:constant="HAND"/>
|
||||
</cursor>
|
||||
</JFXButton>
|
||||
</VBox>
|
||||
<AnchorPane prefHeight="Infinity" prefWidth="Infinity" GridPane.rowIndex="1">
|
||||
<JFXTabPane fx:id="tabPane" prefHeight="230" prefWidth="520.0" styleClass="mainPane">
|
||||
<tabs>
|
||||
<Tab text=" 日志 ">
|
||||
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" />
|
||||
<Tab fx:id="proxyLogPane" text=" 日志 ">
|
||||
<JFXTextArea prefWidth="Infinity"/>
|
||||
</Tab>
|
||||
<Tab text="常见问题">
|
||||
<VBox minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0">
|
||||
<HBox prefHeight="30.0" prefWidth="Infinity">
|
||||
<Label prefHeight="Infinity" text="* 若启动后无法通过外网访问,请点击" />
|
||||
<Hyperlink prefHeight="Infinity" text="此处" />
|
||||
<Label prefHeight="Infinity" text="排查问题" />
|
||||
</HBox>
|
||||
<Label prefHeight="30" text="* 修改配置信息后,必须重启才能生效" />
|
||||
<Label prefHeight="30" text="* 只有启动或重启内网穿透服务时,配置信息才会被保存" />
|
||||
<Label prefHeight="30" text="* 同一个账号在同一时间只能在一台电脑上登录使用" />
|
||||
<Label prefHeight="30" text="* 请勿将非法、暴力、色情等信息映射到外网上去,一经发现立即封号" />
|
||||
<padding>
|
||||
<Insets left="20.0" top="20.0" />
|
||||
<Insets left="20.0" top="20.0"/>
|
||||
</padding>
|
||||
<HBox prefHeight="30.0" prefWidth="Infinity">
|
||||
<Label prefHeight="Infinity" text="* 若启动后无法通过外网访问,请点击"/>
|
||||
<Hyperlink prefHeight="Infinity" text="此处"/>
|
||||
<Label prefHeight="Infinity" text="排查问题"/>
|
||||
</HBox>
|
||||
<Label prefHeight="30" text="* 修改配置信息后,必须重启才能生效"/>
|
||||
<Label prefHeight="30" text="* 只有启动或重启内网穿透服务时,配置信息才会被保存"/>
|
||||
<Label prefHeight="30" text="* 同一个账号在同一时间只能在一台电脑上登录使用"/>
|
||||
<Label prefHeight="30" text="* 请勿将非法、暴力、色情等信息映射到外网上去,一经发现立即封号"/>
|
||||
</VBox>
|
||||
</Tab>
|
||||
<Tab text="使用场景">
|
||||
@ -200,16 +253,23 @@
|
||||
</Tab>
|
||||
</tabs>
|
||||
</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>
|
||||
<FontIcon iconColor="white" iconLiteral="fa-trash-o" iconSize="18" />
|
||||
<FontIcon iconColor="white" iconLiteral="fa-trash-o" iconSize="18"/>
|
||||
</graphic>
|
||||
<cursor>
|
||||
<Cursor fx:constant="HAND"/>
|
||||
</cursor>
|
||||
</JFXButton>
|
||||
</AnchorPane>
|
||||
<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" text="启动" />
|
||||
</children>
|
||||
<JFXButton fx:id="startProxyBtn" buttonType="RAISED" prefHeight="44.0" prefWidth="202.0"
|
||||
styleClass="startProxyBtn" text="启动">
|
||||
<cursor>
|
||||
<Cursor fx:constant="HAND"/>
|
||||
</cursor>
|
||||
</JFXButton>
|
||||
</VBox>
|
||||
</children>
|
||||
</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