refactoring
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
apply from: rootDir.toPath().resolve('logic.gradle').toFile()
|
apply from: rootDir.toPath().resolve('logic.gradle').toFile()
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':utils')
|
api project(':utils')
|
||||||
|
|
||||||
implementation libs.netty.transport
|
implementation libs.netty.transport
|
||||||
implementation libs.netty.codec
|
implementation libs.netty.codec
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import io.netty.util.AttributeKey;
|
|||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
|
|
||||||
@UtilityClass
|
@UtilityClass
|
||||||
public class NettyAttributes {
|
public class ProtocolAttributes {
|
||||||
|
|
||||||
public static final AttributeKey<State> STATE = AttributeKey.newInstance("STATE");
|
public static final AttributeKey<State> STATE = AttributeKey.newInstance("STATE");
|
||||||
}
|
}
|
||||||
@@ -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<State, Class<? extends ClientSidePacket>, Handler> table = new Table<>();
|
||||||
|
|
||||||
|
public <P extends ClientSidePacket> PacketProcessor addHandler(State state, Class<P> packetClass, Handler<P> handler) {
|
||||||
|
table.put(state, packetClass, handler);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <P extends ClientSidePacket> 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<P extends ClientSidePacket> {
|
||||||
|
void handle(ChannelHandlerContext ctx, P packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,23 +4,25 @@ import io.netty.channel.ChannelHandlerContext;
|
|||||||
import io.netty.channel.SimpleChannelInboundHandler;
|
import io.netty.channel.SimpleChannelInboundHandler;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import mc.protocol.NettyAttributes;
|
import mc.protocol.ProtocolAttributes;
|
||||||
import mc.protocol.State;
|
import mc.protocol.State;
|
||||||
import mc.protocol.packets.ClientSidePacket;
|
import mc.protocol.packets.ClientSidePacket;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class PacketInboundHandler extends SimpleChannelInboundHandler<ClientSidePacket> {
|
public class ProtocolInboundHandler extends SimpleChannelInboundHandler<ClientSidePacket> {
|
||||||
|
|
||||||
private static final String CLIENT_FORCE_DISCONNECTED_IOEXCEPTION_MESSAGE_RU = "Программа на вашем хост-компьютере разорвала установленное подключение";
|
private static final String CLIENT_FORCE_DISCONNECTED_IOEXCEPTION_MESSAGE_RU = "Программа на вашем хост-компьютере разорвала установленное подключение";
|
||||||
|
|
||||||
|
private final PacketProcessor packetProcessor;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void channelRead0(ChannelHandlerContext ctx, ClientSidePacket packet) {
|
protected void channelRead0(ChannelHandlerContext ctx, ClientSidePacket packet) {
|
||||||
State state = ctx.channel().attr(NettyAttributes.STATE).get();
|
State state = Objects.requireNonNull(ctx.channel().attr(ProtocolAttributes.STATE).get());
|
||||||
|
packetProcessor.process(state, ctx, packet);
|
||||||
//TODO process
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -4,20 +4,26 @@ import io.netty.buffer.ByteBuf;
|
|||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.ByteToMessageDecoder;
|
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import mc.protocol.NettyAttributes;
|
import mc.protocol.ProtocolAttributes;
|
||||||
import mc.protocol.State;
|
import mc.protocol.State;
|
||||||
import mc.protocol.buffer.NetByteBuf;
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
import mc.protocol.packets.ClientSidePacket;
|
import mc.protocol.packets.ClientSidePacket;
|
||||||
import mc.protocol.pool.PacketObjectPool;
|
import mc.protocol.pool.PacketObjectPool;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class ProtocolDecoder extends ByteToMessageDecoder {
|
public class ProtocolDecoder extends ByteToMessageDecoder {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void channelActive(ChannelHandlerContext ctx) {
|
||||||
|
ctx.channel().attr(ProtocolAttributes.STATE).set(State.HANDSHAKING);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
|
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> 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);
|
NetByteBuf netByteBuf = new NetByteBuf(in);
|
||||||
|
|
||||||
int packetId = netByteBuf.readVarInt();
|
int packetId = netByteBuf.readVarInt();
|
||||||
|
|||||||
@@ -5,17 +5,19 @@ import io.netty.buffer.Unpooled;
|
|||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.MessageToByteEncoder;
|
import io.netty.handler.codec.MessageToByteEncoder;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import mc.protocol.NettyAttributes;
|
import mc.protocol.ProtocolAttributes;
|
||||||
import mc.protocol.State;
|
import mc.protocol.State;
|
||||||
import mc.protocol.buffer.NetByteBuf;
|
import mc.protocol.buffer.NetByteBuf;
|
||||||
import mc.protocol.packets.ServerSidePacket;
|
import mc.protocol.packets.ServerSidePacket;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class ProtocolEncoder extends MessageToByteEncoder<ServerSidePacket> {
|
public class ProtocolEncoder extends MessageToByteEncoder<ServerSidePacket> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void encode(ChannelHandlerContext ctx, ServerSidePacket packet, ByteBuf out) {
|
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());
|
Integer packetId = state.getServerSidePacketId(packet.getClass());
|
||||||
if (packetId == null) {
|
if (packetId == null) {
|
||||||
log.error("Unknown send packet: State {} ; Class {}", state, packet.getClass());
|
log.error("Unknown send packet: State {} ; Class {}", state, packet.getClass());
|
||||||
|
|||||||
@@ -24,9 +24,13 @@ application {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':cli-parser')
|
implementation project(':cli-parser')
|
||||||
|
implementation project(':protocol-new')
|
||||||
|
|
||||||
implementation libs.logger.logback
|
implementation libs.logger.logback
|
||||||
implementation libs.hocon
|
implementation libs.hocon
|
||||||
|
|
||||||
|
implementation libs.netty.transport
|
||||||
|
implementation libs.netty.handler
|
||||||
}
|
}
|
||||||
|
|
||||||
shadowJar {
|
shadowJar {
|
||||||
|
|||||||
@@ -8,9 +8,18 @@ import lombok.SneakyThrows;
|
|||||||
import mc.cliparser.CommandLine;
|
import mc.cliparser.CommandLine;
|
||||||
import mc.cliparser.CommandLineParser;
|
import mc.cliparser.CommandLineParser;
|
||||||
import mc.cliparser.Option;
|
import mc.cliparser.Option;
|
||||||
import mc.server.di.ConfigComponent;
|
import mc.protocol.ProtocolAttributes;
|
||||||
import mc.server.di.ConfigModule;
|
import mc.protocol.ProtocolConstant;
|
||||||
import mc.server.di.DaggerConfigComponent;
|
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.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -22,6 +31,7 @@ import java.net.URL;
|
|||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
@@ -52,11 +62,11 @@ public class Main {
|
|||||||
commandLine.has(configOption) ? Paths.get(configOption.value()) : null);
|
commandLine.has(configOption) ? Paths.get(configOption.value()) : null);
|
||||||
ConfigComponent configComponent = DaggerConfigComponent.builder()
|
ConfigComponent configComponent = DaggerConfigComponent.builder()
|
||||||
.configModule(configModule).build();
|
.configModule(configModule).build();
|
||||||
Config config = configComponent.getConfig();
|
|
||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
Logger log = LoggerFactory.getLogger("LAUNCHER");
|
Logger log = LoggerFactory.getLogger("LAUNCHER");
|
||||||
if (log.isDebugEnabled()) {
|
if (log.isDebugEnabled()) {
|
||||||
|
Config config = configComponent.getConfig();
|
||||||
log.debug("Logback config path: {}", logconfigOption.value() == null ? "(default)" : logconfigOption.value());
|
log.debug("Logback config path: {}", logconfigOption.value() == null ? "(default)" : logconfigOption.value());
|
||||||
log.debug("Config path: {}", configOption.value() == null ? "(default)" : configOption.value());
|
log.debug("Config path: {}", configOption.value() == null ? "(default)" : configOption.value());
|
||||||
|
|
||||||
@@ -65,8 +75,18 @@ public class Main {
|
|||||||
.sorted()
|
.sorted()
|
||||||
.forEach(log::debug);
|
.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 с учетом путей.
|
||||||
* <p>По-умолчанию, logback пытается искать свои конфиги по заранее зашитым путям.
|
* <p>По-умолчанию, logback пытается искать свои конфиги по заранее зашитым путям.
|
||||||
@@ -94,4 +114,37 @@ public class Main {
|
|||||||
URL url = Objects.requireNonNull(Main.class.getResource("/logback-default.xml"));
|
URL url = Objects.requireNonNull(Main.class.getResource("/logback-default.xml"));
|
||||||
return Paths.get(url.toURI());
|
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);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
55
server-new/src/main/java/mc/server/NettyServer.java
Normal file
55
server-new/src/main/java/mc/server/NettyServer.java
Normal file
@@ -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<SocketChannel>() {
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
}
|
||||||
15
server-new/src/main/java/mc/server/di/ServerComponent.java
Normal file
15
server-new/src/main/java/mc/server/di/ServerComponent.java
Normal file
@@ -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();
|
||||||
|
}
|
||||||
24
server-new/src/main/java/mc/server/di/ServerModule.java
Normal file
24
server-new/src/main/java/mc/server/di/ServerModule.java
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user