feat: code
This commit is contained in:
@@ -11,6 +11,7 @@ dependencies {
|
||||
|
||||
implementation("net.kyori:adventure-api:4.25.0")
|
||||
implementation("net.kyori:adventure-text-minimessage:4.25.0")
|
||||
implementation("org.slf4j:slf4j-api:2.0.17")
|
||||
}
|
||||
|
||||
java {
|
||||
|
||||
153
common/src/main/java/online/mineroo/common/BindRequest.java
Normal file
153
common/src/main/java/online/mineroo/common/BindRequest.java
Normal file
@@ -0,0 +1,153 @@
|
||||
package online.mineroo.common;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import online.mineroo.common.NetworkServiceInterface;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* BindRequest handles server binding and verification with the Mineroo API.
|
||||
* <p>
|
||||
* This class operates asynchronously and relies on the injected
|
||||
* {@link NetworkService}
|
||||
* to handle the actual HTTP transport and authentication.
|
||||
*/
|
||||
public class BindRequest {
|
||||
|
||||
private final Logger logger;
|
||||
private final NetworkServiceInterface networkService;
|
||||
|
||||
// State cache
|
||||
private String motdToken = "";
|
||||
private String sessionToken = "";
|
||||
|
||||
/**
|
||||
* Constructs a BindRequest instance.
|
||||
*
|
||||
* @param logger Logger for logging errors and information
|
||||
* @param networkService The network service instance (Local or Proxy) that
|
||||
* handles transport and auth
|
||||
*/
|
||||
public BindRequest(Logger logger, NetworkServiceInterface networkService) {
|
||||
this.logger = logger;
|
||||
this.networkService = networkService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the bind status asynchronously.
|
||||
*
|
||||
* @return A future that completes with true if status is 'bound', false
|
||||
* otherwise
|
||||
*/
|
||||
public CompletableFuture<Boolean> checkBindStatus() {
|
||||
// NetworkService is already configured with BaseURL, only need the path here
|
||||
String path = "/server/server-bind-status";
|
||||
|
||||
return networkService.getData(path, null)
|
||||
.thenApply(responseBody -> {
|
||||
try {
|
||||
JsonObject responseData = JsonParser.parseString(responseBody).getAsJsonObject();
|
||||
boolean bound = responseData.has("bound") && responseData.get("bound").getAsBoolean();
|
||||
|
||||
if (!bound) {
|
||||
logger.warn("Mineroo Bind: Server not bound. 'bound' field is false.");
|
||||
}
|
||||
return bound;
|
||||
} catch (Exception e) {
|
||||
logger.error("Mineroo Bind: Failed to parse bind status response", e);
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.exceptionally(e -> {
|
||||
logger.error("Mineroo Bind: Network error while checking status", e);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates a MOTD verification request asynchronously.
|
||||
*
|
||||
* @param hostname The server hostname
|
||||
* @param port The server port
|
||||
* @return A future that completes with true if tokens are received
|
||||
*/
|
||||
public CompletableFuture<Boolean> initialMotdVerifyRequest(String hostname, Integer port) {
|
||||
String path = "/server/motd-verify";
|
||||
|
||||
JsonObject json = new JsonObject();
|
||||
json.addProperty("server_address", hostname);
|
||||
json.addProperty("server_port", port);
|
||||
|
||||
return networkService.postData(path, json)
|
||||
.thenApply(responseBody -> {
|
||||
try {
|
||||
JsonObject responseData = JsonParser.parseString(responseBody).getAsJsonObject();
|
||||
|
||||
if (responseData.has("motd_token")) {
|
||||
this.motdToken = responseData.get("motd_token").getAsString();
|
||||
} else {
|
||||
logger.error("Mineroo Bind: MOTD Token not received.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (responseData.has("session_token")) {
|
||||
this.sessionToken = responseData.get("session_token").getAsString();
|
||||
} else {
|
||||
logger.error("Mineroo Bind: Session Token not received.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Mineroo Bind: Failed to parse MOTD verify response: " + responseBody, e);
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.exceptionally(e -> {
|
||||
logger.error("Mineroo Bind: Network error during MOTD verify", e);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalizes the server binding asynchronously.
|
||||
*
|
||||
* @param name The server name (nullable)
|
||||
* @param description The server description (nullable)
|
||||
* @return A future that completes with true if the binding is successful
|
||||
*/
|
||||
public CompletableFuture<Boolean> finalizeServerBinding(@Nullable String name, @Nullable String description) {
|
||||
String path = "/server/server-bind";
|
||||
|
||||
JsonObject json = new JsonObject();
|
||||
json.addProperty("session_token", this.sessionToken);
|
||||
json.addProperty("name", name);
|
||||
json.addProperty("description", description);
|
||||
|
||||
return networkService.postData(path, json)
|
||||
.thenApply(responseBody -> {
|
||||
// Assume as long as the request returns successfully and no exception is
|
||||
// thrown, it is considered successful (HTTP 200)
|
||||
// If the API returns a specific {"success": false}, you need to parse the JSON
|
||||
// and check here
|
||||
return true;
|
||||
})
|
||||
.exceptionally(e -> {
|
||||
logger.error("Mineroo Bind: Failed to finalize binding", e);
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the MOTD token received from the API.
|
||||
*
|
||||
* @return the motdToken string
|
||||
*/
|
||||
public String getMotdToken() {
|
||||
return motdToken;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package online.mineroo.common;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.util.Base64;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class HttpNetworkService implements NetworkServiceInterface {
|
||||
|
||||
private final HttpClient client;
|
||||
private final String baseUrl;
|
||||
private final String authHeaderValue; // Precomputed Authorization header value
|
||||
|
||||
/**
|
||||
* @param baseUrl Base URL of the API (e.g., "https://oapi.mineroo.online")
|
||||
* @param username Username for Basic Auth (usually "mbind" in your case)
|
||||
* @param password Password for Basic Auth (the token)
|
||||
*/
|
||||
public HttpNetworkService(String baseUrl, String username, String password) {
|
||||
this.baseUrl = baseUrl.endsWith("/") ? baseUrl.substring(0, baseUrl.length() - 1) : baseUrl;
|
||||
|
||||
// It is recommended to configure connectTimeout
|
||||
this.client = HttpClient.newBuilder()
|
||||
.connectTimeout(Duration.ofSeconds(10))
|
||||
.build();
|
||||
|
||||
// Pre-generate Basic Auth string
|
||||
String auth = username + ":" + password;
|
||||
this.authHeaderValue = "Basic " + Base64.getEncoder().encodeToString(auth.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<String> getData(String endpoint, Map<String, String> params) {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
// 1. Build URL and query parameters
|
||||
StringBuilder urlBuilder = new StringBuilder(baseUrl + endpoint);
|
||||
if (params != null && !params.isEmpty()) {
|
||||
urlBuilder.append("?");
|
||||
params.forEach((k, v) -> urlBuilder.append(k).append("=").append(v).append("&"));
|
||||
// Simple trailing '&' removal (usually harmless, but cleaner)
|
||||
urlBuilder.setLength(urlBuilder.length() - 1);
|
||||
}
|
||||
|
||||
// 2. Build the request
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(urlBuilder.toString()))
|
||||
.header("Authorization", authHeaderValue) // Inject Auth
|
||||
.header("User-Agent", "Mineroo-Plugin/1.0") // Recommended to add User-Agent
|
||||
.GET()
|
||||
.build();
|
||||
|
||||
// 3. Send the request
|
||||
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
|
||||
// You can do a simple status code check here, or leave it to the upper layer
|
||||
// To keep the interface pure, we just return the body
|
||||
return response.body();
|
||||
|
||||
} catch (Exception e) {
|
||||
// Wrap checked exceptions as runtime exceptions, Future will catch them
|
||||
throw new RuntimeException("HTTP GET failed: " + endpoint, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<String> postData(String endpoint, JsonObject body) {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
HttpRequest request = HttpRequest.newBuilder()
|
||||
.uri(URI.create(baseUrl + endpoint))
|
||||
.header("Authorization", authHeaderValue) // Inject Auth
|
||||
.header("Content-Type", "application/json")
|
||||
.header("User-Agent", "Mineroo-Plugin/1.0")
|
||||
.POST(HttpRequest.BodyPublishers.ofString(body.toString(), StandardCharsets.UTF_8))
|
||||
.build();
|
||||
|
||||
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
|
||||
return response.body();
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("HTTP POST failed: " + endpoint, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package online.mineroo.common;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
public interface NetworkServiceInterface {
|
||||
CompletableFuture<String> getData(String endpoint, Map<String, String> params);
|
||||
|
||||
CompletableFuture<String> postData(String endpoint, JsonObject body);
|
||||
}
|
||||
Reference in New Issue
Block a user