package net.md_5.bungee.http;
import com.google.common.base.Preconditions;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoop;
import io.netty.handler.codec.http.DefaultHttpRequest;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpVersion;
import java.net.InetAddress;
import java.net.URI;
import java.net.UnknownHostException;
import java.util.concurrent.TimeUnit;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import net.md_5.bungee.api.Callback;
import net.md_5.bungee.netty.PipelineUtils;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class HttpClient
{
public static final int TIMEOUT = 5000;
private static final Cache<String, InetAddress> addressCache = CacheBuilder.newBuilder().expireAfterWrite( 1, TimeUnit.MINUTES ).build();
@SuppressWarnings("UnusedAssignment")
public static void get(String url, EventLoop eventLoop, final Callback<String> callback)
{
Preconditions.checkNotNull( url, "url" );
Preconditions.checkNotNull( eventLoop, "eventLoop" );
Preconditions.checkNotNull( callback, "callBack" );
final URI uri = URI.create( url );
Preconditions.checkNotNull( uri.getScheme(), "scheme" );
Preconditions.checkNotNull( uri.getHost(), "host" );
boolean ssl = uri.getScheme().equals( "https" );
int port = uri.getPort();
if ( port == -1 )
{
switch ( uri.getScheme() )
{
case "http":
port = 80;
break;
case "https":
port = 443;
break;
default:
throw new IllegalArgumentException( "Unknown scheme " + uri.getScheme() );
}
}
InetAddress inetHost = addressCache.getIfPresent( uri.getHost() );
if ( inetHost == null )
{
try
{
inetHost = InetAddress.getByName( uri.getHost() );
} catch ( UnknownHostException ex )
{
callback.done( null, ex );
return;
}
addressCache.put( uri.getHost(), inetHost );
}
ChannelFutureListener future = new ChannelFutureListener()
{
@Override
public void operationComplete(ChannelFuture future) throws Exception
{
if ( future.isSuccess() )
{
String path = uri.getRawPath() + ( ( uri.getRawQuery() == null ) ? "" : "?" + uri.getRawQuery() );
HttpRequest request = new DefaultHttpRequest( HttpVersion.HTTP_1_1, HttpMethod.GET, path );
request.headers().set( HttpHeaders.Names.HOST, uri.getHost() );
future.channel().writeAndFlush( request );
} else
{
addressCache.invalidate( uri.getHost() );
callback.done( null, future.cause() );
}
}
};
new Bootstrap().channel( PipelineUtils.getChannel() ).group( eventLoop ).handler( new HttpInitializer( callback, ssl, uri.getHost(), port ) ).
option( ChannelOption.CONNECT_TIMEOUT_MILLIS, TIMEOUT ).remoteAddress( inetHost, port ).connect().addListener( future );
}
}