Add notification server and file download service implementation
- Introduce `NotificationServer` for handling HTTP notifications. - Register `ProxyShutdownEvent` to stop the notification server on shutdown. - Add `FileDownloadService` for asynchronous file downloads using the configured endpoint. - Update `Config` to include `download-endpoint`. - Add Javalin and SLF4J dependencies for the HTTP server.
This commit is contained in:
parent
df8f08544b
commit
d4359bf480
|
|
@ -18,6 +18,8 @@ dependencies {
|
|||
compileOnly("com.gitlab.ruany:LiteBansAPI:0.6.1")
|
||||
compileOnly("org.projectlombok:lombok:1.18.30")
|
||||
annotationProcessor("org.projectlombok:lombok:1.18.30")
|
||||
implementation("io.javalin:javalin:6.6.0") // Javalin for HTTP server
|
||||
implementation("org.slf4j:slf4j-api:2.0.9") // Required by Javalin
|
||||
}
|
||||
|
||||
tasks.test {
|
||||
|
|
|
|||
|
|
@ -3,10 +3,12 @@ package com.alttd.webinterface;
|
|||
import com.alttd.webinterface.commands.Login;
|
||||
import com.alttd.webinterface.commands.Reload;
|
||||
import com.alttd.webinterface.config.Config;
|
||||
import com.alttd.webinterface.http.NotificationServer;
|
||||
import com.alttd.webinterface.listeners.ProxyPlayerListener;
|
||||
import com.google.inject.Inject;
|
||||
import com.velocitypowered.api.event.Subscribe;
|
||||
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
|
||||
import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
|
||||
import com.velocitypowered.api.plugin.Plugin;
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
|
@ -18,6 +20,8 @@ import lombok.extern.slf4j.Slf4j;
|
|||
)
|
||||
public class WebInterface {
|
||||
private final ProxyServer server;
|
||||
private NotificationServer notificationServer;
|
||||
private static final int HTTP_PORT = 8080; // Default port, could be made configurable
|
||||
|
||||
@Inject
|
||||
public WebInterface(ProxyServer proxyServer) {
|
||||
|
|
@ -29,11 +33,36 @@ public class WebInterface {
|
|||
reloadConfig();
|
||||
server.getEventManager().register(this, new ProxyPlayerListener());
|
||||
loadCommands();
|
||||
startNotificationServer();
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onProxyShutdown(ProxyShutdownEvent event) {
|
||||
stopNotificationServer();
|
||||
}
|
||||
|
||||
private void startNotificationServer() {
|
||||
notificationServer = new NotificationServer(HTTP_PORT);
|
||||
notificationServer.startServer();
|
||||
log.info("Started notification server on port {}", HTTP_PORT);
|
||||
}
|
||||
|
||||
private void stopNotificationServer() {
|
||||
if (notificationServer != null) {
|
||||
notificationServer.stopServer();
|
||||
log.info("Stopped notification server");
|
||||
}
|
||||
}
|
||||
|
||||
public void reloadConfig() {
|
||||
Config.init();
|
||||
log.info("Reloaded WebInterface config.");
|
||||
|
||||
// Restart the notification server to apply any configuration changes
|
||||
if (notificationServer != null) {
|
||||
stopNotificationServer();
|
||||
}
|
||||
startNotificationServer();
|
||||
}
|
||||
|
||||
public void loadCommands() {// all (proxy)commands go here
|
||||
|
|
|
|||
|
|
@ -201,6 +201,7 @@ public final class Config {
|
|||
|
||||
public static String LOGIN_CODE_ENDPOINT = "https://alttd.com/login/requestNewUserLogin/<uuid>";
|
||||
public static String LOGIN_ENDPOINT = "https://alttd.com/login";
|
||||
public static String DOWNLOAD_ENDPOINT = "https://alttd.com/particles/download";
|
||||
public static String SECRET = "";
|
||||
private static void site() {
|
||||
if (SECRET.isEmpty()) {
|
||||
|
|
@ -210,6 +211,7 @@ public final class Config {
|
|||
}
|
||||
SECRET = getString("secret", SECRET);
|
||||
LOGIN_ENDPOINT = getString("login-endpoint", LOGIN_ENDPOINT);
|
||||
DOWNLOAD_ENDPOINT = getString("download-endpoint", DOWNLOAD_ENDPOINT);
|
||||
LOGIN_CODE_ENDPOINT = getString("login-code-endpoint", LOGIN_CODE_ENDPOINT);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,83 @@
|
|||
package com.alttd.webinterface.http;
|
||||
|
||||
import com.alttd.webinterface.web_interact.FileDownloadService;
|
||||
import io.javalin.Javalin;
|
||||
import io.javalin.http.Context;
|
||||
import io.javalin.http.HttpStatus;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
/**
|
||||
* HTTP server that exposes the /notify/<file>.json endpoint.
|
||||
*/
|
||||
@Slf4j
|
||||
public class NotificationServer {
|
||||
private final int port;
|
||||
private Javalin app;
|
||||
|
||||
/**
|
||||
* Creates a new NotificationServer that listens on the specified port.
|
||||
*
|
||||
* @param port The port to listen on
|
||||
*/
|
||||
public NotificationServer(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the server.
|
||||
*/
|
||||
public void startServer() {
|
||||
try {
|
||||
app = Javalin.create(config -> {
|
||||
config.showJavalinBanner = false;
|
||||
}).start(port);
|
||||
|
||||
app.get("/notify/{file}.json", this::handleNotifyRequest);
|
||||
|
||||
log.info("NotificationServer started on port {}", port);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to start NotificationServer", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the server.
|
||||
*/
|
||||
public void stopServer() {
|
||||
if (app != null) {
|
||||
app.stop();
|
||||
log.info("NotificationServer stopped");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles requests to the /notify/<file>.json endpoint.
|
||||
*/
|
||||
private void handleNotifyRequest(Context ctx) {
|
||||
String uri = ctx.path();
|
||||
log.info("Received request: {} {}", ctx.method(), uri);
|
||||
|
||||
String fileName = ctx.pathParam("file") + ".json";
|
||||
log.info("Requested file: {}", fileName);
|
||||
|
||||
FileDownloadService.downloadFileAsync(fileName).thenAccept(fileData -> {
|
||||
if (fileData.isPresent()) {
|
||||
ctx.contentType("application/json");
|
||||
ctx.result(fileData.get());
|
||||
} else {
|
||||
ctx.status(HttpStatus.NOT_FOUND);
|
||||
ctx.contentType("text/plain");
|
||||
ctx.result("File not found or download failed");
|
||||
}
|
||||
}).exceptionally(e -> {
|
||||
log.error("Error downloading file: {}", fileName, e);
|
||||
ctx.status(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
ctx.contentType("text/plain");
|
||||
ctx.result("Failed to handle download");
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
package com.alttd.webinterface.web_interact;
|
||||
|
||||
import com.alttd.webinterface.config.Config;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* Service for downloading files from the configured download endpoint.
|
||||
*/
|
||||
@Slf4j
|
||||
public class FileDownloadService {
|
||||
|
||||
/**
|
||||
* Asynchronously downloads a file from the configured download endpoint.
|
||||
*
|
||||
* @param fileName The name of the file to download
|
||||
* @return A CompletableFuture containing an Optional with the file content if successful,
|
||||
* or an empty Optional otherwise
|
||||
*/
|
||||
public static CompletableFuture<Optional<byte[]>> downloadFileAsync(String fileName) {
|
||||
String downloadUrl = Config.DOWNLOAD_ENDPOINT;
|
||||
if (!downloadUrl.endsWith("/")) {
|
||||
downloadUrl += "/";
|
||||
}
|
||||
downloadUrl += fileName;
|
||||
|
||||
log.debug("Downloading file from {}", downloadUrl);
|
||||
|
||||
HttpClient client = HttpClient.newHttpClient();
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(downloadUrl))
|
||||
.header("Authorization", "SECRET " + Config.SECRET)
|
||||
.GET()
|
||||
.build();
|
||||
|
||||
return client.sendAsync(request, HttpResponse.BodyHandlers.ofByteArray())
|
||||
.thenApply(response -> {
|
||||
if (response.statusCode() == HttpServletResponse.SC_OK) {
|
||||
log.debug("Successfully downloaded file: {}", fileName);
|
||||
return Optional.of(response.body());
|
||||
} else {
|
||||
log.error("Failed to download file: {}. Status code: {}", fileName, response.statusCode());
|
||||
return Optional.<byte[]>empty();
|
||||
}
|
||||
})
|
||||
.exceptionally(e -> {
|
||||
log.error("Exception occurred while downloading file: {}", fileName, e);
|
||||
return Optional.empty();
|
||||
});
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user