feat: use clang-format
This commit is contained in:
@@ -5,14 +5,15 @@ package online.mineroo.velocity;
|
||||
* Handles plugin initialization, configuration loading, and provides access to core components.
|
||||
*/
|
||||
import com.google.inject.Inject;
|
||||
import com.velocitypowered.api.command.CommandManager;
|
||||
import com.velocitypowered.api.event.Subscribe;
|
||||
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
|
||||
import com.velocitypowered.api.plugin.Plugin;
|
||||
import com.velocitypowered.api.plugin.annotation.DataDirectory;
|
||||
import com.velocitypowered.api.proxy.ProxyServer;
|
||||
import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
|
||||
|
||||
import online.mineroo.common.MessageManager;
|
||||
import online.mineroo.common.ProtocolConstants;
|
||||
import online.mineroo.velocity.listeners.BindListener;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -27,7 +28,7 @@ import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
|
||||
|
||||
@Plugin(id = "mineroo-velocity", name = "Mineroo Velocity", version = "0.1.0-SNAPSHOT", url = "https://mineroo.online", description = "Mineroo main plugin", authors = {
|
||||
"YuKun Liu" })
|
||||
public class MinerooCore {
|
||||
public class MinerooVelocity {
|
||||
|
||||
// Reference to the Velocity ProxyServer instance
|
||||
private final ProxyServer server;
|
||||
@@ -53,7 +54,7 @@ public class MinerooCore {
|
||||
* @param dataDirectory Directory for plugin data
|
||||
*/
|
||||
@Inject
|
||||
public MinerooCore(ProxyServer server, Logger logger, @DataDirectory Path dataDirectory) {
|
||||
public MinerooVelocity(ProxyServer server, Logger logger, @DataDirectory Path dataDirectory) {
|
||||
this.server = server;
|
||||
this.logger = logger;
|
||||
this.dataDirectory = dataDirectory;
|
||||
@@ -61,16 +62,19 @@ public class MinerooCore {
|
||||
|
||||
@Subscribe
|
||||
public void onProxyInitialization(ProxyInitializeEvent event) {
|
||||
|
||||
// Register event listeners
|
||||
this.bindListener = new BindListener();
|
||||
server.getEventManager().register(this, bindListener);
|
||||
|
||||
// Register ChannelListener to handle cross-platform MOTD token messages
|
||||
server.getEventManager().register(this, new online.mineroo.velocity.listeners.ChannelListener(this));
|
||||
|
||||
// Load configuration
|
||||
reloadConfig();
|
||||
|
||||
server.getChannelRegistrar().register(MinecraftChannelIdentifier.from(ProtocolConstants.PROTOCOL_CHANNEL));
|
||||
|
||||
// Register ChannelListener to handle cross-platform MOTD token messages
|
||||
server.getEventManager().register(this, new online.mineroo.velocity.listeners.ChannelListener(this));
|
||||
|
||||
// Initialize message manager
|
||||
this.messageManager = new MessageManager();
|
||||
}
|
||||
@@ -1,200 +0,0 @@
|
||||
// package online.mineroo.velocity.commands;
|
||||
//
|
||||
// import java.util.List;
|
||||
// import java.util.Optional;
|
||||
// import java.util.concurrent.CompletionException;
|
||||
// import java.util.stream.Collectors;
|
||||
// import java.util.stream.Stream;
|
||||
//
|
||||
// import org.slf4j.Logger;
|
||||
//
|
||||
// import com.velocitypowered.api.command.CommandSource;
|
||||
// import com.velocitypowered.api.command.SimpleCommand;
|
||||
//
|
||||
// import net.kyori.adventure.text.Component;
|
||||
// import net.kyori.adventure.text.format.NamedTextColor;
|
||||
// import online.mineroo.common.MessageManager;
|
||||
// import online.mineroo.common.NetworkServiceInterface;
|
||||
// import online.mineroo.velocity.Config;
|
||||
// import online.mineroo.velocity.MinerooCore;
|
||||
// import online.mineroo.common.BindRequest;
|
||||
// import online.mineroo.common.HttpNetworkService;
|
||||
//
|
||||
// public class MainCommand implements SimpleCommand {
|
||||
//
|
||||
// private final MinerooCore plugin;
|
||||
//
|
||||
// public MainCommand(MinerooCore plugin) {
|
||||
// this.plugin = plugin;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void execute(Invocation invocation) {
|
||||
// String[] args = invocation.arguments();
|
||||
// if (args.length < 1) {
|
||||
// sendHelp(invocation.source());
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// String subCommand = args[0];
|
||||
//
|
||||
// if (subCommand.equals("bind")) {
|
||||
// bindServer(invocation.source());
|
||||
// }
|
||||
//
|
||||
// if (subCommand.equalsIgnoreCase("reload")) {
|
||||
// reload(invocation.source());
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public List<String> suggest(Invocation invocation) {
|
||||
// String[] args = invocation.arguments();
|
||||
//
|
||||
// if (args.length == 0) {
|
||||
// return List.of("bind", "reload");
|
||||
// }
|
||||
//
|
||||
// if (args.length == 1) {
|
||||
// String input = args[0].toLowerCase();
|
||||
// return Stream.of("bind", "reload")
|
||||
// .filter(cmd -> cmd.startsWith(input))
|
||||
// .collect(Collectors.toList());
|
||||
// }
|
||||
//
|
||||
// return List.of();
|
||||
// }
|
||||
//
|
||||
// public void reload(CommandSource source) {
|
||||
// MessageManager msg = plugin.getMessageManager();
|
||||
//
|
||||
// long start = System.currentTimeMillis();
|
||||
// boolean success = plugin.reloadConfig();
|
||||
//
|
||||
// if (success) {
|
||||
// long time = System.currentTimeMillis() - start;
|
||||
// source.sendMessage(msg.get("command.reload.success", "time",
|
||||
// String.valueOf(time)));
|
||||
// } else {
|
||||
//
|
||||
// source.sendMessage(msg.get("command.reload.failed"));
|
||||
// }
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// public void bindServer(CommandSource source) {
|
||||
//
|
||||
// Config config = plugin.getConfig();
|
||||
// MessageManager msg = plugin.getMessageManager();
|
||||
//
|
||||
// String bind_name = config.getServerName();
|
||||
// String bind_description = config.getDescription();
|
||||
//
|
||||
// String bind_token = config.getBind().getBindToken();
|
||||
// String bind_address = config.getBind().getAddress();
|
||||
//
|
||||
// int bind_port =
|
||||
// Optional.ofNullable(config.getBind().getPort()).orElse(25565);
|
||||
//
|
||||
// source.sendMessage(msg.get("command.bind.server.start"));
|
||||
//
|
||||
// Logger logger = plugin.getLogger();
|
||||
//
|
||||
// // Run in a separate worker thread to allow blocking (Thread.sleep)
|
||||
// plugin.getServer().getScheduler().buildTask(plugin, () -> {
|
||||
//
|
||||
// // 1. Initialize the Network Service locally (Velocity connects directly)
|
||||
// NetworkServiceInterface networkService = new HttpNetworkService(
|
||||
// "https://oapi.mineroo.online",
|
||||
// "mserver",
|
||||
// bind_token);
|
||||
//
|
||||
// BindRequest request = new BindRequest(logger, networkService);
|
||||
//
|
||||
// try {
|
||||
//
|
||||
// // 2. Check Status
|
||||
// // We use .join() to block the thread until the Future completes.
|
||||
// if (request.checkBindStatus(bind_address, bind_port).join()) {
|
||||
// source.sendMessage(msg.get("command.bind.server.already-bound"));
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // 3. Initial Verification
|
||||
// boolean inital_bind = request.initialMotdVerifyRequest(bind_address,
|
||||
// bind_port).join();
|
||||
//
|
||||
// if (inital_bind) {
|
||||
// String motdToken = request.getMotdToken();
|
||||
// plugin.getBindListener().setVerificationToken(motdToken);
|
||||
//
|
||||
// source.sendMessage(msg.get("command.bind.server.wait"));
|
||||
//
|
||||
// // 4. Wait for external refresh (Blocking this worker thread is intended)
|
||||
// try {
|
||||
// Thread.sleep(2 * 60 * 1000 + 5000); // 2m 5s
|
||||
// } catch (InterruptedException e) {
|
||||
// logger.error("Bind thread interrupted", e);
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // 5. Final Bind & Retry Loop
|
||||
// boolean success = false;
|
||||
// int maxRetries = 3;
|
||||
//
|
||||
// for (int i = 1; i <= maxRetries; i++) {
|
||||
// // Check final status synchronously using join()
|
||||
// if (request.finalizeServerBinding(bind_name, bind_description).join()) {
|
||||
// success = true;
|
||||
// break;
|
||||
// }
|
||||
//
|
||||
// if (i < maxRetries) {
|
||||
// source.sendMessage(msg.get("command.bind.server.retry",
|
||||
// "current", String.valueOf(i),
|
||||
// "max", String.valueOf(maxRetries)));
|
||||
//
|
||||
// try {
|
||||
// Thread.sleep(10000); // Wait 10s before retry
|
||||
// } catch (InterruptedException e) {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (success) {
|
||||
// source.sendMessage(msg.get("command.bind.server.success"));
|
||||
// } else {
|
||||
// source.sendMessage(msg.get("command.bind.server.failed"));
|
||||
// }
|
||||
//
|
||||
// } else {
|
||||
// source.sendMessage(
|
||||
// Component.text("Initial handshake failed. Check your token or network.",
|
||||
// NamedTextColor.RED));
|
||||
// }
|
||||
//
|
||||
// } catch (CompletionException e) {
|
||||
// // Unpack the wrapper exception from join() to see the real network error
|
||||
// logger.error("Mineroo Bind Network Error: " + e.getCause().getMessage());
|
||||
// } catch (Exception e) {
|
||||
// logger.error("Mineroo Bind Error: " + e.toString());
|
||||
// } finally {
|
||||
// plugin.getBindListener().clearVerificationToken();
|
||||
// }
|
||||
//
|
||||
// }).schedule();
|
||||
// }
|
||||
//
|
||||
// public void sendHelp(CommandSource source) {
|
||||
// source.sendMessage(Component.text("=== # @Mineroo # ===",
|
||||
// NamedTextColor.AQUA));
|
||||
// source.sendMessage(Component.text(" /mineroo bind - Start to bind server",
|
||||
// NamedTextColor.YELLOW));
|
||||
// source.sendMessage(Component.text(" /mineroo reload - Reload config",
|
||||
// NamedTextColor.YELLOW));
|
||||
// source.sendMessage(Component.text("=== mineroo.online ===",
|
||||
// NamedTextColor.AQUA));
|
||||
// }
|
||||
// }
|
||||
@@ -23,7 +23,7 @@ public class BindListener {
|
||||
public void onPing(ProxyPingEvent event) {
|
||||
String token = verificationToken.get();
|
||||
|
||||
if (token == null) {
|
||||
if (token == null || token.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,36 +1,208 @@
|
||||
package online.mineroo.velocity.listeners;
|
||||
|
||||
import com.google.common.io.ByteArrayDataInput;
|
||||
import com.google.common.io.ByteArrayDataOutput;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import com.velocitypowered.api.event.Subscribe;
|
||||
import com.velocitypowered.api.event.connection.PluginMessageEvent;
|
||||
import com.velocitypowered.api.proxy.ServerConnection;
|
||||
import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
|
||||
import online.mineroo.common.*;
|
||||
import online.mineroo.velocity.MinerooVelocity;
|
||||
|
||||
import online.mineroo.common.ProtocolConstants;
|
||||
|
||||
import online.mineroo.velocity.MinerooCore;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class ChannelListener {
|
||||
private final MinerooCore plugin;
|
||||
|
||||
public ChannelListener(MinerooCore plugin) {
|
||||
private final MinerooVelocity plugin;
|
||||
private final Gson gson = new Gson();
|
||||
|
||||
private final HttpNetworkService httpService;
|
||||
|
||||
public ChannelListener(MinerooVelocity plugin) {
|
||||
this.plugin = plugin;
|
||||
|
||||
String apiUrl = "https://oapi.mineroo.online";
|
||||
|
||||
this.httpService = new HttpNetworkService(apiUrl, "mserver", plugin.getConfig().getBind().getBindToken());
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onPluginMessage(PluginMessageEvent event) {
|
||||
// Only handle messages from the specified protocol channel
|
||||
if (!event.getIdentifier().getId().equals(ProtocolConstants.PROTOCOL_CHANNEL))
|
||||
return;
|
||||
|
||||
// Only handle messages from a backend server
|
||||
if (!(event.getSource() instanceof ServerConnection))
|
||||
return;
|
||||
|
||||
ServerConnection backendServer = (ServerConnection) event.getSource();
|
||||
ByteArrayDataInput in = event.dataAsDataStream();
|
||||
String subChannel = in.readUTF();
|
||||
|
||||
if (subChannel.equals(ProtocolConstants.BIND_MOTD_TOKEN)) {
|
||||
String token = in.readUTF();
|
||||
plugin.getBindListener().setVerificationToken(token);
|
||||
try {
|
||||
String subChannel = in.readUTF();
|
||||
|
||||
if (subChannel.equals(ProtocolConstants.API_REQUEST)) {
|
||||
handleApiRequest(in, backendServer);
|
||||
}
|
||||
|
||||
if (subChannel.equals(ProtocolConstants.BIND_MOTD_TOKEN)) {
|
||||
String token = in.readUTF();
|
||||
plugin.getBindListener().setVerificationToken(token);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().error("Failed to handle plugin message", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleApiRequest(ByteArrayDataInput in, ServerConnection backendServer) {
|
||||
String reqId = "unknown";
|
||||
try {
|
||||
// 1. Parse the request
|
||||
String jsonPayload = in.readUTF();
|
||||
ProxyNetworkRequest req = gson.fromJson(jsonPayload, ProxyNetworkRequest.class);
|
||||
reqId = req.getRequestId();
|
||||
|
||||
CompletableFuture<NetworkResponse> future;
|
||||
|
||||
// 2. Delegate to HttpNetworkService for processing
|
||||
if ("POST".equalsIgnoreCase(req.getMethod())) {
|
||||
JsonObject bodyJson = null;
|
||||
try {
|
||||
JsonObject originalJson = gson.fromJson(req.getJsonBody(), JsonObject.class);
|
||||
if (originalJson == null)
|
||||
originalJson = new JsonObject();
|
||||
|
||||
bodyJson = resolvePlacehodersInJson(originalJson).getAsJsonObject();
|
||||
|
||||
plugin.getLogger().info("Proxy POST [ " + req.getEndpoint() + " ]\n\t" + bodyJson.toString());
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().error("JSON parsing error", e);
|
||||
bodyJson = new JsonObject();
|
||||
}
|
||||
|
||||
future = httpService.postData(req.getEndpoint(), bodyJson);
|
||||
} else {
|
||||
|
||||
// replace placeholders
|
||||
java.util.Map<String, String> finalParams = new java.util.HashMap<>();
|
||||
|
||||
if (req.getParams() != null) {
|
||||
for (java.util.Map.Entry<String, String> entry : req.getParams().entrySet()) {
|
||||
String originalKey = entry.getKey();
|
||||
String originalValue = entry.getValue();
|
||||
|
||||
String replacedValue = resolvePlaceholders(originalValue);
|
||||
|
||||
finalParams.put(originalKey, replacedValue);
|
||||
}
|
||||
}
|
||||
|
||||
plugin.getLogger().info("Proxy GET [ " + req.getEndpoint() + " ]\n\t" + finalParams.toString());
|
||||
|
||||
future = httpService.getData(req.getEndpoint(), finalParams);
|
||||
}
|
||||
|
||||
// 3. Handle the result and send back the response
|
||||
String finalReqId = reqId;
|
||||
future.thenAccept(response -> {
|
||||
// Check if HTTP status code is 2xx
|
||||
boolean success = response.getStatusCode() >= 200 && response.getStatusCode() < 300;
|
||||
sendResponse(backendServer, finalReqId, success, response.getBody());
|
||||
}).exceptionally(e -> {
|
||||
plugin.getLogger().error("API Proxy Request Failed", e);
|
||||
sendResponse(backendServer, finalReqId, false, "Proxy Error: " + e.getMessage());
|
||||
return null;
|
||||
});
|
||||
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().error("Error parsing API request", e);
|
||||
sendResponse(backendServer, reqId, false, "Protocol Error");
|
||||
}
|
||||
}
|
||||
|
||||
private void sendResponse(ServerConnection server, String reqId, boolean success, String data) {
|
||||
ByteArrayDataOutput out = ByteStreams.newDataOutput();
|
||||
out.writeUTF(ProtocolConstants.API_RESPONSE);
|
||||
out.writeUTF(reqId);
|
||||
out.writeBoolean(success);
|
||||
out.writeUTF(data != null ? data : "");
|
||||
server.sendPluginMessage(MinecraftChannelIdentifier.from(ProtocolConstants.PROTOCOL_CHANNEL), out.toByteArray());
|
||||
}
|
||||
|
||||
private JsonElement resolvePlacehodersInJson(JsonElement element) {
|
||||
if (element.isJsonPrimitive()) {
|
||||
JsonPrimitive primitive = element.getAsJsonPrimitive();
|
||||
if (primitive.isString()) {
|
||||
String original = primitive.getAsString();
|
||||
|
||||
if ("$port".equals(original)) {
|
||||
Integer port = null;
|
||||
if (plugin.getConfig().getBind() != null) {
|
||||
port = plugin.getConfig().getBind().getPort();
|
||||
}
|
||||
|
||||
if (port == null || port <= 0) {
|
||||
return null;
|
||||
}
|
||||
return new JsonPrimitive(port);
|
||||
}
|
||||
|
||||
if ("$timestamp".equals(original)) {
|
||||
return new JsonPrimitive(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
String replaced = resolvePlaceholders(original);
|
||||
return new JsonPrimitive(replaced);
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
if (element.isJsonObject()) {
|
||||
JsonObject obj = element.getAsJsonObject();
|
||||
JsonObject newObj = new JsonObject();
|
||||
for (java.util.Map.Entry<String, JsonElement> entry : obj.entrySet()) {
|
||||
JsonElement processedValue = resolvePlacehodersInJson(entry.getValue());
|
||||
|
||||
if (processedValue != null) {
|
||||
newObj.add(entry.getKey(), processedValue);
|
||||
}
|
||||
}
|
||||
return newObj;
|
||||
}
|
||||
|
||||
if (element.isJsonArray()) {
|
||||
JsonArray array = element.getAsJsonArray();
|
||||
JsonArray newArray = new JsonArray();
|
||||
for (JsonElement item : array) {
|
||||
JsonElement processedItem = resolvePlacehodersInJson(item);
|
||||
|
||||
if (processedItem != null) {
|
||||
newArray.add(processedItem);
|
||||
}
|
||||
}
|
||||
return newArray;
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
private String resolvePlaceholders(String input) {
|
||||
if (input == null)
|
||||
return null;
|
||||
|
||||
String hostname = plugin.getConfig().getBind().getAddress();
|
||||
String port = String.valueOf(plugin.getConfig().getBind().getPort());
|
||||
|
||||
return input
|
||||
.replace("$hostname", hostname != null ? hostname : "unknown")
|
||||
.replace("$port", port)
|
||||
.replace("$timestamp", String.valueOf(System.currentTimeMillis()));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user