Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: fix bugs #4

Merged
merged 4 commits into from
Aug 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 64 additions & 13 deletions src/main/java/cn/apisium/uniporter/Uniporter.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,12 @@
@SoftDependency("ProtocolLib")
public final class Uniporter extends JavaPlugin {
private static final String PREFIX = ChatColor.YELLOW + "[Uniporter] ";
private static final HashMap<String, UniporterHttpHandler> handlers = new HashMap<>();
private static final ArrayList<RouteWithOptions> pluginRoutes = new ArrayList<>();
private static Uniporter instance;
private static Config config;
private static boolean debug; // Is this debug environment
private static boolean useNativeTransport;

/**
* @return Plugin's instance
Expand All @@ -68,13 +71,21 @@ public static boolean isDebug() {
return debug;
}

/**
* @return is in debug environment
*/
public static boolean isUseNativeTransport() {
return useNativeTransport;
}

/**
* Register a route listen to minecraft port.
*
* @param route the route need to be registered
*/
public static void registerRoute(Route route) {
getRouteConfig().registerRoute(route);
getRouteConfig().registerRoute(":minecraft", true, route);
pluginRoutes.add(new RouteWithOptions(":minecraft", true, route));
}

/**
Expand All @@ -87,6 +98,7 @@ public static void registerRoute(Route route) {
@SuppressWarnings("unused")
public static void registerRoute(int port, boolean ssl, Route route) {
getRouteConfig().registerRoute(":" + port, ssl, route);
pluginRoutes.add(new RouteWithOptions(":" + port, ssl, route));
}

/**
Expand All @@ -107,21 +119,47 @@ public static void registerHandler(String id, UniporterHttpHandler handler) {
* @param isAutoRoute will the handler register a route corresponding to its id immediately
*/
public static void registerHandler(String id, UniporterHttpHandler handler, boolean isAutoRoute) {
getRouteConfig().registerHandler(id, handler);
registerHandler(id, handler, isAutoRoute, true);
}

/**
* Register handler for later use.
*
* @param id the unique handler id, the very last handler registered with same id will be used
* @param handler the handler who will process the http request
* @param isAutoRoute will the handler register a route corresponding to its id immediately
* @param gzip whether gzip is enabled
*/
public static void registerHandler(String id, UniporterHttpHandler handler, boolean isAutoRoute, boolean gzip) {
handlers.put(id, handler);
if (isAutoRoute) {
registerRoute(new Route(String.format("/%s", id), id, true, new HashMap<>(),
new HashMap<>()));
registerRoute(new Route("/" + id, id, gzip, Collections.emptyMap(), Collections.emptyMap()));
}
}

@SuppressWarnings("unused")
public static Map<String, UniporterHttpHandler> getHandlers() {
return Collections.unmodifiableMap(handlers);
}

/**
* Remove a registered handler.
*
* @param id the unique handler id
*/
@SuppressWarnings("unused")
public static void removeHandler(String id) {
getRouteConfig().removeHandler(id);
handlers.remove(id);
}

/**
* Find a possible handler represents by the given id
*
* @param id unique handler id
* @return possible handler
*/
public static UniporterHttpHandler getHandler(String id) {
return handlers.get(id);
}

/**
Expand Down Expand Up @@ -197,9 +235,12 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) {
}

private void reload() {
config.stop();
reloadConfig();
debug = this.getConfig().getBoolean("debug", false);
useNativeTransport = this.getConfig().getBoolean("use-native-transport", true);
config = new Config(new File(this.getDataFolder(), "route.yml"));
pluginRoutes.forEach(it -> config.registerRoute(it.port, it.ssl, it.route));
}

@Override
Expand All @@ -209,6 +250,7 @@ public void onEnable() {
instance = this;
config = new Config(new File(this.getDataFolder(), "route.yml"));
debug = this.getConfig().getBoolean("debug", false);
useNativeTransport = this.getConfig().getBoolean("use-native-transport", true);

getServer().getPluginManager().registerEvents(new RouterChannelCreator(), this);

Expand Down Expand Up @@ -258,11 +300,8 @@ public void onDisable() {
future.channel().pipeline().remove(Constants.UNIPORTER_ID);
}
});
// Close all previous opened servers
getRouteConfig().getAdditionalServers().values().forEach(server -> {
server.getFuture().addListener(ChannelFutureListener.CLOSE);
server.getFuture().syncUninterruptibly();
});

config.stop();
}

private static String formatBoolean(boolean value) {
Expand All @@ -273,9 +312,10 @@ private static String formatBoolean(boolean value) {
public boolean onCommand(CommandSender sender, org.bukkit.command.Command command, String label, String[] args) {
if (args.length == 0) {
sender.sendMessage(PREFIX + ChatColor.GRAY + "Version: " + ChatColor.WHITE + getDescription().getVersion());
sender.sendMessage(ChatColor.AQUA + "/uniporter reload");
sender.sendMessage(ChatColor.AQUA + "/uniporter debug");
sender.sendMessage(ChatColor.AQUA + "/uniporter channels");
sender.sendMessage(ChatColor.AQUA + "/uniporter debug");
sender.sendMessage(ChatColor.AQUA + "/uniporter handlers");
sender.sendMessage(ChatColor.AQUA + "/uniporter reload");
return true;
}
if (args.length != 1) return false;
Expand All @@ -289,7 +329,7 @@ public boolean onCommand(CommandSender sender, org.bukkit.command.Command comman
return true;
case "handlers":
sender.sendMessage(PREFIX + ChatColor.GRAY + "Handlers:");
getRouteConfig().getHandlers().forEach((k, v) -> {
handlers.forEach((k, v) -> {
sender.sendMessage(" " + k + ": " + ChatColor.GRAY + v.getClass().getName());
sender.sendMessage(ChatColor.GRAY + " Need re-fire: " + formatBoolean(v.needReFire()));
sender.sendMessage(ChatColor.GRAY + " Hijack Aggregator: " +
Expand Down Expand Up @@ -322,4 +362,15 @@ public List<String> onTabComplete(CommandSender sender, org.bukkit.command.Comma
String alias, String[] args) {
return args.length == 1 ? Arrays.asList("channels", "debug", "handlers", "reload") : Collections.emptyList();
}

private static final class RouteWithOptions {
public final String port;
public final boolean ssl;
public final Route route;
public RouteWithOptions(String port, boolean ssl, Route route) {
this.port = port;
this.ssl = ssl;
this.route = route;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
public class HttpChannelCreatedEvent extends ChannelCreatedEvent {
private static final HandlerList handlerList = new HandlerList();

@SuppressWarnings("unused")
public static HandlerList getHandlerList() {
return handlerList;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*
* @author Baleine_2000
*/
@SuppressWarnings("unused")
public class HttpHelloSender implements UniporterHttpHandler {
@Override
public void handle(String path, Route route, ChannelHandlerContext context, FullHttpRequest request) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import java.nio.charset.StandardCharsets;

@SuppressWarnings("unused")
public class HttpHijackMixedSender implements UniporterHttpHandler {
@Override
public void handle(String path, Route route, ChannelHandlerContext context, FullHttpRequest request) {
Expand All @@ -28,7 +29,7 @@ public void hijack(ChannelHandlerContext context, HttpRequest request) {
context.pipeline().addBefore(Constants.AGGREGATOR_HANDLER_ID, "mixed",
new SimpleChannelInboundHandler<HttpObject>() {
@Override
protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) {
System.out.println(msg);
ctx.fireChannelRead(msg);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import java.nio.charset.StandardCharsets;

@SuppressWarnings("unused")
public class HttpHijackSender implements UniporterHttpHandler {
@Override
public void handle(String path, Route route, ChannelHandlerContext context, FullHttpRequest request) {
Expand All @@ -26,7 +27,7 @@ public void hijack(ChannelHandlerContext context, HttpRequest request) {
context.pipeline().addBefore(Constants.AGGREGATOR_HANDLER_ID, "Hijack",
new SimpleChannelInboundHandler<Object>() {
@Override
protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
protected void channelRead0(ChannelHandlerContext ctx, Object msg) {
Uniporter.send(context, "text/plain", request.uri().getBytes(StandardCharsets.UTF_8));
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@
*
* @author Baleine_2000
*/
@SuppressWarnings("unused")
public class HttpReFireHelloSender implements UniporterHttpHandler {
@Override
public void handle(String path, Route route, ChannelHandlerContext context, FullHttpRequest request) {
context.channel().pipeline().addLast(new SimpleChannelInboundHandler<FullHttpRequest>() {
@Override
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) {
String builder = "ReFired: Hello world from Uniporter!" +
"<br>" +
"<br>This is: " +
Expand Down
59 changes: 12 additions & 47 deletions src/main/java/cn/apisium/uniporter/router/api/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import cn.apisium.uniporter.server.SimpleHttpServer;
import cn.apisium.uniporter.server.SimpleHttpsServer;
import cn.apisium.uniporter.server.SimpleServer;
import io.netty.channel.ChannelFutureListener;
import io.netty.handler.codec.http.HttpResponseStatus;
import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection;
Expand Down Expand Up @@ -38,7 +39,6 @@ public class Config {
final HashMap<String, SimpleServer> additionalServers = new HashMap<>();
// All servers with ports other than :minecraft, key is its port

final HashMap<String, UniporterHttpHandler> handlers = new HashMap<>(); // All registered http handlers
final HashMap<String, Set<Integer>> extraPorts = new HashMap<>();
final HashMap<String, Set<Route>> handlerToRoute = new HashMap<>();
final HashSet<Integer> sslPorts = new HashSet<>();
Expand All @@ -50,6 +50,7 @@ public HashMap<String, HashMap<String, Route>> getRouteCache() {
return routeCache;
}

@SuppressWarnings("unused")
public HashMap<String, SimpleServer> getAdditionalServers() {
return additionalServers;
}
Expand Down Expand Up @@ -83,11 +84,6 @@ public HashMap<String, HashMap<String, HashSet<Route>>> getRoutes() {
return routes;
}

@SuppressWarnings("unused")
public HashMap<String, UniporterHttpHandler> getHandlers() {
return handlers;
}

/**
* Load configuration from given file.
*
Expand Down Expand Up @@ -177,36 +173,6 @@ public Config(File file) {
});
}

/**
* Register handler for later use.
*
* @param id the unique handler id, the very last handler registered with same id will be used
* @param handler the handler who will process the http request
*/
public void registerHandler(String id, UniporterHttpHandler handler) {
handlers.put(id, handler);
}

/**
* Remove a registered handler.
*
* @param id the unique handler id
*/
public void removeHandler(String id) {
handlers.remove(id);
}


/**
* Register a route, with default ssl enable and listen to minecraft port.
*
* @param route the route need to be registered
*/
public void registerRoute(Route route) {
registerRoute(":minecraft", true, route);
}


/**
* Register a route, with given port to listen to, and will ssl be used
*
Expand Down Expand Up @@ -250,16 +216,6 @@ public void registerRoute(String logicalPort, boolean ssl, Route route) {
routes.add(route);
}

/**
* Find a possible handler represents by the given id
*
* @param id unique handler id
* @return possible handler
*/
public Optional<UniporterHttpHandler> getHandler(String id) {
return Optional.ofNullable(handlers.get(id));
}

/**
* Find a most suitable route which listens to minecraft with empty hosts
*
Expand Down Expand Up @@ -304,7 +260,7 @@ public Route findRoute(String logicalPort, String host, String path) throws Ille
// Find match with port numbers as a fallback
|| route.hosts.stream().anyMatch(pattern -> pattern.matcher(host).find()))
// Find the most precise route by path length
.max(Comparator.comparingInt((route) -> route.path.length()))
.max(Comparator.comparingInt(route -> route.path.length()))
// Throws error if nothing is found
.orElseThrow(() -> new IllegalHttpStateException(HttpResponseStatus.NOT_FOUND)));
}
Expand All @@ -327,4 +283,13 @@ public Set<Route> findRoutesByHandler(String handler) {
public boolean isSSLPort(int port) {
return sslPorts.contains(port);
}

// Close all previous opened servers
public void stop() {
additionalServers.forEach((key, server) -> {
server.getFuture().addListener(ChannelFutureListener.CLOSE);
server.getFuture().syncUninterruptibly();
server.stop();
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,10 @@ protected void channelRead0(ChannelHandlerContext context, FullHttpRequest reque
try {
// Find the route corresponding to this request and calls the handler registered
Route route = this.getRoute(context, request.headers(), path);
UniporterHttpHandler handler =
Uniporter.getRouteConfig()
.getHandler(route.getHandler())
.orElseThrow(IllegalHttpStateException::new);

UniporterHttpHandler handler = Uniporter.getHandler(route.getHandler());
if (handler == null) {
throw new IllegalHttpStateException("No such route:<br>" + path, HttpResponseStatus.NOT_FOUND);
}
// Check if the response need to be gzipped or not
if (!route.isGzip() && context.channel().pipeline().names().contains(Constants.GZIP_HANDLER_ID)) {
context.channel().pipeline().remove(Constants.GZIP_HANDLER_ID);
Expand Down Expand Up @@ -73,21 +72,10 @@ protected void channelRead0(ChannelHandlerContext context, FullHttpRequest reque
if (Uniporter.isDebug()) {
exception.printStackTrace();
}
sendNoRouter(path, context);
exception.send(context);
} catch (Throwable e) {
// This is an unexpected error, should not happened
IllegalHttpStateException.send(context, e);
}
}

/**
* Send no router exception via {@link IllegalHttpStateException}.
*
* @param path current accessing path
* @param context current request context
*/
private static void sendNoRouter(String path, ChannelHandlerContext context) {
IllegalHttpStateException.send(context, HttpResponseStatus.NOT_FOUND, String.format("No such route:<br>%s",
path));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ protected void channelRead0(ChannelHandlerContext context, HttpRequest request)

try {
route = this.getRoute(context, request.headers(), findPath(request.uri()));
handler = Uniporter.getRouteConfig().getHandler(route.getHandler()).orElse(null);
handler = Uniporter.getHandler(route.getHandler());
} catch (Throwable ignore) {
}

Expand Down
Loading