新增Web CDK接口,可对接Web系统进行兑换

This commit is contained in:
youpaishidifu
2026-06-20 14:02:41 +08:00
parent 2c7f765fb0
commit 203c9d423a
5 changed files with 328 additions and 21 deletions
+8 -2
View File
@@ -172,9 +172,15 @@ public class LoginManager {
plugin.getDb().setField(name, plugin.getDb().setField(name,
"last_online_check", "last_online_check",
System.currentTimeMillis()); System.currentTimeMillis());
// ★ 立即同步在线状态到PHP // ★ 立即同步在线状态到PHP(异步,避免阻塞主线程)
if (plugin.webManager != null) { if (plugin.webManager != null) {
plugin.webManager.syncOnlinePlayers(); Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
try {
plugin.webManager.syncOnlinePlayers();
} catch (Exception e) {
plugin.getLogger().warning("[Web通信] 异步syncOnlinePlayers异常: " + e.getMessage());
}
});
} }
// 登录成功关闭飞行 // 登录成功关闭飞行
p.setAllowFlight(false); p.setAllowFlight(false);
+8 -2
View File
@@ -1167,9 +1167,15 @@ public class Main extends JavaPlugin
joinTime.remove(p.getUniqueId()); joinTime.remove(p.getUniqueId());
recordIPLogin(p); recordIPLogin(p);
// ★ 立即同步在线状态到PHP(不等下次心跳30秒) // ★ 立即同步在线状态到PHP(异步,避免阻塞主线程)
if (webManager != null) { if (webManager != null) {
webManager.syncOnlinePlayers(); Bukkit.getScheduler().runTaskAsynchronously(this, () -> {
try {
webManager.syncOnlinePlayers();
} catch (Exception e) {
getLogger().warning("[Web通信] 异步syncOnlinePlayers异常: " + e.getMessage());
}
});
} }
// 只在有有效备份时恢复 // 只在有有效备份时恢复
+44 -12
View File
@@ -48,12 +48,16 @@ public class UpdateChecker {
private static final String GITHUB_REPO = "sdf1_login"; private static final String GITHUB_REPO = "sdf1_login";
private static final String GITEE_OWNER = "nihaoshidifu"; private static final String GITEE_OWNER = "nihaoshidifu";
private static final String GITEE_REPO = "sdf1_login"; private static final String GITEE_REPO = "sdf1_login";
private static final String GYP_OWNER = "youpaishidifu";
private static final String GYP_REPO = "Sdf1_login";
// API 地址(使用releases/latest获取最新版本) // API 地址(使用releases/latest获取最新版本)
private static final String GITHUB_API = private static final String GITHUB_API =
"https://api.github.com/repos/" + GITHUB_OWNER + "/" + GITHUB_REPO + "/releases/latest"; "https://api.github.com/repos/" + GITHUB_OWNER + "/" + GITHUB_REPO + "/releases/latest";
private static final String GITEE_API = private static final String GITEE_API =
"https://gitee.com/api/v5/repos/" + GITEE_OWNER + "/" + GITEE_REPO + "/releases/latest"; "https://gitee.com/api/v5/repos/" + GITEE_OWNER + "/" + GITEE_REPO + "/releases/latest";
private static final String GYP_API =
"https://git.ypshidifu.cn/api/v1/repos/" + GYP_OWNER + "/" + GYP_REPO + "/releases/latest";
// 第三路备选:宝塔静态HTML // 第三路备选:宝塔静态HTML
private static final String FALLBACK_HTML = private static final String FALLBACK_HTML =
@@ -64,6 +68,8 @@ public class UpdateChecker {
"https://github.com/" + GITHUB_OWNER + "/" + GITHUB_REPO + "/releases"; "https://github.com/" + GITHUB_OWNER + "/" + GITHUB_REPO + "/releases";
private static final String GITEE_LINK = private static final String GITEE_LINK =
"https://gitee.com/" + GITEE_OWNER + "/" + GITEE_REPO + "/releases"; "https://gitee.com/" + GITEE_OWNER + "/" + GITEE_REPO + "/releases";
private static final String GYP_LINK =
"https://git.ypshidifu.cn/" + GYP_OWNER + "/" + GYP_REPO + "/releases";
// 单次请求超时(毫秒) // 单次请求超时(毫秒)
private static final int TIMEOUT_MS = 5000; private static final int TIMEOUT_MS = 5000;
@@ -157,18 +163,31 @@ public class UpdateChecker {
plugin.getLogger().info("[Sdf1_login] 启动自动检查更新..."); plugin.getLogger().info("[Sdf1_login] 启动自动检查更新...");
} }
// ★ 双通道并行执行,一路成功掐断另一路 // ★ 三通道并行执行,一路成功掐断其余
AtomicBoolean cancelled = new AtomicBoolean(false); AtomicBoolean cancelled = new AtomicBoolean(false);
AtomicReference<CheckResult> gypResult = new AtomicReference<>();
AtomicReference<CheckResult> ghResult = new AtomicReference<>(); AtomicReference<CheckResult> ghResult = new AtomicReference<>();
AtomicReference<CheckResult> geResult = new AtomicReference<>(); AtomicReference<CheckResult> geResult = new AtomicReference<>();
CountDownLatch latch = new CountDownLatch(2); CountDownLatch latch = new CountDownLatch(3);
// 通道0:git.ypshidifu.cn(最高优先级,Gitea格式)
Thread gypThread = new Thread(() -> {
if (!cancelled.get()) {
gypResult.set(tryChannel(GYP_API, "git.ypshidifu.cn", GYP_LINK));
if (gypResult.get().isSuccess()) {
cancelled.set(true);
}
}
latch.countDown();
});
gypThread.setDaemon(true);
// 通道1:GitHub // 通道1:GitHub
Thread ghThread = new Thread(() -> { Thread ghThread = new Thread(() -> {
if (!cancelled.get()) { if (!cancelled.get()) {
ghResult.set(tryChannel(GITHUB_API, "GitHub", GITHUB_LINK)); ghResult.set(tryChannel(GITHUB_API, "GitHub", GITHUB_LINK));
if (ghResult.get().isSuccess()) { if (ghResult.get().isSuccess()) {
cancelled.set(true); // 成功则取消另一路 cancelled.set(true);
} }
} }
latch.countDown(); latch.countDown();
@@ -180,34 +199,38 @@ public class UpdateChecker {
if (!cancelled.get()) { if (!cancelled.get()) {
geResult.set(tryChannel(GITEE_API, "Gitee", GITEE_LINK)); geResult.set(tryChannel(GITEE_API, "Gitee", GITEE_LINK));
if (geResult.get().isSuccess()) { if (geResult.get().isSuccess()) {
cancelled.set(true); // 成功则取消另一路 cancelled.set(true);
} }
} }
latch.countDown(); latch.countDown();
}); });
geThread.setDaemon(true); geThread.setDaemon(true);
gypThread.start();
ghThread.start(); ghThread.start();
geThread.start(); geThread.start();
try { try {
latch.await(); // 等待两路都完成 latch.await();
} catch (InterruptedException ignored) { } catch (InterruptedException ignored) {
} }
CheckResult gyp = gypResult.get();
CheckResult gh = ghResult.get(); CheckResult gh = ghResult.get();
CheckResult ge = geResult.get(); CheckResult ge = geResult.get();
// 选择成功的结果 // 选择成功的结果(优先级:git.ypshidifu.cn > GitHub > Gitee)
CheckResult chosen = null; CheckResult chosen = null;
if (gh != null && gh.isSuccess()) { if (gyp != null && gyp.isSuccess()) {
chosen = gyp;
} else if (gh != null && gh.isSuccess()) {
chosen = gh; chosen = gh;
} else if (ge != null && ge.isSuccess()) { } else if (ge != null && ge.isSuccess()) {
chosen = ge; chosen = ge;
} else { } else {
// ★ 双通道均失败,尝试第三路备选(宝塔静态HTML) // ★ 双通道均失败,尝试第三路备选(宝塔静态HTML)
plugin.getLogger().info("[Sdf1_login] GitHub/Gitee 均失败,尝试第三路备选 BaoTa..."); plugin.getLogger().info("[Sdf1_login] git.ypshidifu.cn/GitHub/Gitee 均失败,尝试第三路备选 BaoTa...");
CheckResult fbResult = tryFallbackChannel(); CheckResult fbResult = tryFallbackChannel();
if (fbResult != null && fbResult.isSuccess()) { if (fbResult != null && fbResult.isSuccess()) {
chosen = fbResult; chosen = fbResult;
@@ -215,7 +238,11 @@ public class UpdateChecker {
} else { } else {
failCount++; failCount++;
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
if (gyp != null && gyp.error != null) {
sb.append("§7git.ypshidifu.cn: §c").append(gyp.error);
}
if (gh != null && gh.error != null) { if (gh != null && gh.error != null) {
if (sb.length() > 0) sb.append("\n");
sb.append("§7GitHub: §c").append(gh.error); sb.append("§7GitHub: §c").append(gh.error);
} }
if (ge != null && ge.error != null) { if (ge != null && ge.error != null) {
@@ -310,10 +337,15 @@ public class UpdateChecker {
sender.sendMessage("§a[Sdf1_login] [更新] 已是最新版本"); sender.sendMessage("§a[Sdf1_login] [更新] 已是最新版本");
} }
// 显示另一通道的失败原因 // 显示其他失败通道的错误信息
CheckResult other = (src.equals("GitHub")) ? ge : gh; if (gyp != null && !gyp.isSuccess() && gyp.error != null && !src.equals("git.ypshidifu.cn")) {
if (other != null && !other.isSuccess() && other.error != null) { sender.sendMessage("§7[Sdf1_login] [更新] git.ypshidifu.cn 不可用: " + gyp.error);
sender.sendMessage("§7[Sdf1_login] [更新] " + other.source + " 不可用: " + other.error); }
if (gh != null && !gh.isSuccess() && gh.error != null && !src.equals("GitHub")) {
sender.sendMessage("§7[Sdf1_login] [更新] GitHub 不可用: " + gh.error);
}
if (ge != null && !ge.isSuccess() && ge.error != null && !src.equals("Gitee")) {
sender.sendMessage("§7[Sdf1_login] [更新] Gitee 不可用: " + ge.error);
} }
}); });
} }
+267 -4
View File
@@ -124,6 +124,7 @@ public class WebManager {
syncIntervalMinutes = Integer.parseInt(getConfigValue("web通信-同步间隔分钟", "5")); syncIntervalMinutes = Integer.parseInt(getConfigValue("web通信-同步间隔分钟", "5"));
callbackPort = Integer.parseInt(getConfigValue("web通信-回调端口", "9090")); callbackPort = Integer.parseInt(getConfigValue("web通信-回调端口", "9090"));
secretKey = getConfigValue("web通信-密钥", secretKey); secretKey = getConfigValue("web通信-密钥", secretKey);
plugin.getLogger().info("[Web通信] 后端地址: " + webBaseUrl + " | 启用: " + enabled);
} }
/** /**
@@ -258,6 +259,9 @@ public class WebManager {
// ★ 启动交易高频轮询(每5秒检查PHP端是否有待处理交易) // ★ 启动交易高频轮询(每5秒检查PHP端是否有待处理交易)
startTransactionPolling(); startTransactionPolling();
// ★ 启动CDK验证轮询(每2秒检查PHP端CDK验证请求)
startCdkValidationPolling();
plugin.getLogger().info("[Web通信] 实时同步调度器已启动(60~90秒随机,无人停止,有人恢复)"); plugin.getLogger().info("[Web通信] 实时同步调度器已启动(60~90秒随机,无人停止,有人恢复)");
plugin.getLogger().info("[Web通信] PHP回调服务器已启动,端口: " + callbackPort); plugin.getLogger().info("[Web通信] PHP回调服务器已启动,端口: " + callbackPort);
} }
@@ -737,8 +741,8 @@ public class WebManager {
HttpURLConnection conn = (HttpURLConnection) url.openConnection(); HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET"); conn.setRequestMethod("GET");
conn.setRequestProperty("User-Agent", "Sdf1-WebManager/1.0"); conn.setRequestProperty("User-Agent", "Sdf1-WebManager/1.0");
conn.setConnectTimeout(5000); conn.setConnectTimeout(8000);
conn.setReadTimeout(5000); conn.setReadTimeout(10000);
int code = conn.getResponseCode(); int code = conn.getResponseCode();
if (code != 200) { if (code != 200) {
plugin.getLogger().warning("[Web交易轮询] HTTP状态码: " + code); plugin.getLogger().warning("[Web交易轮询] HTTP状态码: " + code);
@@ -775,6 +779,244 @@ public class WebManager {
}.runTaskTimerAsynchronously(plugin, 20L * 5, 20L * 5); // 每5秒检查一次 }.runTaskTimerAsynchronously(plugin, 20L * 5, 20L * 5); // 每5秒检查一次
} }
// ==================== CDK验证轮询 ====================
/**
* 每2秒检查PHP端的CDK验证请求,本地验证后推送结果回去
* 让Web前端的CDK兑换可以验证Java端(bond.db)中的CDK
* 同时拉取sdf1插件的pending远程验证请求,发送到Web后端
*/
private void startCdkValidationPolling() {
new BukkitRunnable() {
@Override
public void run() {
try {
// === Part 1: 拉取Web端的CDK验证请求 → 本地验证 ===
pullWebCdkRequestsAndValidate();
// === Part 2: 拉取sdf1插件的pending请求 → 发送到Web验证 ===
pullSdf1PendingAndValidateWeb();
} catch (Exception e) {
// 静默,避免刷屏
}
}
}.runTaskTimerAsynchronously(plugin, 20L * 2, 20L * 2); // 每2秒检查一次
plugin.getLogger().info("[Web通信] CDK远程验证轮询已启动(每2秒)");
}
/**
* Part 1: Web端写cdk_validate_requests → Sdf1_login拉取 → 本地CDKManager.redeem → 写回结果
*/
private void pullWebCdkRequestsAndValidate() {
try {
String listUrl = webBaseUrl + "/api/sync.php?action=pull_cdk_validate_requests&secret="
+ java.net.URLEncoder.encode(secretKey, "UTF-8");
URL url = new URL(listUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("User-Agent", "Sdf1-CDKValidator/1.0");
conn.setConnectTimeout(8000);
conn.setReadTimeout(10000);
int respCode = conn.getResponseCode();
if (respCode != 200) { conn.disconnect(); return; }
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) sb.append(line);
reader.close();
conn.disconnect();
String json = sb.toString();
if (!json.contains("\"success\":true")) return;
int reqIdx = json.indexOf("\"requests\":[");
if (reqIdx < 0) return;
int arrStart = json.indexOf('[', reqIdx);
int arrEnd = json.indexOf(']', arrStart);
if (arrEnd < 0) return;
String arr = json.substring(arrStart, arrEnd + 1);
if (arr.equals("[]")) return;
int pi = 0;
while (pi < arr.length()) {
int objStart = arr.indexOf('{', pi);
if (objStart < 0) break;
int objEnd = arr.indexOf('}', objStart);
if (objEnd < 0) break;
String obj = arr.substring(objStart, objEnd + 1);
pi = objEnd + 1;
String requestId = extractJsonStr(obj, "request_id");
String cdkCode = extractJsonStr(obj, "code");
String playerName = extractJsonStr(obj, "player_name");
if (requestId.isEmpty() || cdkCode.isEmpty()) continue;
if (playerName.isEmpty()) playerName = "web_remote";
// ★ 直接检查sdf1计分板CDK(bond.db只是钱包,不存CDK)
String status = "not_found";
int amount = 0;
try {
Object sdf1Plugin = Bukkit.getPluginManager().getPlugin("sdf1");
if (sdf1Plugin != null) {
plugin.getLogger().info("[CDK远程验证] 调用sdf1检查计分板: " + cdkCode);
java.lang.reflect.Method checkMethod = sdf1Plugin.getClass().getMethod("checkScoreBoardCdk", String.class);
String[] sbResult = (String[]) checkMethod.invoke(sdf1Plugin, cdkCode);
plugin.getLogger().info("[CDK远程验证] sdf1返回: " + (sbResult != null ? String.join(",", sbResult) : "null"));
if (sbResult != null && sbResult.length >= 2 && "success".equals(sbResult[0])) {
status = "success";
amount = Integer.parseInt(sbResult[1]);
plugin.getLogger().info("[CDK远程验证] 计分板CDK匹配: " + cdkCode + " 金额=" + amount);
} else if (sbResult != null && "not_bond".equals(sbResult[0])) {
status = "not_bond";
plugin.getLogger().info("[CDK远程验证] 计分板CDK存在但非债券类型: " + cdkCode);
} else {
plugin.getLogger().info("[CDK远程验证] 计分板CDK未找到: " + cdkCode);
}
} else {
plugin.getLogger().warning("[CDK远程验证] sdf1插件未加载");
}
} catch (Exception e) {
plugin.getLogger().warning("[CDK远程验证] 检查计分板异常: " + e.getClass().getSimpleName() + ": " + e.getMessage());
}
// 推送结果回PHP
String pushUrl = webBaseUrl + "/api/sync.php?action=push_cdk_validate_result&secret="
+ java.net.URLEncoder.encode(secretKey, "UTF-8")
+ "&request_id=" + java.net.URLEncoder.encode(requestId, "UTF-8")
+ "&code=" + java.net.URLEncoder.encode(cdkCode, "UTF-8")
+ "&status=" + java.net.URLEncoder.encode(status, "UTF-8")
+ "&amount=" + amount;
URL pushUrlObj = new URL(pushUrl);
HttpURLConnection pushConn = (HttpURLConnection) pushUrlObj.openConnection();
pushConn.setRequestMethod("GET");
pushConn.setConnectTimeout(8000);
pushConn.setReadTimeout(10000);
pushConn.getResponseCode();
pushConn.disconnect();
if (!"not_found".equals(status)) {
plugin.getLogger().info("[CDK远程验证] " + cdkCode + " → " + status + " player=" + playerName + (amount > 0 ? " 金额:" + amount : ""));
}
}
} catch (Exception e) {
// 静默
}
}
/**
* Part 2: sdf1插件pending队列 → Sdf1_login拉取 → 发送Web validate_cdk → 结果回传sdf1
*/
private void pullSdf1PendingAndValidateWeb() {
try {
// 通过反射获取sdf1插件(避免直接依赖Plugin类)
Object sdf1Plugin = Bukkit.getPluginManager().getPlugin("sdf1");
if (sdf1Plugin == null) return;
// 检查是否启用
java.lang.reflect.Method isEnabled = sdf1Plugin.getClass().getMethod("isEnabled");
if (!(Boolean) isEnabled.invoke(sdf1Plugin)) return;
// 调用 sdf1.Main.pullPendingCdkValidations()
java.lang.reflect.Method pullMethod = sdf1Plugin.getClass().getMethod("pullPendingCdkValidations");
Object[][] pendingList = (Object[][]) pullMethod.invoke(sdf1Plugin);
if (pendingList == null || pendingList.length == 0) return;
for (Object[] item : pendingList) {
String requestId = (String) item[0];
String cdkCode = (String) item[1];
String playerName = (String) item[2];
// ★ 先检查CDK是否存在(只读)
String status = "not_found";
int amount = 0;
try {
String validateUrl = webBaseUrl + "/api/sync.php?action=check_cdk_exists&secret="
+ java.net.URLEncoder.encode(secretKey, "UTF-8")
+ "&code=" + java.net.URLEncoder.encode(cdkCode, "UTF-8");
URL vUrl = new URL(validateUrl);
HttpURLConnection vConn = (HttpURLConnection) vUrl.openConnection();
vConn.setRequestMethod("GET");
vConn.setConnectTimeout(8000);
vConn.setReadTimeout(10000);
int vCode = vConn.getResponseCode();
if (vCode == 200) {
BufferedReader vReader = new BufferedReader(new InputStreamReader(vConn.getInputStream(), StandardCharsets.UTF_8));
StringBuilder vSb = new StringBuilder();
String vLine;
while ((vLine = vReader.readLine()) != null) vSb.append(vLine);
vReader.close();
vConn.disconnect();
String vJson = vSb.toString();
// ★ 详细日志:PHP返回的原始JSON
plugin.getLogger().info("[CDK-Web验证] PHP原始返回: " + vJson);
String found = extractJsonStr(vJson, "found");
String st = extractJsonStr(vJson, "status");
String am = extractJsonStr(vJson, "amount");
plugin.getLogger().info("[CDK-Web验证] 解析结果: found=" + found + " status=" + st + " amount=" + am);
if ("true".equals(found) && "available".equals(st)) {
amount = am.isEmpty() ? 0 : Integer.parseInt(am);
// ★ CDK存在且可用,调用兑换API标记已使用+写流水
// status只在cdk_redeem_remote成功后才设为success
try {
String redeemUrl = webBaseUrl + "/api/sync.php?action=cdk_redeem_remote&secret="
+ java.net.URLEncoder.encode(secretKey, "UTF-8")
+ "&code=" + java.net.URLEncoder.encode(cdkCode, "UTF-8")
+ "&player=" + java.net.URLEncoder.encode(playerName, "UTF-8");
URL rUrl = new URL(redeemUrl);
HttpURLConnection rConn = (HttpURLConnection) rUrl.openConnection();
rConn.setRequestMethod("GET");
rConn.setConnectTimeout(5000);
rConn.setReadTimeout(5000);
int rCode = rConn.getResponseCode();
if (rCode == 200) {
BufferedReader rReader = new BufferedReader(new InputStreamReader(rConn.getInputStream(), StandardCharsets.UTF_8));
StringBuilder rSb = new StringBuilder();
String rLine;
while ((rLine = rReader.readLine()) != null) rSb.append(rLine);
rReader.close();
rConn.disconnect();
String rJson = rSb.toString();
plugin.getLogger().info("[CDK-Web验证] 兑换结果: " + rJson);
String rSt = extractJsonStr(rJson, "status");
if ("success".equals(rSt)) {
status = "success";
} else if ("already_used".equals(rSt)) {
status = "already_used";
}
} else {
plugin.getLogger().warning("[CDK-Web验证] cdk_redeem_remote HTTP: " + rCode);
}
} catch (Exception e) {
plugin.getLogger().warning("[CDK-Web验证] 兑换请求失败: " + e.getMessage());
}
} else if ("true".equals(found) && "already_used".equals(st)) {
status = "already_used";
} else {
plugin.getLogger().info("[CDK-Web验证] CDK " + cdkCode + " 在Web端不存在或状态未知");
}
} else {
plugin.getLogger().warning("[CDK-Web验证] HTTP状态码: " + vCode + " CDK=" + cdkCode);
vConn.disconnect();
}
} catch (Exception e) {
plugin.getLogger().warning("[CDK-Web验证] 请求失败: " + e.getMessage());
}
// 回传结果给sdf1
java.lang.reflect.Method setResult = sdf1Plugin.getClass().getMethod("setCdkValidationResult", String.class, String.class, int.class);
setResult.invoke(sdf1Plugin, requestId, status, amount);
if (!"not_found".equals(status)) {
plugin.getLogger().info("[CDK-Web验证] " + cdkCode + " → " + status + " player=" + playerName + (amount > 0 ? " 金额:" + amount : ""));
}
}
} catch (Exception e) {
// 静默
}
}
// ==================== Token同步到Web ==================== // ==================== Token同步到Web ====================
/** /**
@@ -1140,6 +1382,20 @@ public class WebManager {
} }
} }
/**
* 简单JSON字符串值提取(不依赖第三方库)
*/
private static String extractJsonStr(String json, String key) {
int i = json.indexOf("\"" + key + "\"");
if (i < 0) return "";
int colon = json.indexOf(":", i);
int start = json.indexOf("\"", colon + 1);
if (start < 0) return "";
int end = json.indexOf("\"", start + 1);
if (end < 0) return "";
return json.substring(start + 1, end);
}
/** /**
* 简单JSON解析(提取字段值) * 简单JSON解析(提取字段值)
*/ */
@@ -1708,6 +1964,13 @@ public class WebManager {
Map<String, Object> playerInfo = new LinkedHashMap<>(); Map<String, Object> playerInfo = new LinkedHashMap<>();
playerInfo.put("name", p.getName()); playerInfo.put("name", p.getName());
playerInfo.put("login_time", System.currentTimeMillis() / 1000); playerInfo.put("login_time", System.currentTimeMillis() / 1000);
// ★ 推送当前IP(从Bukkit Player对象实时获取,不走login.db缓存)
try {
java.net.InetSocketAddress addr = p.getAddress();
if (addr != null && addr.getAddress() != null) {
playerInfo.put("ip", addr.getAddress().getHostAddress());
}
} catch (Exception ignored) {}
playersData.add(playerInfo); playersData.add(playerInfo);
} }
@@ -3658,8 +3921,8 @@ public class WebManager {
HttpURLConnection conn = (HttpURLConnection) url.openConnection(); HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET"); conn.setRequestMethod("GET");
conn.setRequestProperty("User-Agent", "Sdf1-WebManager/1.0"); conn.setRequestProperty("User-Agent", "Sdf1-WebManager/1.0");
conn.setConnectTimeout(3000); // 缩短超时到3秒 conn.setConnectTimeout(8000);
conn.setReadTimeout(3000); conn.setReadTimeout(10000);
int code = conn.getResponseCode(); int code = conn.getResponseCode();
if (code != 200) { if (code != 200) {
+1 -1
View File
@@ -1,5 +1,5 @@
name: Sdf1_login name: Sdf1_login
version: 2.3 version: 2.5
main: Sdf1_login.Main main: Sdf1_login.Main
api-version: '1.21' api-version: '1.21'
commands: commands: