Mirror von
https://github.com/PaperMC/Velocity.git
synchronisiert 2024-11-17 05:20:14 +01:00
Switch from AsyncHttpClient to JDK HttpClient
AsyncHttpClient is not well-maintained and is unlikely to survive the Netty 5 migration. Switch to the JDK's built-in HttpClient which has a much better chance of being maintained.
Dieser Commit ist enthalten in:
Ursprung
42acf84dda
Commit
e18cef9cc4
@ -69,8 +69,6 @@ dependencies {
|
||||
implementation(platform("net.kyori:adventure-bom:${adventureVersion}"))
|
||||
implementation("net.kyori:adventure-nbt")
|
||||
|
||||
implementation 'org.asynchttpclient:async-http-client:2.12.3'
|
||||
|
||||
implementation 'com.spotify:completable-futures:0.3.5'
|
||||
|
||||
implementation 'com.electronwill.night-config:toml:3.6.4'
|
||||
|
@ -68,6 +68,7 @@ import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.http.HttpClient;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
@ -100,7 +101,6 @@ import net.kyori.adventure.translation.TranslationRegistry;
|
||||
import net.kyori.adventure.util.UTF8ResourceBundleControl;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.asynchttpclient.AsyncHttpClient;
|
||||
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
@ -546,7 +546,7 @@ public class VelocityServer implements ProxyServer, ForwardingAudience {
|
||||
shutdown(true);
|
||||
}
|
||||
|
||||
public AsyncHttpClient getAsyncHttpClient() {
|
||||
public HttpClient getAsyncHttpClient() {
|
||||
return cm.getHttpClient();
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,6 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
@ -37,15 +36,17 @@ import com.velocitypowered.api.util.ProxyVersion;
|
||||
import com.velocitypowered.proxy.VelocityServer;
|
||||
import com.velocitypowered.proxy.util.InformationUtils;
|
||||
|
||||
import java.net.ConnectException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpRequest.BodyPublishers;
|
||||
import java.net.http.HttpResponse.BodyHandlers;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import net.kyori.adventure.identity.Identity;
|
||||
@ -59,10 +60,6 @@ import net.kyori.adventure.text.format.TextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.asynchttpclient.AsyncHttpClient;
|
||||
import org.asynchttpclient.BoundRequestBuilder;
|
||||
import org.asynchttpclient.ListenableFuture;
|
||||
import org.asynchttpclient.Response;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
public class VelocityCommand implements SimpleCommand {
|
||||
@ -380,92 +377,72 @@ public class VelocityCommand implements SimpleCommand {
|
||||
dump.add("plugins", InformationUtils.collectPluginInfo(server));
|
||||
|
||||
source.sendMessage(Component.text().content("Uploading gathered information...").build());
|
||||
AsyncHttpClient httpClient = ((VelocityServer) server).getAsyncHttpClient();
|
||||
HttpClient httpClient = ((VelocityServer) server).getAsyncHttpClient();
|
||||
|
||||
BoundRequestBuilder request =
|
||||
httpClient.preparePost("https://dump.velocitypowered.com/documents");
|
||||
request.setHeader("Content-Type", "text/plain");
|
||||
request.addHeader("User-Agent", server.getVersion().getName() + "/"
|
||||
+ server.getVersion().getVersion());
|
||||
request.setBody(
|
||||
InformationUtils.toHumanReadableString(dump).getBytes(StandardCharsets.UTF_8));
|
||||
httpClient.sendAsync(
|
||||
HttpRequest.newBuilder()
|
||||
.uri(URI.create("https://dump.velocitypowered.com/documents"))
|
||||
.POST(BodyPublishers.ofString(
|
||||
InformationUtils.toHumanReadableString(dump), StandardCharsets.UTF_8
|
||||
))
|
||||
.header("Content-Type", "text/plain")
|
||||
.header("User-Agent", server.getVersion().getName() + "/"
|
||||
+ server.getVersion().getVersion())
|
||||
.build(),
|
||||
BodyHandlers.ofString()
|
||||
).thenAccept(response -> {
|
||||
if (response.statusCode() != 200) {
|
||||
source.sendMessage(Component.text()
|
||||
.content("An error occurred while communicating with the Velocity servers. "
|
||||
+ "The servers may be temporarily unavailable or there is an issue "
|
||||
+ "with your network settings. You can find more information in the "
|
||||
+ "log or console of your Velocity server.")
|
||||
.color(NamedTextColor.RED).build());
|
||||
logger.error("Invalid status code while POST-ing Velocity dump: "
|
||||
+ response.statusCode());
|
||||
logger.error("Headers: \n--------------BEGIN HEADERS--------------\n"
|
||||
+ response.headers().toString()
|
||||
+ "\n---------------END HEADERS---------------");
|
||||
return;
|
||||
}
|
||||
|
||||
ListenableFuture<Response> future = request.execute();
|
||||
future.addListener(() -> {
|
||||
try {
|
||||
Response response = future.get();
|
||||
if (response.getStatusCode() != 200) {
|
||||
source.sendMessage(Component.text()
|
||||
.content("An error occurred while communicating with the Velocity servers. "
|
||||
+ "The servers may be temporarily unavailable or there is an issue "
|
||||
+ "with your network settings. You can find more information in the "
|
||||
+ "log or console of your Velocity server.")
|
||||
.color(NamedTextColor.RED).build());
|
||||
logger.error("Invalid status code while POST-ing Velocity dump: "
|
||||
+ response.getStatusCode());
|
||||
logger.error("Headers: \n--------------BEGIN HEADERS--------------\n"
|
||||
+ response.getHeaders().toString()
|
||||
+ "\n---------------END HEADERS---------------");
|
||||
return;
|
||||
}
|
||||
JsonObject key = InformationUtils.parseString(
|
||||
response.getResponseBody(StandardCharsets.UTF_8));
|
||||
JsonObject key = InformationUtils.parseString(response.body());
|
||||
if (!key.has("key")) {
|
||||
throw new JsonSyntaxException("Missing Dump-Url-response");
|
||||
}
|
||||
String url = "https://dump.velocitypowered.com/"
|
||||
+ key.get("key").getAsString() + ".json";
|
||||
+ key.get("key").getAsString() + ".json";
|
||||
source.sendMessage(Component.text()
|
||||
.content("Created an anonymised report containing useful information about "
|
||||
+ "this proxy. If a developer requested it, you may share the "
|
||||
+ "following link with them:")
|
||||
.append(Component.newline())
|
||||
.append(Component.text(">> " + url)
|
||||
.color(NamedTextColor.GREEN)
|
||||
.clickEvent(ClickEvent.openUrl(url)))
|
||||
.append(Component.newline())
|
||||
.append(Component.text("Note: This link is only valid for a few days")
|
||||
.color(NamedTextColor.GRAY)
|
||||
).build());
|
||||
} catch (InterruptedException e) {
|
||||
source.sendMessage(Component.text()
|
||||
.content("Could not complete the request, the command was interrupted."
|
||||
+ "Please refer to the proxy-log or console for more information.")
|
||||
.color(NamedTextColor.RED).build());
|
||||
logger.error("Failed to complete dump command, "
|
||||
+ "the executor was interrupted: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
} catch (ExecutionException e) {
|
||||
TextComponent.Builder message = Component.text()
|
||||
.content("An error occurred while attempting to upload the gathered "
|
||||
+ "information to the Velocity servers.")
|
||||
.append(Component.newline())
|
||||
.color(NamedTextColor.RED);
|
||||
if (e.getCause() instanceof UnknownHostException
|
||||
|| e.getCause() instanceof ConnectException) {
|
||||
message.append(Component.text(
|
||||
"Likely cause: Invalid system DNS settings or no internet connection"));
|
||||
}
|
||||
source.sendMessage(message
|
||||
.append(Component.newline()
|
||||
.append(Component.text(
|
||||
"Error details can be found in the proxy log / console"))
|
||||
).build());
|
||||
|
||||
logger.error("Failed to complete dump command, "
|
||||
+ "the executor encountered an Exception: " + e.getCause().getMessage());
|
||||
e.getCause().printStackTrace();
|
||||
.content("Created an anonymised report containing useful information about "
|
||||
+ "this proxy. If a developer requested it, you may share the "
|
||||
+ "following link with them:")
|
||||
.append(Component.newline())
|
||||
.append(Component.text(">> " + url)
|
||||
.color(NamedTextColor.GREEN)
|
||||
.clickEvent(ClickEvent.openUrl(url)))
|
||||
.append(Component.newline())
|
||||
.append(Component.text("Note: This link is only valid for a few days")
|
||||
.color(NamedTextColor.GRAY)
|
||||
).build());
|
||||
} catch (JsonParseException e) {
|
||||
source.sendMessage(Component.text()
|
||||
.content("An error occurred on the Velocity servers and the dump could not "
|
||||
+ "be completed. Please contact the Velocity staff about this problem. "
|
||||
+ "If you do, provide the details about this error from the Velocity "
|
||||
+ "console or server log.")
|
||||
.color(NamedTextColor.RED).build());
|
||||
.content("An error occurred on the Velocity servers and the dump could not "
|
||||
+ "be completed. Please contact the Velocity staff about this problem. "
|
||||
+ "If you do, provide the details about this error from the Velocity "
|
||||
+ "console or server log.")
|
||||
.color(NamedTextColor.RED).build());
|
||||
logger.error("Invalid response from the Velocity servers: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}, MoreExecutors.directExecutor());
|
||||
}).exceptionally(err -> {
|
||||
source.sendMessage(Component.text()
|
||||
.content("An error occurred whilst gathering the dump. More information is available "
|
||||
+ "in the server console.")
|
||||
.color(NamedTextColor.RED).build());
|
||||
logger.error("Unable to post dump to the Velocity servers", err);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -50,8 +50,14 @@ import com.velocitypowered.proxy.protocol.packet.LoginPluginResponse;
|
||||
import com.velocitypowered.proxy.protocol.packet.ServerLogin;
|
||||
import com.velocitypowered.proxy.protocol.packet.ServerLoginSuccess;
|
||||
import com.velocitypowered.proxy.protocol.packet.SetCompression;
|
||||
import com.velocitypowered.proxy.util.InformationUtils;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpRequest.BodyPublishers;
|
||||
import java.net.http.HttpResponse.BodyHandlers;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.KeyPair;
|
||||
import java.security.MessageDigest;
|
||||
@ -132,9 +138,15 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
||||
url += "&ip=" + urlFormParameterEscaper().escape(playerIp);
|
||||
}
|
||||
|
||||
ListenableFuture<Response> hasJoinedResponse = server.getAsyncHttpClient().prepareGet(url)
|
||||
.execute();
|
||||
hasJoinedResponse.addListener(() -> {
|
||||
server.getAsyncHttpClient().sendAsync(
|
||||
HttpRequest.newBuilder()
|
||||
.uri(URI.create(url))
|
||||
.header("User-Agent", server.getVersion().getName() + "/"
|
||||
+ server.getVersion().getVersion())
|
||||
.GET()
|
||||
.build(),
|
||||
BodyHandlers.ofString()
|
||||
).thenAcceptAsync(hasJoinedResponse -> {
|
||||
if (mcConnection.isClosed()) {
|
||||
// The player disconnected after we authenticated them.
|
||||
return;
|
||||
@ -152,31 +164,30 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Response profileResponse = hasJoinedResponse.get();
|
||||
if (profileResponse.getStatusCode() == 200) {
|
||||
// All went well, initialize the session.
|
||||
initializePlayer(GENERAL_GSON.fromJson(profileResponse.getResponseBody(),
|
||||
GameProfile.class), true);
|
||||
} else if (profileResponse.getStatusCode() == 204) {
|
||||
// Apparently an offline-mode user logged onto this online-mode proxy.
|
||||
inbound.disconnect(Component.translatable("velocity.error.online-mode-only",
|
||||
NamedTextColor.RED));
|
||||
} else {
|
||||
// Something else went wrong
|
||||
logger.error(
|
||||
"Got an unexpected error code {} whilst contacting Mojang to log in {} ({})",
|
||||
profileResponse.getStatusCode(), login.getUsername(), playerIp);
|
||||
inbound.disconnect(Component.translatable("multiplayer.disconnect.authservers_down"));
|
||||
}
|
||||
} catch (ExecutionException e) {
|
||||
logger.error("Unable to authenticate with Mojang", e);
|
||||
if (hasJoinedResponse.statusCode() == 200) {
|
||||
// All went well, initialize the session.
|
||||
initializePlayer(GENERAL_GSON.fromJson(hasJoinedResponse.body(), GameProfile.class),
|
||||
true);
|
||||
} else if (hasJoinedResponse.statusCode() == 204) {
|
||||
// Apparently an offline-mode user logged onto this online-mode proxy.
|
||||
inbound.disconnect(Component.translatable("velocity.error.online-mode-only",
|
||||
NamedTextColor.RED));
|
||||
} else {
|
||||
// Something else went wrong
|
||||
logger.error(
|
||||
"Got an unexpected error code {} whilst contacting Mojang to log in {} ({})",
|
||||
hasJoinedResponse.statusCode(), login.getUsername(), playerIp);
|
||||
inbound.disconnect(Component.translatable("multiplayer.disconnect.authservers_down"));
|
||||
} catch (InterruptedException e) {
|
||||
// not much we can do usefully
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}, mcConnection.eventLoop());
|
||||
}, mcConnection.eventLoop()).exceptionally(err -> {
|
||||
mcConnection.eventLoop().execute(() -> {
|
||||
if (!mcConnection.isClosed()) {
|
||||
logger.error("Unable to enable encryption", err);
|
||||
mcConnection.close(true);
|
||||
}
|
||||
});
|
||||
return null;
|
||||
});
|
||||
} catch (GeneralSecurityException e) {
|
||||
logger.error("Unable to enable encryption", e);
|
||||
mcConnection.close(true);
|
||||
|
@ -17,9 +17,6 @@
|
||||
|
||||
package com.velocitypowered.proxy.network;
|
||||
|
||||
import static org.asynchttpclient.Dsl.asyncHttpClient;
|
||||
import static org.asynchttpclient.Dsl.config;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.velocitypowered.api.event.proxy.ListenerBoundEvent;
|
||||
import com.velocitypowered.api.event.proxy.ListenerCloseEvent;
|
||||
@ -38,15 +35,11 @@ import io.netty.channel.WriteBufferWaterMark;
|
||||
import io.netty.channel.epoll.EpollChannelOption;
|
||||
import io.netty.util.concurrent.GlobalEventExecutor;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.http.HttpClient;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.asynchttpclient.AsyncHttpClient;
|
||||
import org.asynchttpclient.RequestBuilder;
|
||||
import org.asynchttpclient.filter.FilterContext;
|
||||
import org.asynchttpclient.filter.FilterContext.FilterContextBuilder;
|
||||
import org.asynchttpclient.filter.RequestFilter;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public final class ConnectionManager {
|
||||
@ -67,7 +60,7 @@ public final class ConnectionManager {
|
||||
public final BackendChannelInitializerHolder backendChannelInitializer;
|
||||
|
||||
private final SeparatePoolInetNameResolver resolver;
|
||||
private final AsyncHttpClient httpClient;
|
||||
private final HttpClient httpClient;
|
||||
|
||||
/**
|
||||
* Initalizes the {@code ConnectionManager}.
|
||||
@ -84,20 +77,7 @@ public final class ConnectionManager {
|
||||
this.backendChannelInitializer = new BackendChannelInitializerHolder(
|
||||
new BackendChannelInitializer(this.server));
|
||||
this.resolver = new SeparatePoolInetNameResolver(GlobalEventExecutor.INSTANCE);
|
||||
this.httpClient = asyncHttpClient(config()
|
||||
.setEventLoopGroup(this.workerGroup)
|
||||
.setUserAgent(server.getVersion().getName() + "/" + server.getVersion().getVersion())
|
||||
.addRequestFilter(new RequestFilter() {
|
||||
@Override
|
||||
public <T> FilterContext<T> filter(FilterContext<T> ctx) {
|
||||
return new FilterContextBuilder<>(ctx)
|
||||
.request(new RequestBuilder(ctx.getRequest())
|
||||
.setNameResolver(resolver)
|
||||
.build())
|
||||
.build();
|
||||
}
|
||||
})
|
||||
.build());
|
||||
this.httpClient = HttpClient.newBuilder().build();
|
||||
}
|
||||
|
||||
public void logChannelInformation() {
|
||||
@ -241,7 +221,7 @@ public final class ConnectionManager {
|
||||
return this.serverChannelInitializer;
|
||||
}
|
||||
|
||||
public AsyncHttpClient getHttpClient() {
|
||||
public HttpClient getHttpClient() {
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren