Skip to content

Commit 51f6af9

Browse files
committed
refactor: improve HttpService robustness and add localhost detection
- Add UrlUtils.isLocalhost() supporting IPv6 localhost variants - Skip starting mod HTTP server when endpoint is localhost - Add MetricsHandler for /api/metrics endpoint - Add reinitialize() for dynamic endpoint changes - Remove shutdownNow() calls to avoid forced thread termination - Add endpoint change callback support in ConfigAccess - Improve getNetworkUrl() to handle trailing slash correctly
1 parent 9465a31 commit 51f6af9

4 files changed

Lines changed: 108 additions & 6 deletions

File tree

src/main/java/org/damon233/performtrackermod/PerformTracker.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,22 @@ public void onInitialize() {
6565
} else {
6666
// Network was disabled - stop server and clear HttpService
6767
if (httpService != null) {
68+
httpService.stop();
6869
httpService.stopServer();
6970
httpService = null;
7071
LOGGER.info("HttpService unloaded due to network being disabled.");
7172
}
7273
}
7374
});
7475

76+
// Register callback for network endpoint changes
77+
ConfigAccess.setOnNetworkEndpointChanged(() -> {
78+
if (httpService != null && ConfigAccess.isNetworkEnabled()) {
79+
httpService.reinitialize(ConfigAccess.getNetworkUrl());
80+
LOGGER.info("HttpService reinitialized with new endpoint: {}", ConfigAccess.getNetworkUrl());
81+
}
82+
});
83+
7584
ServerLifecycleEvents.SERVER_STOPPING.register(server -> {
7685
if (httpService != null) {
7786
httpService.stopServer();

src/main/java/org/damon233/performtrackermod/config/ConfigAccess.java

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,11 @@ public static String getNetworkEndpoint() {
147147
}
148148

149149
public static String getNetworkUrl() {
150-
return getNetworkEndpoint() + API_PATH;
150+
String endpoint = getNetworkEndpoint();
151+
if (endpoint.endsWith("/")) {
152+
return endpoint + API_PATH.substring(1);
153+
}
154+
return endpoint + API_PATH;
151155
}
152156

153157
public static int getLocalServerPort() {
@@ -245,30 +249,45 @@ public static void setNetworkEnabled(boolean enabled) {
245249
if (configData != null) {
246250
configData.networkEnabled = enabled;
247251
save();
248-
notifyNetworkEnabledChanged(enabled);
252+
notifyNetworkEnabledChanged();
249253
}
250254
}
251255

252256
public static void setNetworkEndpoint(String endpoint) {
253257
if (configData != null) {
254258
String validated = validateNetworkEndpoint(endpoint);
259+
String oldEndpoint = configData.networkEndpoint;
255260
configData.networkEndpoint = validated != null ? validated : DEFAULT_NETWORK_ENDPOINT;
256261
save();
262+
if (configData.networkEnabled && !configData.networkEndpoint.equals(oldEndpoint)) {
263+
notifyNetworkEndpointChanged();
264+
}
257265
}
258266
}
259267

260268
private static Runnable networkEnabledCallback;
269+
private static Runnable networkEndpointCallback;
261270

262271
public static void setOnNetworkEnabledChanged(Runnable callback) {
263272
networkEnabledCallback = callback;
264273
}
274+
275+
public static void setOnNetworkEndpointChanged(Runnable callback) {
276+
networkEndpointCallback = callback;
277+
}
265278

266-
private static void notifyNetworkEnabledChanged(boolean enabled) {
279+
private static void notifyNetworkEnabledChanged() {
267280
if (networkEnabledCallback != null) {
268281
networkEnabledCallback.run();
269282
}
270283
}
271284

285+
private static void notifyNetworkEndpointChanged() {
286+
if (networkEndpointCallback != null) {
287+
networkEndpointCallback.run();
288+
}
289+
}
290+
272291
public static String validateNetworkEndpoint(String endpoint) {
273292
if (endpoint == null || endpoint.isBlank()) {
274293
return null;

src/main/java/org/damon233/performtrackermod/network/HttpService.java

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@
2222
import org.damon233.performtrackermod.collector.SystemInfoCollector;
2323
import org.damon233.performtrackermod.config.ConfigAccess;
2424
import org.damon233.performtrackermod.data.SystemInfo;
25+
import org.damon233.performtrackermod.utils.UrlUtils;
2526
import org.slf4j.Logger;
2627
import org.slf4j.LoggerFactory;
2728

2829
import java.io.IOException;
30+
import java.io.InputStream;
2931
import java.io.OutputStream;
3032
import java.net.InetSocketAddress;
3133
import java.net.URI;
@@ -85,6 +87,18 @@ public void initialize(String remoteUrl) {
8587
.build();
8688
}
8789

90+
public void reinitialize(String remoteUrl) {
91+
boolean wasRunning = serverRunning.get();
92+
if (wasRunning) {
93+
stopServer();
94+
}
95+
stopSender();
96+
initialize(remoteUrl);
97+
if (wasRunning) {
98+
tryStartServer();
99+
}
100+
}
101+
88102
public synchronized void start() {
89103
startSender();
90104
}
@@ -97,12 +111,19 @@ public synchronized boolean tryStartServer() {
97111
}
98112

99113
private boolean startServerInternal() {
114+
String bindHost = ConfigAccess.getLocalServerHost();
115+
116+
if (UrlUtils.isLocalhost(bindHost)) {
117+
LOGGER.info("HttpService server not started: endpoint is localhost, assuming external server handles requests");
118+
return false;
119+
}
120+
100121
try {
101-
String bindHost = ConfigAccess.getLocalServerHost();
102122
server = HttpServer.create(new InetSocketAddress(bindHost, localPort), 0);
103123
server.setExecutor(serverExecutor);
104124

105125
server.createContext("/api/deviceinfo", new DeviceInfoHandler());
126+
server.createContext("/api/metrics", new MetricsHandler());
106127

107128
server.start();
108129
serverRunning.set(true);
@@ -128,7 +149,7 @@ public synchronized void stop() {
128149
public synchronized void stopServer() {
129150
if (server != null && serverRunning.compareAndSet(true, false)) {
130151
server.stop(0);
131-
serverExecutor.shutdownNow();
152+
server = null;
132153
LOGGER.info("HttpService server stopped");
133154
}
134155
}
@@ -140,7 +161,6 @@ private void stopSender() {
140161
sendQueue.poll();
141162
dropped++;
142163
}
143-
senderExecutor.shutdownNow();
144164
LOGGER.info("HttpService sender stopped, {} items dropped", dropped);
145165
}
146166
}
@@ -238,4 +258,41 @@ private void sendResponse(HttpExchange exchange, int statusCode, String body) {
238258
}
239259
}
240260
}
261+
262+
private static class MetricsHandler implements HttpHandler {
263+
@Override
264+
public void handle(HttpExchange exchange) {
265+
if (!"POST".equalsIgnoreCase(exchange.getRequestMethod())) {
266+
sendResponse(exchange, 405, "{\"error\":\"Method not allowed\"}");
267+
return;
268+
}
269+
270+
try {
271+
int contentLength = Integer.parseInt(exchange.getRequestHeaders().getFirst("Content-Length"));
272+
if (contentLength > 0) {
273+
try (InputStream is = exchange.getRequestBody()) {
274+
byte[] body = is.readAllBytes();
275+
LOGGER.debug("Received metrics payload: {} bytes", body.length);
276+
}
277+
}
278+
} catch (Exception e) {
279+
LOGGER.debug("Failed to read metrics payload: {}", e.getMessage());
280+
}
281+
282+
sendResponse(exchange, 200, "{\"status\":\"ok\"}");
283+
}
284+
285+
private void sendResponse(HttpExchange exchange, int statusCode, String body) {
286+
try {
287+
exchange.getResponseHeaders().set("Content-Type", "application/json");
288+
byte[] bytes = body.getBytes(StandardCharsets.UTF_8);
289+
exchange.sendResponseHeaders(statusCode, bytes.length);
290+
try (OutputStream os = exchange.getResponseBody()) {
291+
os.write(bytes);
292+
}
293+
} catch (IOException e) {
294+
LOGGER.debug("Failed to send response: {}", e.getMessage());
295+
}
296+
}
297+
}
241298
}

src/main/java/org/damon233/performtrackermod/utils/UrlUtils.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
import java.net.URI;
2020

2121
public class UrlUtils {
22+
private static final String[] LOCALHOST_HOSTS = {
23+
"localhost", "127.0.0.1", "::1", "0:0:0:0:0:0:0:1"
24+
};
25+
2226
public static int parsePort(String url) {
2327
try {
2428
URI uri = URI.create(url);
@@ -42,4 +46,17 @@ public static String parseHost(String url) {
4246
}
4347
return "localhost";
4448
}
49+
50+
public static boolean isLocalhost(String host) {
51+
if (host == null) {
52+
return true;
53+
}
54+
String lowerHost = host.toLowerCase();
55+
for (String localhost : LOCALHOST_HOSTS) {
56+
if (localhost.equals(lowerHost)) {
57+
return true;
58+
}
59+
}
60+
return false;
61+
}
4562
}

0 commit comments

Comments
 (0)