#2447: Add API for fluent server connect requests

API allows for more control over callback to see why the callback was performed whilst maintaining backwards compatibility
This commit is contained in:
Mystiflow 2018-07-23 05:40:31 +01:00 committed by md_5
parent 6fadb4250c
commit 715ec07a28
3 changed files with 119 additions and 7 deletions

View File

@ -0,0 +1,78 @@
package net.md_5.bungee.api;
import lombok.Builder;
import lombok.Getter;
import lombok.NonNull;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.event.ServerConnectEvent;
/**
* A request to connect a server.
*/
@Getter
@Builder(builderClassName = "Builder")
public class ServerConnectRequest
{
/**
* The result from this callback after request has been executed by proxy.
*/
public enum Result
{
/**
* ServerConnectEvent to the new server was canceled.
*/
EVENT_CANCEL,
/**
* Already connected to target server.
*/
ALREADY_CONNECTED,
/**
* Already connecting to target server.
*/
ALREADY_CONNECTING,
/**
* Successfully connected to server.
*/
SUCCESS,
/**
* Connection failed, error can be accessed from callback method handle.
*/
FAIL
}
/**
* Target server to connect to.
*/
@NonNull
private final ServerInfo target;
/**
* Reason for connecting to server.
*/
@NonNull
private final ServerConnectEvent.Reason reason;
/**
* Callback to execute post request.
*/
private final Callback<Result> callback;
/**
* Timeout in milliseconds for request.
*/
private final int connectTimeout;
/**
* Should the player be attempted to connect to the next server in their
* queue if the initial request fails.
*/
private final boolean retry;
/**
* Class that sets default properties/adds methods to the lombok builder
* generated class.
*/
public static class ServerConnectRequestBuilder
{
private int connectTimeout = 5000; // TODO: Configurable
}
}

View File

@ -6,6 +6,7 @@ import java.util.UUID;
import net.md_5.bungee.api.Callback;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ServerConnectRequest;
import net.md_5.bungee.api.SkinConfiguration;
import net.md_5.bungee.api.Title;
import net.md_5.bungee.api.chat.BaseComponent;
@ -123,6 +124,15 @@ public interface ProxiedPlayer extends Connection, CommandSender
*/
void connect(ServerInfo target, Callback<Boolean> callback, ServerConnectEvent.Reason reason);
/**
* Connects / transfers this user to the specified connection, gracefully
* closing the current one. Depending on the implementation, this method
* might return before the user has been connected.
*
* @param request request to connect with
*/
void connect(ServerConnectRequest request);
/**
* Gets the server this player is connected to.
*

View File

@ -27,6 +27,7 @@ import lombok.Setter;
import net.md_5.bungee.api.Callback;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.ServerConnectRequest;
import net.md_5.bungee.api.SkinConfiguration;
import net.md_5.bungee.api.Title;
import net.md_5.bungee.api.chat.BaseComponent;
@ -253,12 +254,35 @@ public final class UserConnection implements ProxiedPlayer
{
Preconditions.checkNotNull( info, "info" );
ServerConnectEvent event = new ServerConnectEvent( this, info, reason );
ServerConnectRequest.Builder builder = ServerConnectRequest.builder().retry( retry ).reason( reason ).target( info );
if ( callback != null )
{
// Convert the Callback<Boolean> to be compatible with Callback<Result> from ServerConnectRequest.
builder.callback( new Callback<ServerConnectRequest.Result>()
{
@Override
public void done(ServerConnectRequest.Result result, Throwable error)
{
callback.done( ( result == ServerConnectRequest.Result.SUCCESS ) ? Boolean.TRUE : Boolean.FALSE, error );
}
} );
}
connect( builder.build() );
}
@Override
public void connect(final ServerConnectRequest request)
{
Preconditions.checkNotNull( request, "request" );
final Callback<ServerConnectRequest.Result> callback = request.getCallback();
ServerConnectEvent event = new ServerConnectEvent( this, request.getTarget(), request.getReason() );
if ( bungee.getPluginManager().callEvent( event ).isCancelled() )
{
if ( callback != null )
{
callback.done( false, null );
callback.done( ServerConnectRequest.Result.EVENT_CANCEL, null );
}
if ( getServer() == null && !ch.isClosing() )
@ -274,7 +298,7 @@ public final class UserConnection implements ProxiedPlayer
{
if ( callback != null )
{
callback.done( false, null );
callback.done( ServerConnectRequest.Result.ALREADY_CONNECTED, null );
}
sendMessage( bungee.getTranslation( "already_connected" ) );
@ -284,7 +308,7 @@ public final class UserConnection implements ProxiedPlayer
{
if ( callback != null )
{
callback.done( false, null );
callback.done( ServerConnectRequest.Result.ALREADY_CONNECTING, null );
}
sendMessage( bungee.getTranslation( "already_connecting" ) );
@ -312,7 +336,7 @@ public final class UserConnection implements ProxiedPlayer
{
if ( callback != null )
{
callback.done( future.isSuccess(), future.cause() );
callback.done( ( future.isSuccess() ) ? ServerConnectRequest.Result.SUCCESS : ServerConnectRequest.Result.FAIL, future.cause() );
}
if ( !future.isSuccess() )
@ -321,7 +345,7 @@ public final class UserConnection implements ProxiedPlayer
pendingConnects.remove( target );
ServerInfo def = updateAndGetNextServer( target );
if ( retry && def != null && ( getServer() == null || def != getServer().getInfo() ) )
if ( request.isRetry() && def != null && ( getServer() == null || def != getServer().getInfo() ) )
{
sendMessage( bungee.getTranslation( "fallback_lobby" ) );
connect( def, null, true, ServerConnectEvent.Reason.LOBBY_FALLBACK );
@ -339,7 +363,7 @@ public final class UserConnection implements ProxiedPlayer
.channel( PipelineUtils.getChannel() )
.group( ch.getHandle().eventLoop() )
.handler( initializer )
.option( ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000 ) // TODO: Configurable
.option( ChannelOption.CONNECT_TIMEOUT_MILLIS, request.getConnectTimeout() )
.remoteAddress( target.getAddress() );
// Windows is bugged, multi homed users will just have to live with random connecting IPs
if ( getPendingConnection().getListener().isSetLocalAddress() && !PlatformDependent.isWindows() )