Skip to content

Commit 05d8a3d

Browse files
v6 adaptation
1 parent 0f7330a commit 05d8a3d

13 files changed

Lines changed: 820 additions & 178 deletions

File tree

.idea/gradle.xml

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ java {
1919

2020
dependencies {
2121

22+
implementation("org.java-websocket:Java-WebSocket:1.5.3")
2223
implementation("com.squareup.okhttp3:okhttp:4.12.0")
2324
// JSON 处理
2425
implementation("com.fasterxml.jackson.core:jackson-databind:2.17.2")
Lines changed: 159 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -1,193 +1,223 @@
11
package com.lokins.sleepy.gui.controller;
22

3-
import com.lokins.sleepy.gui.network.SleepyClient;
3+
import com.lokins.sleepy.gui.network.ISleepyClient;
4+
import com.lokins.sleepy.gui.network.SleepyClientFactory;
5+
import com.lokins.sleepy.gui.network.SleepyClientV5;
6+
import com.lokins.sleepy.gui.network.SleepyPingProvider;
47
import com.lokins.sleepy.gui.service.MonitorService;
58
import com.lokins.sleepy.gui.utils.ConfigManager;
69
import javafx.application.Platform;
7-
import javafx.event.ActionEvent;
810
import javafx.fxml.FXML;
911
import javafx.scene.control.*;
1012
import org.slf4j.Logger;
1113
import org.slf4j.LoggerFactory;
12-
1314
import java.io.IOException;
1415

1516
public class ConnectViewController {
1617
private static final Logger logger = LoggerFactory.getLogger(ConnectViewController.class);
1718

18-
@FXML private TextField serverUrlField;
19-
@FXML private PasswordField secretField;
20-
@FXML private TextField deviceNameField;
21-
@FXML private Button startBtn;
22-
@FXML private Label statusLabel;
23-
@FXML private Button testConnBtn; // 必须添加这一行
19+
@FXML private TextField serverUrlField, deviceNameField;
20+
@FXML private PasswordField secretField, refreshTokenField;
21+
@FXML private Label statusLabel, refreshLabel;
22+
@FXML private Button startBtn, testConnBtn;
23+
@FXML private CheckBox autoProtocolCheck;
24+
@FXML private ChoiceBox<String> protocolVersionBox;
2425

25-
// 使用静态变量或单例,确保页面切换时服务不被销毁
2626
private static MonitorService monitorService;
2727
private static boolean isRunning = false;
2828

2929
@FXML
3030
public void initialize() {
31-
// 恢复之前的配置
32-
try {
33-
ConfigManager config = ConfigManager.getInstance();
34-
serverUrlField.setText(config.get("server", "url", ""));
35-
secretField.setText(config.get("auth", "secret", ""));
36-
deviceNameField.setText(config.get("device", "name", "My-PC"));
37-
} catch (IOException e) {
38-
logger.error("加载配置失败", e);
39-
}
40-
41-
// 恢复按钮状态(防止从日志页切回来时按钮变回“开始”)
42-
updateUIState();
43-
}
44-
45-
@FXML
46-
private void handleStart() {
47-
try {
48-
ConfigManager config = ConfigManager.getInstance();
49-
config.set("server", "url", serverUrlField.getText());
50-
config.set("auth", "secret", secretField.getText());
51-
config.set("device", "name", deviceNameField.getText());
52-
53-
// !!!必须加这一行,否则文件不会更新 !!!
54-
config.save();
55-
56-
logger.info("配置已持久化到磁盘");
57-
} catch (IOException e) {
58-
logger.error("无法保存配置", e);
31+
// 1. 初始化下拉框选项(仅执行一次)
32+
if (protocolVersionBox.getItems().isEmpty()) {
33+
protocolVersionBox.getItems().addAll("Protocol v5 (Legacy)", "Protocol v6 (Modern)");
5934
}
6035

61-
if (!isRunning) {
62-
startMonitoring();
63-
} else {
64-
stopMonitoring();
65-
}
66-
}
36+
loadConfiguration();
6737

68-
private void startMonitoring() {
69-
String url = serverUrlField.getText();
70-
String secret = secretField.getText();
71-
String device = deviceNameField.getText();
72-
73-
if (url.isEmpty() || secret.isEmpty() || device.isEmpty()) {
74-
logger.warn("配置不完整,取消启动");
75-
showAlert(Alert.AlertType.ERROR, "启动失败", "配置信息不完整。请确保服务器地址、密钥和设备名称都已填写。");
76-
return;
38+
if (isRunning && monitorService != null) {
39+
String currentVersion = monitorService.getClient().getVersionTag(); // 需在 MonitorService 增加 getClient
40+
if (currentVersion.contains("v6")) {
41+
protocolVersionBox.setValue("Protocol v6 (Modern)");
42+
} else {
43+
protocolVersionBox.setValue("Protocol v5 (Legacy)");
44+
}
45+
updateUIState(); // 锁定所有输入框
7746
}
7847

79-
// 启动逻辑
80-
SleepyClient client = new SleepyClient(url, secret, device);
81-
monitorService = new MonitorService(client, (appName) -> {
82-
Platform.runLater(() -> statusLabel.setText("正在运行: " + appName));
48+
// 4. 【核心修复】监听下拉框,改变即保存
49+
protocolVersionBox.getSelectionModel().selectedItemProperty().addListener((obs, oldVal, newVal) -> {
50+
if (newVal != null && !isRunning) {
51+
updateRefreshFieldState(); // 更新刷新密钥置灰状态
52+
saveCurrentConfig(); // 只要改了就保存,防止切换 Tab 丢失
53+
}
8354
});
8455

85-
monitorService.start();
86-
isRunning = true;
87-
updateUIState();
88-
logger.info(">>> 监控已启动,设备名: {}", device);
89-
}
90-
91-
private void stopMonitoring() {
92-
if (monitorService != null) monitorService.stop();
93-
isRunning = false;
94-
updateUIState();
95-
logger.info(">>> 监控已手动停止");
96-
}
97-
98-
private void updateUIState() {
9956
if (isRunning) {
100-
startBtn.setText("停止监控");
101-
startBtn.setStyle("-fx-background-color: #e74c3c; -fx-text-fill: white;");
102-
statusLabel.setText("状态: 运行中");
57+
statusLabel.setText("状态: 正在监控 (" + protocolVersionBox.getValue() + ")");
10358
} else {
104-
startBtn.setText("开始监控");
105-
startBtn.setStyle(""); // 恢复 CSS 默认
10659
statusLabel.setText("状态: 已停止");
10760
}
10861
}
10962

63+
private void updateRefreshFieldState() {
64+
boolean isV6 = protocolVersionBox.getValue().contains("v6");
65+
boolean isAuto = autoProtocolCheck.isSelected();
66+
// 只有非自动模式且选了 V6,或者自动模式(待检测)时,我们根据需要开启
67+
refreshTokenField.setDisable(!isV6 && !isAuto);
68+
refreshLabel.setOpacity(refreshTokenField.isDisable() ? 0.5 : 1.0);
69+
}
70+
71+
@FXML
72+
private void handleAutoProtocolToggle() {
73+
protocolVersionBox.setDisable(autoProtocolCheck.isSelected());
74+
updateRefreshFieldState();
75+
}
76+
11077
@FXML
11178
private void handleTestConnection() {
11279
String url = serverUrlField.getText().trim();
113-
11480
if (url.isEmpty()) {
115-
showStatus("请输入服务器地址", "red");
81+
showAlert(Alert.AlertType.WARNING, "提醒", "请输入服务器地址后再进行测试");
11682
return;
11783
}
11884

119-
if (!url.startsWith("http://") && !url.startsWith("https://")) {
120-
url = "http://" + url;
121-
serverUrlField.setText(url);
122-
}
123-
124-
// 禁用按钮防止重复点击
85+
// UI 反馈
12586
testConnBtn.setDisable(true);
126-
testConnBtn.setText("测试中...");
87+
statusLabel.setText("状态: 正在测试连通性...");
12788

128-
String finalUrl1 = url;
89+
// 在后台线程执行网络操作,避免 UI 卡死
12990
new Thread(() -> {
130-
boolean success = false;
131-
try {
132-
// 2. 使用锁定的 url 变量
133-
SleepyClient testClient = new SleepyClient(finalUrl1, "", "");
134-
success = testClient.ping();
135-
} catch (Exception e) {
136-
System.err.println("测试连接失败: " + e.getMessage());
137-
}
91+
SleepyPingProvider.PingResult result = SleepyPingProvider.testConnection(url);
13892

139-
// 3. 回到主线程更新 UI
140-
final boolean finalSuccess = success;
93+
// 回到 UI 线程更新界面
14194
Platform.runLater(() -> {
14295
testConnBtn.setDisable(false);
143-
testConnBtn.setText("测试连接");
144-
145-
if (finalSuccess) {
146-
showAlert(Alert.AlertType.INFORMATION, "成功", "服务器连接正常!");
96+
if (result.success) {
97+
statusLabel.setText("状态: 连接正常 (" + result.latencyMs + "ms)");
98+
showAlert(Alert.AlertType.INFORMATION, "测试通过",
99+
"成功连接到服务器!\n响应延迟: " + result.latencyMs + "ms");
147100
} else {
148-
showAlert(Alert.AlertType.ERROR, "失败", "无法连接到服务器,请检查地址或网络。");
101+
statusLabel.setText("状态: 连接失败");
102+
showAlert(Alert.AlertType.ERROR, "测试失败", result.message);
149103
}
150104
});
151105
}).start();
152106
}
153107

154-
private void showStatus(String message, String color) {
155-
System.out.println("Status: " + message);
156-
}
108+
@FXML
109+
private void handleStart() {
110+
if (isRunning) {
111+
stopMonitoring();
112+
return;
113+
}
157114

158-
private void showAlert(Alert.AlertType type, String title, String content) {
159-
Alert alert = new Alert(type, content, ButtonType.OK);
160-
alert.setTitle(title);
161-
alert.setHeaderText(null);
162-
alert.showAndWait();
115+
saveCurrentConfig();
116+
117+
if (autoProtocolCheck.isSelected()) {
118+
statusLabel.setText("状态: 自动识别中...");
119+
new Thread(() -> {
120+
int version = SleepyClientV5.probeProtocolVersion(serverUrlField.getText());
121+
Platform.runLater(() -> executeStartSequence(version));
122+
}).start();
123+
} else {
124+
executeStartSequence(protocolVersionBox.getValue().contains("v6") ? 6 : 5);
125+
}
163126
}
164127

165-
@FXML
166-
private void handleSaveConfig() {
167-
String url = serverUrlField.getText().trim();
168-
String secret = secretField.getText().trim();
169-
String deviceName = deviceNameField.getText().trim();
128+
private void executeStartSequence(int version) {
129+
// 确保在主线程更新 UI 状态
130+
Platform.runLater(() -> {
131+
// 如果是自动检测出来的版本,我们需要手动同步下拉框的值
132+
// 这样 updateRefreshFieldState() 才能拿到正确的结果
133+
if (autoProtocolCheck.isSelected()) {
134+
if (version == 6) {
135+
protocolVersionBox.setValue("Protocol v6 (Modern)");
136+
} else {
137+
protocolVersionBox.setValue("Protocol v5 (Legacy)");
138+
}
139+
}
140+
// 核心修复:强制刷新“刷新密钥”一栏的禁用/启用状态
141+
updateRefreshFieldState();
142+
});
170143

171-
if (url.isEmpty()) {
172-
showAlert(Alert.AlertType.WARNING, "校验失败", "服务器地址不能为空");
173-
return;
144+
// 原有的启动逻辑...
145+
ISleepyClient client = SleepyClientFactory.createClient();
146+
monitorService = new MonitorService(client, (appName) -> {
147+
Platform.runLater(() -> statusLabel.setText("正在运行: " + appName));
148+
});
149+
150+
if (monitorService.start()) {
151+
isRunning = true;
152+
Platform.runLater(this::updateUIState); // 务必在 UI 线程刷新按钮文字
153+
} else {
154+
Platform.runLater(() -> {
155+
statusLabel.setText("状态: 连接失败");
156+
isRunning = false;
157+
updateUIState();
158+
});
174159
}
160+
}
175161

162+
private void stopMonitoring() {
163+
if (monitorService != null) monitorService.stop();
164+
isRunning = false;
165+
updateUIState();
166+
}
167+
168+
@FXML
169+
private void handleSaveAction() {
170+
saveCurrentConfig();
171+
showAlert(Alert.AlertType.INFORMATION, "成功", "配置已保存");
172+
}
173+
174+
private void saveCurrentConfig() {
176175
try {
177176
ConfigManager config = ConfigManager.getInstance();
178-
// 写入配置内存
179-
config.set("connection", "server_url", url);
180-
config.set("connection", "secret", secret);
181-
config.set("connection", "device_name", deviceName);
182-
183-
// 执行持久化,写入 .sleepy/config.ini
177+
config.set("server", "url", serverUrlField.getText());
178+
config.set("auth", "secret", secretField.getText());
179+
config.set("auth", "refresh_token", refreshTokenField.getText()); // 存入 auth 下
180+
config.set("device", "name", deviceNameField.getText());
181+
config.set("settings", "auto_protocol", String.valueOf(autoProtocolCheck.isSelected()));
182+
config.set("settings", "protocol_version", autoProtocolCheck.isSelected() ? "0" : (protocolVersionBox.getValue().contains("v6") ? "6" : "5"));
184183
config.save();
184+
} catch (IOException e) { logger.error("保存失败", e); }
185+
}
185186

186-
showAlert(Alert.AlertType.INFORMATION, "保存成功", "连接配置已持久化到本地。");
187-
logger.info("用户手动保存了连接配置: {}", url);
188-
} catch (IOException e) {
189-
logger.error("保存配置失败", e);
190-
showAlert(Alert.AlertType.ERROR, "保存失败", "无法写入配置文件: " + e.getMessage());
191-
}
187+
private void loadConfiguration() {
188+
try {
189+
ConfigManager config = ConfigManager.getInstance();
190+
serverUrlField.setText(config.get("server", "url", ""));
191+
secretField.setText(config.get("auth", "secret", ""));
192+
refreshTokenField.setText(config.get("auth", "refresh_token", ""));
193+
deviceNameField.setText(config.get("device", "name", "My-PC"));
194+
boolean isAuto = Boolean.parseBoolean(config.get("settings", "auto_protocol", "true"));
195+
autoProtocolCheck.setSelected(isAuto);
196+
protocolVersionBox.setDisable(isAuto);
197+
updateRefreshFieldState();
198+
} catch (Exception e) { logger.warn("配置加载失败"); }
199+
}
200+
201+
private void updateUIState() {
202+
// 强制 UI 切换
203+
startBtn.setText(isRunning ? "停止监控" : "开始监控");
204+
startBtn.getStyleClass().removeAll("primary-button", "danger-button");
205+
startBtn.getStyleClass().add(isRunning ? "danger-button" : "primary-button");
206+
207+
// 运行中禁用,停止后启用
208+
boolean disabled = isRunning;
209+
serverUrlField.setDisable(disabled);
210+
secretField.setDisable(disabled);
211+
refreshTokenField.setDisable(disabled || !protocolVersionBox.getValue().contains("v6")); // V6 特殊判断
212+
deviceNameField.setDisable(disabled);
213+
autoProtocolCheck.setDisable(disabled);
214+
protocolVersionBox.setDisable(disabled || autoProtocolCheck.isSelected());
215+
testConnBtn.setDisable(disabled);
216+
}
217+
private void showAlert(Alert.AlertType type, String title, String content) {
218+
Alert alert = new Alert(type, content, ButtonType.OK);
219+
alert.setTitle(title);
220+
alert.setHeaderText(null);
221+
alert.showAndWait();
192222
}
193223
}

0 commit comments

Comments
 (0)