fix: 用户组PHP→Java拉取JSON解析bug + owner_change重复打印
1. pullUserGroupsFromPHP: 数组结束查找逻辑修复
- 旧代码用[]计数找数组边界,但去掉开头[后内容是{},遇到]时depth=-1永远不匹配
- 改为用{}计数+objDepth==0时匹配],正确解析[{...},{...}]格式
2. setLandOwnerFromWeb: 幂等检查
- 如果所有者已相同(equalsIgnoreCase),跳过DB更新和日志打印
- 防止ack失败后同一条owner_change重复打印
3. processedChangeIds清理优化
- 超500时不再粗暴清空全部,先移除已过游标的旧ID(id < lastPollAdminChangesId)
- 只在清理后仍然过大时才全部清空
4. pullUserGroupsFromPHP: 增加调试日志
- 空响应/success!=true/无groups数组/解析失败都记录fine级别日志
This commit is contained in:
@@ -7545,6 +7545,12 @@ public class AreaProtection implements Listener {
|
||||
public void setLandOwnerFromWeb(String landName, String newOwner) {
|
||||
if (dbConnection == null) return;
|
||||
try {
|
||||
// ★ 幂等检查:如果所有者已相同则跳过,避免ack失败后重复打印
|
||||
AreaConfig ac = getLand(landName);
|
||||
if (ac != null && newOwner.equalsIgnoreCase(ac.owner)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新数据库
|
||||
PreparedStatement ps = dbConnection.prepareStatement("UPDATE area_lands SET owner = ? WHERE name = ?");
|
||||
ps.setString(1, newOwner);
|
||||
@@ -7553,7 +7559,6 @@ public class AreaProtection implements Listener {
|
||||
ps.close();
|
||||
|
||||
// 更新内存中的AreaConfig
|
||||
AreaConfig ac = getLand(landName);
|
||||
if (ac != null) {
|
||||
ac.owner = newOwner;
|
||||
}
|
||||
|
||||
@@ -3077,35 +3077,37 @@ public class WebManager {
|
||||
params.put("action", "list_user_groups");
|
||||
params.put("secret", secretKey);
|
||||
String resp = httpGet("api/land_api.php", params);
|
||||
if (resp == null || resp.isEmpty()) return;
|
||||
if (resp == null || resp.isEmpty()) { plugin.getLogger().fine("[防护-sync] 从PHP拉取用户组: 响应为空"); return; }
|
||||
|
||||
// 简单解析JSON: {"success":true,"groups":[{...},{...}]}
|
||||
if (!resp.contains("\"success\":true")) return;
|
||||
if (!resp.contains("\"success\":true")) { plugin.getLogger().fine("[防护-sync] 从PHP拉取用户组: success!=true, resp=" + resp.substring(0, Math.min(200, resp.length()))); return; }
|
||||
int groupsStart = resp.indexOf("\"groups\":[");
|
||||
if (groupsStart < 0) return;
|
||||
String arrStr = resp.substring(groupsStart + 10);
|
||||
// 找到数组的结束 ]
|
||||
int depth = 0;
|
||||
if (groupsStart < 0) { plugin.getLogger().fine("[防护-sync] 从PHP拉取用户组: 未找到groups数组"); return; }
|
||||
String arrStr = resp.substring(groupsStart + 10); // 跳过 "groups":[
|
||||
// ★ 修复:用{}计数来找数组的结束 ](去掉开头[后内容是{...},{...}],不含嵌套[])
|
||||
int objDepth = 0;
|
||||
int arrEnd = -1;
|
||||
for (int i = 0; i < arrStr.length(); i++) {
|
||||
char c = arrStr.charAt(i);
|
||||
if (c == '[') depth++;
|
||||
else if (c == ']') {
|
||||
depth--;
|
||||
if (depth == 0) { arrEnd = i; break; }
|
||||
if (c == '{') objDepth++;
|
||||
else if (c == '}') objDepth--;
|
||||
else if (c == ']' && objDepth == 0) {
|
||||
arrEnd = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (arrEnd < 0) return;
|
||||
arrStr = arrStr.substring(1, arrEnd); // 去掉 [ ]
|
||||
if (arrEnd < 0) { plugin.getLogger().fine("[防护-sync] 从PHP拉取用户组: 数组解析失败"); return; }
|
||||
arrStr = arrStr.substring(1, arrEnd); // 去掉开头 [ 和结尾 ]
|
||||
|
||||
if (arrStr.trim().isEmpty()) return; // 空数组
|
||||
|
||||
UserGroupManager ugm = plugin.getUserGroup();
|
||||
if (ugm == null) return;
|
||||
|
||||
plugin.getLogger().fine("[防护-sync] 从PHP拉取用户组: 解析到 " + arrStr.length() + " 字符的数组内容");
|
||||
// 拆分每个JSON对象
|
||||
int imported = 0;
|
||||
depth = 0;
|
||||
int depth = 0;
|
||||
int objStart = -1;
|
||||
for (int i = 0; i < arrStr.length(); i++) {
|
||||
char c = arrStr.charAt(i);
|
||||
@@ -3309,9 +3311,11 @@ public class WebManager {
|
||||
doGet(ackUrl);
|
||||
}
|
||||
|
||||
// ★ 清理去重集合,防止内存泄漏
|
||||
// ★ 清理去重集合:只清理已过游标的旧ID,防止ACK失败后重复打印
|
||||
if (processedChangeIds.size() > 500) {
|
||||
processedChangeIds.clear();
|
||||
processedChangeIds.removeIf(id -> id < lastPollAdminChangesId);
|
||||
// 如果清理后仍然过大,才全部清空(最后手段)
|
||||
if (processedChangeIds.size() > 500) processedChangeIds.clear();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().warning("[Web通信] 轮询PHP管理员变更异常: " + e.getMessage());
|
||||
|
||||
Reference in New Issue
Block a user