YanFrp/src/main/java/top/octopusyan/controller/MainController.java

531 lines
21 KiB
Java
Raw Normal View History

2022-04-06 17:49:00 +08:00
package top.octopusyan.controller;
import com.jfoenix.controls.*;
2022-04-09 03:59:20 +08:00
import com.jfoenix.validation.IntegerValidator;
import com.jfoenix.validation.RequiredFieldValidator;
import javafx.application.HostServices;
2022-04-06 17:49:00 +08:00
import javafx.application.Platform;
2022-04-09 03:59:20 +08:00
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleIntegerProperty;
2022-04-06 17:49:00 +08:00
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
2022-04-09 03:59:20 +08:00
import javafx.event.EventHandler;
2022-04-06 17:49:00 +08:00
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
2022-04-09 03:59:20 +08:00
import javafx.scene.control.Button;
import javafx.scene.control.Label;
2022-04-06 17:49:00 +08:00
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import top.octopusyan.base.BaseController;
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.manager.http.listener.OnHttpListener;
2022-04-09 03:59:20 +08:00
import top.octopusyan.model.ProxySetupModel;
2022-04-06 17:49:00 +08:00
import top.octopusyan.utils.AlertUtil;
2022-04-09 03:59:20 +08:00
import top.octopusyan.utils.DomainUtil;
import top.octopusyan.utils.FrpUtil;
2022-04-06 17:49:00 +08:00
import top.octopusyan.utils.ProxyUtil;
2022-04-09 03:59:20 +08:00
import top.octopusyan.config.TextValidate;
2022-04-06 17:49:00 +08:00
2022-04-09 03:59:20 +08:00
import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
2022-04-06 17:49:00 +08:00
import java.io.IOException;
2022-04-09 03:59:20 +08:00
import java.util.*;
2022-04-06 17:49:00 +08:00
import java.util.List;
/**
* @author : octopus yan
* @email : octopus_yan@foxmail.com
* @description :
* @create : 2022-4-4 22:32
*/
public class MainController extends BaseController<StackPane> implements Initializable {
public static final String PROXY_LIST_ITEM_CLASS = "proxyListItem";
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";
2022-04-09 03:59:20 +08:00
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";
2022-04-06 17:49:00 +08:00
@FXML
public StackPane root;
@FXML
public JFXButton closeBtn, minimizeBtn;
@FXML
2022-04-09 03:59:20 +08:00
public JFXButton startProxyBtn, addProxyBtn;
2022-04-06 17:49:00 +08:00
@FXML
2022-04-09 03:59:20 +08:00
public JFXComboBox<String> proxyProtocolComboBox;
2022-04-06 17:49:00 +08:00
@FXML
public JFXButton customizeDomainBtn;
@FXML
public JFXRadioButton openProxyRBtn, closeProxyRBtn;
@FXML
public JFXTextField domainTextField, domainSuffixTextField;
@FXML
public JFXTextField proxyNameTextField, localHostTextField, localPortTextField;
@FXML
2022-04-09 03:59:20 +08:00
public JFXComboBox<String> proxyServerComboBox;
2022-04-06 17:49:00 +08:00
@FXML
public JFXTabPane tabPane;
@FXML
public JFXListView<Label> proxyListView;
2022-04-09 03:59:20 +08:00
@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;
2022-04-06 17:49:00 +08:00
private ToggleGroup openProxyGroup = new ToggleGroup();
2022-04-09 03:59:20 +08:00
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;
2022-04-06 17:49:00 +08:00
private ProxySetup proxySetup;
2022-04-09 03:59:20 +08:00
private SimpleBooleanProperty setting = new SimpleBooleanProperty(false);
2022-04-06 17:49:00 +08:00
@Override
public boolean dragWindow() {
return true;
}
@Override
public StackPane getRootPanel() {
return root;
}
@NotNull
@Override
public String getRootFxmlPath() {
return "/fxml/main.fxml";
}
@Override
public Button getClooseBtn() {
return closeBtn;
}
@Override
public Button getMinimizeBtn() {
return minimizeBtn;
}
@Override
public JFXButton getFirstBtn() {
return minimizeBtn;
}
@Override
public void initData() {
2022-04-09 03:59:20 +08:00
// 初始化视图模型
proxySetup = ProxyUtil.initProxy(null);
proxySetupModel = new ProxySetupModel(proxySetup);
2022-04-06 17:49:00 +08:00
// 隧道类型
2022-04-09 03:59:20 +08:00
Arrays.asList(ProxyType.values()).forEach((type) -> proxyProtocolComboBox.getItems().add(type.name()));
2022-04-06 17:49:00 +08:00
// 服务器
2022-04-09 03:59:20 +08:00
Arrays.asList(ProxyServer.values()).forEach((server) -> proxyServerComboBox.getItems().add(server.getServerName()));
2022-04-06 17:49:00 +08:00
// 获取用户隧道列表
ProxyUtil.getList(new OnHttpListener<List<ProxySetup>>() {
@Override
public void onSucceed(List<ProxySetup> result) {
if (result != null)
proxyList = result;
// 如果用户隧道列表不为空
if (proxyList != null && proxyList.size() > 0) {
// 显示隧道列表
initProxyList(proxyList);
// 默认选中第一个(配置隧道设置模型)
proxyListView.getSelectionModel().select(0);
} else {
// 配置隧道设置模型
proxyList = new ArrayList<>();
proxyList.add(proxySetup);
}
}
2022-04-09 03:59:20 +08:00
@Override
public void onFail(Exception e) {
2022-04-09 03:59:20 +08:00
}
2022-04-06 17:49:00 +08:00
});
2022-04-09 03:59:20 +08:00
/* 数据绑定 */
// 服务器
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());
2022-04-06 17:49:00 +08:00
}
@Override
public void initViewStyle() {
// 启用链接
openProxyRBtn.setToggleGroup(openProxyGroup);
closeProxyRBtn.setToggleGroup(openProxyGroup);
openProxyRBtn.setUserData(true);
closeProxyRBtn.setUserData(false);
2022-04-09 03:59:20 +08:00
openProxyRBtn.setSelected(true);
2022-04-06 17:49:00 +08:00
2022-04-09 03:59:20 +08:00
// 是否启用
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));
2022-04-06 17:49:00 +08:00
2022-04-09 03:59:20 +08:00
// 设置
localHostTextField.setText(host);
localPortTextField.setText(port);
});
2022-04-06 17:49:00 +08:00
2022-04-09 03:59:20 +08:00
// 隧道名称
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);
2022-04-06 17:49:00 +08:00
}
@Override
public void initViewAction() {
2022-04-09 03:59:20 +08:00
// 重置
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();
}
});
2022-04-06 17:49:00 +08:00
// 是否启用
openProxyGroup.selectedToggleProperty().addListener(
(ObservableValue<? extends Toggle> ov, Toggle old_toggle, Toggle new_toggle) -> {
Toggle toggle = openProxyGroup.getSelectedToggle();
if (toggle != null) {
2022-04-09 03:59:20 +08:00
// 设置状态
proxySetupModel.setStatus((Boolean) toggle.getUserData());
2022-04-06 17:49:00 +08:00
}
}
);
2022-04-09 03:59:20 +08:00
// 自定义访问域名
customizeDomainBtn.setOnMouseClicked((event) -> customizeDomain.set(!customizeDomain.get()));
2022-04-06 17:49:00 +08:00
2022-04-09 03:59:20 +08:00
// 本地IP检查
localHostTextField.getValidators().add(TextValidate.IpRequired);
localHostTextField.getValidators().add(TextValidate.IpFormat);
localHostTextField.textProperty().addListener((observable, oldValue, newValue) -> {
localHostTextField.validate();
2022-04-06 17:49:00 +08:00
});
2022-04-09 03:59:20 +08:00
// 端口检查
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();
2022-04-06 17:49:00 +08:00
});
// 点击隧道列表
proxyListView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
2022-04-09 03:59:20 +08:00
ObservableList<Label> items = proxyListView.getItems();
for (Label item : items) {
item.getStyleClass().remove(PROXY_LIST_ITEM_SELECT_CLASS);
}
2022-04-06 17:49:00 +08:00
if (newValue != null) {
2022-04-09 03:59:20 +08:00
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);
});
2022-04-06 17:49:00 +08:00
}
});
// 添加隧道
addProxyBtn.setOnMouseClicked(event -> {
2022-04-09 03:59:20 +08:00
// 保存运行状态
proxyList.get(selectProxy.get()).setRuning(proxySetupModel.isRunning());
2022-04-06 17:49:00 +08:00
// 获取默认隧道设置
2022-04-09 03:59:20 +08:00
proxySetup = ProxyUtil.initProxy(proxyList.get(proxyList.size() - 1).getSort());
2022-04-06 17:49:00 +08:00
// 加入列表
proxyList.add(proxySetup);
2022-04-09 03:59:20 +08:00
initProxyList(proxyList);
2022-04-06 17:49:00 +08:00
// 展示
2022-04-09 03:59:20 +08:00
proxyListView.getSelectionModel().select(proxyList.size() - 1);
2022-04-06 17:49:00 +08:00
});
2022-04-09 03:59:20 +08:00
// 启动
startProxyBtn.setOnMouseClicked(event -> {
if (proxySetupModel.isRunning())
stopProxy();
else
startProxy();
});
2022-04-06 17:49:00 +08:00
2022-04-09 03:59:20 +08:00
// 链接跳转
domainLink.setOnMouseClicked(event -> {
getApplication().getHostServices().showDocument(domainLink.getText());
});
2022-04-06 17:49:00 +08:00
2022-04-09 03:59:20 +08:00
// 复制外网访问地址
copyDomainBtn.setOnMouseClicked(event -> {
//获取系统剪切板
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
//构建String数据类型
StringSelection selection = new StringSelection(domainLink.getText());
//添加文本到系统剪切板
clipboard.setContents(selection, null);
// 复制成功提示
AlertUtil.info("复制成功,快去分享给小伙伴吧!").show();
});
2022-04-06 17:49:00 +08:00
}
/**
* 显示隧道列表
*/
private void initProxyList(List<ProxySetup> proxyList) {
// 清空列表
proxyListView.getItems().clear();
for (ProxySetup proxy : proxyList) {
try {
Label label = FXMLLoader.load(getClass().getResource("/fxml/proxyItem.fxml"));
2022-04-09 03:59:20 +08:00
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);
2022-04-06 17:49:00 +08:00
proxyListView.getItems().add(label);
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 是否启用当前隧道
*/
private void closeProxy(boolean close) {
2022-04-09 03:59:20 +08:00
if (close && proxySetupModel.isRunning()) stopProxy();
2022-04-06 17:49:00 +08:00
proxyNameTextField.setDisable(close);// 隧道名称
2022-04-09 03:59:20 +08:00
proxyProtocolComboBox.setDisable(close);// 隧道类型
2022-04-06 17:49:00 +08:00
localHostTextField.setDisable(close);// 本地地址
localPortTextField.setDisable(close);// 本地端口
domainTextField.setDisable(close); // 外网子域名
startProxyBtn.setDisable(close); // 启动按钮
2022-04-09 03:59:20 +08:00
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);
2022-04-06 17:49:00 +08:00
if (close) {
styleClass.add(PROXY_LIST_ITEM_CLOSE_CLASS);
} else {
2022-04-09 03:59:20 +08:00
styleClass.add(proxySetupModel.isRunning() ? PROXY_LIST_ITEM_RUN_CLASS : PROXY_LIST_ITEM_STOP_CLASS);
2022-04-06 17:49:00 +08:00
}
}
/**
* TODO 启动代理
*/
private void startProxy() {
2022-04-09 03:59:20 +08:00
// 非 http 隧道系统随机分配端口
if (!DomainUtil.isHttp(proxySetupModel)) {
proxySetupModel.setRemotePort(String.valueOf(ProxyUtil.randomPort()));
}
2022-04-06 17:49:00 +08:00
2022-04-09 03:59:20 +08:00
if (proxySetupModel.getId() != null && !proxySetupModel.get().equals(proxySetup)) {
// 删除旧隧道
ProxyUtil.delete(proxySetupModel.getId());
2022-04-06 17:49:00 +08:00
2022-04-09 03:59:20 +08:00
// 添加隧道
ProxyUtil.add(new OnHttpListener<ProxySetup>() {
@Override
public void onSucceed(ProxySetup result) {
proxySetup = result;
proxySetupModel.set(proxySetup);
}
@Override
public void onFail(Exception e) {
}
2022-04-09 03:59:20 +08:00
}, proxySetupModel.get());
}
2022-04-06 17:49:00 +08:00
2022-04-09 03:59:20 +08:00
// 初始化frputil
FrpUtil frpUtil;
if ((frpUtil = frpUtilMap.get(proxySetupModel.getProxyName())) == null)
frpUtilMap.put(proxySetupModel.getProxyName(), frpUtil = FrpUtil.init(proxySetupModel));
2022-04-06 17:49:00 +08:00
2022-04-09 03:59:20 +08:00
// 设置文本域对象
if (proxyLogPane.getContent() == null) proxyLogPane.contentProperty().set(frpUtil.getConsole());
// 开始
frpUtil.start();
2022-04-06 17:49:00 +08:00
}
/**
* TODO 暂停代理
*/
private void stopProxy() {
// 关闭CMD
2022-04-09 03:59:20 +08:00
FrpUtil frpUtil = frpUtilMap.get(proxySetupModel.getProxyName());
if (frpUtil != null) frpUtil.stop();
2022-04-06 17:49:00 +08:00
}
}