111 lines
4.0 KiB
Java
111 lines
4.0 KiB
Java
package com.example.playertime;
|
|
|
|
import com.google.gson.Gson;
|
|
import com.sun.net.httpserver.HttpServer;
|
|
import com.sun.net.httpserver.HttpHandler;
|
|
import com.sun.net.httpserver.HttpExchange;
|
|
|
|
import java.io.*;
|
|
import java.net.InetSocketAddress;
|
|
import java.net.URL;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.nio.file.*;
|
|
import java.util.*;
|
|
import java.util.concurrent.*;
|
|
|
|
public class WebServer {
|
|
private final HttpServer server;
|
|
private final PlayerTimeTracker timeTracker;
|
|
private final ExecutorService executor = Executors.newFixedThreadPool(4);
|
|
private static final Map<String, String> MIME_TYPES = Map.of(
|
|
"html", "text/html",
|
|
"css", "text/css",
|
|
"js", "application/javascript",
|
|
"json", "application/json"
|
|
);
|
|
|
|
public WebServer(PlayerTimeTracker timeTracker, int port) throws IOException {
|
|
this.timeTracker = timeTracker;
|
|
this.server = HttpServer.create(new InetSocketAddress(port), 0);
|
|
setupContexts();
|
|
}
|
|
|
|
private void setupContexts() {
|
|
// API 端点
|
|
// 在 WebServer.java 中修改 /api/stats 的处理
|
|
server.createContext("/api/stats", exchange -> {
|
|
if (!"GET".equals(exchange.getRequestMethod())) {
|
|
sendResponse(exchange, 405, "Method Not Allowed");
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// 改为使用新的白名单统计方法
|
|
Map<String, String> stats = timeTracker.getWhitelistedPlayerStats();
|
|
String response = new Gson().toJson(stats);
|
|
sendResponse(exchange, 200, response.getBytes(), "application/json");
|
|
} catch (Exception e) {
|
|
PlayerTimeMod.LOGGER.error("Failed to get stats", e);
|
|
sendResponse(exchange, 500, "Internal Server Error");
|
|
}
|
|
});
|
|
|
|
// 静态文件服务
|
|
server.createContext("/", exchange -> {
|
|
try {
|
|
String path = exchange.getRequestURI().getPath();
|
|
if (path.equals("/")) path = "/index.html";
|
|
|
|
// 从资源目录加载文件
|
|
String resourcePath = "assets/playertime/web" + path;
|
|
InputStream is = getClass().getClassLoader().getResourceAsStream(resourcePath);
|
|
|
|
if (is == null) {
|
|
sendResponse(exchange, 404, "Not Found");
|
|
return;
|
|
}
|
|
|
|
// 确定内容类型
|
|
String extension = path.substring(path.lastIndexOf('.') + 1);
|
|
String contentType = MIME_TYPES.getOrDefault(extension, "text/plain");
|
|
|
|
// 读取文件内容
|
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
|
byte[] data = new byte[1024];
|
|
int nRead;
|
|
while ((nRead = is.read(data, 0, data.length)) != -1) {
|
|
buffer.write(data, 0, nRead);
|
|
}
|
|
buffer.flush();
|
|
|
|
sendResponse(exchange, 200, buffer.toByteArray(), contentType);
|
|
} catch (Exception e) {
|
|
PlayerTimeMod.LOGGER.error("Failed to serve resource", e);
|
|
sendResponse(exchange, 500, "Internal Server Error");
|
|
}
|
|
});
|
|
|
|
server.setExecutor(executor);
|
|
}
|
|
|
|
private void sendResponse(HttpExchange exchange, int code, String response) throws IOException {
|
|
sendResponse(exchange, code, response.getBytes(StandardCharsets.UTF_8), "text/plain");
|
|
}
|
|
|
|
private void sendResponse(HttpExchange exchange, int code, byte[] response, String contentType) throws IOException {
|
|
exchange.getResponseHeaders().set("Content-Type", contentType);
|
|
exchange.sendResponseHeaders(code, response.length);
|
|
try (OutputStream os = exchange.getResponseBody()) {
|
|
os.write(response);
|
|
}
|
|
}
|
|
|
|
public void start() {
|
|
server.start();
|
|
}
|
|
|
|
public void stop() {
|
|
server.stop(0);
|
|
executor.shutdown();
|
|
}
|
|
} |