From 475f1a28ca8344b31252b5118e682b14618757de Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Sun, 13 Jun 2021 17:06:46 +0300 Subject: [PATCH] refactoring --- protocol-new/build.gradle | 2 +- ...ttributes.java => ProtocolAttributes.java} | 2 +- .../mc/protocol/handler/PacketProcessor.java | 30 +++++++++ ...ndler.java => ProtocolInboundHandler.java} | 12 ++-- .../handler/codec/ProtocolDecoder.java | 10 ++- .../handler/codec/ProtocolEncoder.java | 6 +- .../main/java/mc/protocol/utils/Table.java | 0 server-new/build.gradle | 4 ++ server-new/src/main/java/mc/server/Main.java | 61 +++++++++++++++++-- .../src/main/java/mc/server/NettyServer.java | 55 +++++++++++++++++ .../java/mc/server/di/ServerComponent.java | 15 +++++ .../main/java/mc/server/di/ServerModule.java | 24 ++++++++ 12 files changed, 206 insertions(+), 15 deletions(-) rename protocol-new/src/main/java/mc/protocol/{NettyAttributes.java => ProtocolAttributes.java} (85%) create mode 100644 protocol-new/src/main/java/mc/protocol/handler/PacketProcessor.java rename protocol-new/src/main/java/mc/protocol/handler/{PacketInboundHandler.java => ProtocolInboundHandler.java} (76%) rename {protocol => protocol-new}/src/main/java/mc/protocol/utils/Table.java (100%) create mode 100644 server-new/src/main/java/mc/server/NettyServer.java create mode 100644 server-new/src/main/java/mc/server/di/ServerComponent.java create mode 100644 server-new/src/main/java/mc/server/di/ServerModule.java diff --git a/protocol-new/build.gradle b/protocol-new/build.gradle index 3162283..9458488 100644 --- a/protocol-new/build.gradle +++ b/protocol-new/build.gradle @@ -1,7 +1,7 @@ apply from: rootDir.toPath().resolve('logic.gradle').toFile() dependencies { - implementation project(':utils') + api project(':utils') implementation libs.netty.transport implementation libs.netty.codec diff --git a/protocol-new/src/main/java/mc/protocol/NettyAttributes.java b/protocol-new/src/main/java/mc/protocol/ProtocolAttributes.java similarity index 85% rename from protocol-new/src/main/java/mc/protocol/NettyAttributes.java rename to protocol-new/src/main/java/mc/protocol/ProtocolAttributes.java index ddca953..da368cd 100644 --- a/protocol-new/src/main/java/mc/protocol/NettyAttributes.java +++ b/protocol-new/src/main/java/mc/protocol/ProtocolAttributes.java @@ -4,7 +4,7 @@ import io.netty.util.AttributeKey; import lombok.experimental.UtilityClass; @UtilityClass -public class NettyAttributes { +public class ProtocolAttributes { public static final AttributeKey STATE = AttributeKey.newInstance("STATE"); } diff --git a/protocol-new/src/main/java/mc/protocol/handler/PacketProcessor.java b/protocol-new/src/main/java/mc/protocol/handler/PacketProcessor.java new file mode 100644 index 0000000..8413988 --- /dev/null +++ b/protocol-new/src/main/java/mc/protocol/handler/PacketProcessor.java @@ -0,0 +1,30 @@ +package mc.protocol.handler; + +import io.netty.channel.ChannelHandlerContext; +import mc.protocol.State; +import mc.protocol.packets.ClientSidePacket; +import mc.protocol.utils.Table; + +@SuppressWarnings({ "rawtypes", "unchecked" }) +public class PacketProcessor { + + private final Table, Handler> table = new Table<>(); + + public

PacketProcessor addHandler(State state, Class

packetClass, Handler

handler) { + table.put(state, packetClass, handler); + return this; + } + + public

void process(State state, ChannelHandlerContext ctx, P packet) { + Handler handler = table.getColumnAndRow(state, packet.getClass()); + + if (handler != null) { + handler.handle(ctx, packet); + } + } + + @FunctionalInterface + public interface Handler

{ + void handle(ChannelHandlerContext ctx, P packet); + } +} diff --git a/protocol-new/src/main/java/mc/protocol/handler/PacketInboundHandler.java b/protocol-new/src/main/java/mc/protocol/handler/ProtocolInboundHandler.java similarity index 76% rename from protocol-new/src/main/java/mc/protocol/handler/PacketInboundHandler.java rename to protocol-new/src/main/java/mc/protocol/handler/ProtocolInboundHandler.java index 7cfd820..a45ddfd 100644 --- a/protocol-new/src/main/java/mc/protocol/handler/PacketInboundHandler.java +++ b/protocol-new/src/main/java/mc/protocol/handler/ProtocolInboundHandler.java @@ -4,23 +4,25 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import mc.protocol.NettyAttributes; +import mc.protocol.ProtocolAttributes; import mc.protocol.State; import mc.protocol.packets.ClientSidePacket; import java.io.IOException; +import java.util.Objects; @Slf4j @RequiredArgsConstructor -public class PacketInboundHandler extends SimpleChannelInboundHandler { +public class ProtocolInboundHandler extends SimpleChannelInboundHandler { private static final String CLIENT_FORCE_DISCONNECTED_IOEXCEPTION_MESSAGE_RU = "Программа на вашем хост-компьютере разорвала установленное подключение"; + private final PacketProcessor packetProcessor; + @Override protected void channelRead0(ChannelHandlerContext ctx, ClientSidePacket packet) { - State state = ctx.channel().attr(NettyAttributes.STATE).get(); - - //TODO process + State state = Objects.requireNonNull(ctx.channel().attr(ProtocolAttributes.STATE).get()); + packetProcessor.process(state, ctx, packet); } @Override diff --git a/protocol-new/src/main/java/mc/protocol/handler/codec/ProtocolDecoder.java b/protocol-new/src/main/java/mc/protocol/handler/codec/ProtocolDecoder.java index cadf4f9..1a63ecd 100644 --- a/protocol-new/src/main/java/mc/protocol/handler/codec/ProtocolDecoder.java +++ b/protocol-new/src/main/java/mc/protocol/handler/codec/ProtocolDecoder.java @@ -4,20 +4,26 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import lombok.extern.slf4j.Slf4j; -import mc.protocol.NettyAttributes; +import mc.protocol.ProtocolAttributes; import mc.protocol.State; import mc.protocol.buffer.NetByteBuf; import mc.protocol.packets.ClientSidePacket; import mc.protocol.pool.PacketObjectPool; import java.util.List; +import java.util.Objects; @Slf4j public class ProtocolDecoder extends ByteToMessageDecoder { + @Override + public void channelActive(ChannelHandlerContext ctx) { + ctx.channel().attr(ProtocolAttributes.STATE).set(State.HANDSHAKING); + } + @Override protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { - State state = ctx.channel().attr(NettyAttributes.STATE).get(); + State state = Objects.requireNonNull(ctx.channel().attr(ProtocolAttributes.STATE).get()); NetByteBuf netByteBuf = new NetByteBuf(in); int packetId = netByteBuf.readVarInt(); diff --git a/protocol-new/src/main/java/mc/protocol/handler/codec/ProtocolEncoder.java b/protocol-new/src/main/java/mc/protocol/handler/codec/ProtocolEncoder.java index c357d52..ccf0ff5 100644 --- a/protocol-new/src/main/java/mc/protocol/handler/codec/ProtocolEncoder.java +++ b/protocol-new/src/main/java/mc/protocol/handler/codec/ProtocolEncoder.java @@ -5,17 +5,19 @@ import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToByteEncoder; import lombok.extern.slf4j.Slf4j; -import mc.protocol.NettyAttributes; +import mc.protocol.ProtocolAttributes; import mc.protocol.State; import mc.protocol.buffer.NetByteBuf; import mc.protocol.packets.ServerSidePacket; +import java.util.Objects; + @Slf4j public class ProtocolEncoder extends MessageToByteEncoder { @Override protected void encode(ChannelHandlerContext ctx, ServerSidePacket packet, ByteBuf out) { - State state = ctx.channel().attr(NettyAttributes.STATE).get(); + State state = Objects.requireNonNull(ctx.channel().attr(ProtocolAttributes.STATE).get()); Integer packetId = state.getServerSidePacketId(packet.getClass()); if (packetId == null) { log.error("Unknown send packet: State {} ; Class {}", state, packet.getClass()); diff --git a/protocol/src/main/java/mc/protocol/utils/Table.java b/protocol-new/src/main/java/mc/protocol/utils/Table.java similarity index 100% rename from protocol/src/main/java/mc/protocol/utils/Table.java rename to protocol-new/src/main/java/mc/protocol/utils/Table.java diff --git a/server-new/build.gradle b/server-new/build.gradle index 62650da..80f4366 100644 --- a/server-new/build.gradle +++ b/server-new/build.gradle @@ -24,9 +24,13 @@ application { dependencies { implementation project(':cli-parser') + implementation project(':protocol-new') implementation libs.logger.logback implementation libs.hocon + + implementation libs.netty.transport + implementation libs.netty.handler } shadowJar { diff --git a/server-new/src/main/java/mc/server/Main.java b/server-new/src/main/java/mc/server/Main.java index 8374a3e..da7b467 100644 --- a/server-new/src/main/java/mc/server/Main.java +++ b/server-new/src/main/java/mc/server/Main.java @@ -8,9 +8,18 @@ import lombok.SneakyThrows; import mc.cliparser.CommandLine; import mc.cliparser.CommandLineParser; import mc.cliparser.Option; -import mc.server.di.ConfigComponent; -import mc.server.di.ConfigModule; -import mc.server.di.DaggerConfigComponent; +import mc.protocol.ProtocolAttributes; +import mc.protocol.ProtocolConstant; +import mc.protocol.State; +import mc.protocol.handler.PacketProcessor; +import mc.protocol.model.ServerInfo; +import mc.protocol.model.ServerInfoSerializer; +import mc.protocol.model.text.TextSerializer; +import mc.protocol.packets.KeepAlivePacket; +import mc.protocol.packets.handshaking.client.HandshakePacket; +import mc.protocol.packets.status.client.StatusServerRequestPacket; +import mc.protocol.packets.status.server.StatusServerResponse; +import mc.server.di.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,6 +31,7 @@ import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Collections; import java.util.Objects; public class Main { @@ -52,11 +62,11 @@ public class Main { commandLine.has(configOption) ? Paths.get(configOption.value()) : null); ConfigComponent configComponent = DaggerConfigComponent.builder() .configModule(configModule).build(); - Config config = configComponent.getConfig(); //endregion Logger log = LoggerFactory.getLogger("LAUNCHER"); if (log.isDebugEnabled()) { + Config config = configComponent.getConfig(); log.debug("Logback config path: {}", logconfigOption.value() == null ? "(default)" : logconfigOption.value()); log.debug("Config path: {}", configOption.value() == null ? "(default)" : configOption.value()); @@ -65,8 +75,18 @@ public class Main { .sorted() .forEach(log::debug); } + + ServerComponent serverComponent = DaggerServerComponent.create(); + setupPacketProcessor(serverComponent, configComponent); + + Config config = configComponent.getConfig(); + NettyServer server = serverComponent.getNettyServer(); + + log.info("Server starting: {}:{}", config.getString("server.host"), config.getInt("server.port")); + server.start(config.getString("server.host"), config.getInt("server.port")); } + //TODO нужно продумать как этот метод сделать доступным для расширенных версий сервера /** * Перенастраиваем logback с учетом путей. *

По-умолчанию, logback пытается искать свои конфиги по заранее зашитым путям. @@ -94,4 +114,37 @@ public class Main { URL url = Objects.requireNonNull(Main.class.getResource("/logback-default.xml")); return Paths.get(url.toURI()); } + + private static void setupPacketProcessor(ServerComponent serverComponent, ConfigComponent configComponent) { + PacketProcessor packetProcessor = serverComponent.getPacketProcessor(); + + packetProcessor.addHandler(State.HANDSHAKING, HandshakePacket.class, + (ctx, packet) -> ctx.channel().attr(ProtocolAttributes.STATE).set(packet.getNextState())); + + setupStatusPacketProcessor(packetProcessor, configComponent); + } + + private static void setupStatusPacketProcessor(PacketProcessor packetProcessor, ConfigComponent configComponent) { + Config config = configComponent.getConfig(); + + packetProcessor + .addHandler(State.STATUS, KeepAlivePacket.class, (ctx, packet) -> { + ctx.writeAndFlush(packet); + ctx.close(); + }) + .addHandler(State.STATUS, StatusServerRequestPacket.class, (ctx, packet) -> { + ServerInfo serverInfo = new ServerInfo(); + serverInfo.version().name(ProtocolConstant.PROTOCOL_NAME); + serverInfo.version().protocol(ProtocolConstant.PROTOCOL_NUMBER); + serverInfo.players().max(config.getInt("players.max-online")); + serverInfo.players().online(config.getInt("players.fake-online.value")); + serverInfo.players().sample(Collections.emptyList()); + serverInfo.description(TextSerializer.fromPlain(config.getString("motd"))); + + StatusServerResponse response = new StatusServerResponse(); + response.setInfo(ServerInfoSerializer.toStringPlain(serverInfo)); + + ctx.writeAndFlush(response); + }); + } } diff --git a/server-new/src/main/java/mc/server/NettyServer.java b/server-new/src/main/java/mc/server/NettyServer.java new file mode 100644 index 0000000..adb11fc --- /dev/null +++ b/server-new/src/main/java/mc/server/NettyServer.java @@ -0,0 +1,55 @@ +package mc.server; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.logging.LogLevel; +import io.netty.handler.logging.LoggingHandler; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import mc.protocol.handler.PacketProcessor; +import mc.protocol.handler.ProtocolInboundHandler; +import mc.protocol.handler.codec.ProtocolDecoder; +import mc.protocol.handler.codec.ProtocolEncoder; +import mc.protocol.handler.codec.ProtocolSplitter; + +import javax.annotation.Nonnull; + +@Slf4j +@RequiredArgsConstructor +public class NettyServer { + + private final PacketProcessor packetProcessor; + + public void start(String host, int port) { + try { + createServerBootstrap().bind(host, port).sync().channel().closeFuture().sync(); + } catch (InterruptedException e) { + if (log.isTraceEnabled()) { + log.trace("{}: {}", e.getClass().getSimpleName(), e.getMessage(), e); + } + } + } + + private ServerBootstrap createServerBootstrap() { + ServerBootstrap bootstrap = new ServerBootstrap(); + + bootstrap.group(new NioEventLoopGroup(1), new NioEventLoopGroup()) + .channel(NioServerSocketChannel.class) + .childHandler(new ChannelInitializer() { + @Override + protected void initChannel(@Nonnull SocketChannel socketChannel) { + socketChannel.pipeline() + .addLast("packet_splitter", new ProtocolSplitter()) + .addLast("logger", new LoggingHandler(LogLevel.DEBUG)) + .addLast("packet_decoder", new ProtocolDecoder()) + .addLast("packet_encoder", new ProtocolEncoder()) + .addLast("packet_handler", new ProtocolInboundHandler(packetProcessor)); + } + }); + + return bootstrap; + } +} diff --git a/server-new/src/main/java/mc/server/di/ServerComponent.java b/server-new/src/main/java/mc/server/di/ServerComponent.java new file mode 100644 index 0000000..cd1b738 --- /dev/null +++ b/server-new/src/main/java/mc/server/di/ServerComponent.java @@ -0,0 +1,15 @@ +package mc.server.di; + +import dagger.Component; +import mc.protocol.handler.PacketProcessor; +import mc.server.NettyServer; + +import javax.inject.Singleton; + +@Component(modules = ServerModule.class) +@Singleton +public interface ServerComponent { + + PacketProcessor getPacketProcessor(); + NettyServer getNettyServer(); +} diff --git a/server-new/src/main/java/mc/server/di/ServerModule.java b/server-new/src/main/java/mc/server/di/ServerModule.java new file mode 100644 index 0000000..82467d9 --- /dev/null +++ b/server-new/src/main/java/mc/server/di/ServerModule.java @@ -0,0 +1,24 @@ +package mc.server.di; + +import dagger.Module; +import dagger.Provides; +import mc.protocol.handler.PacketProcessor; +import mc.server.NettyServer; + +import javax.inject.Singleton; + +@Module +public class ServerModule { + + @Provides + @Singleton + PacketProcessor providePacketProcessor() { + return new PacketProcessor(); + } + + @Provides + @Singleton + NettyServer provideNettyServer(PacketProcessor packetProcessor) { + return new NettyServer(packetProcessor); + } +}