Archived
0

создана абстракция над NettyServer

This commit is contained in:
2021-04-27 00:10:55 +03:00
parent eff6dcf148
commit 2a1992b6dd
19 changed files with 194 additions and 201 deletions

View File

@@ -15,9 +15,7 @@ dependencies {
implementation libs.logger.logback
implementation platform('io.projectreactor:reactor-bom:2020.0.6')
implementation 'io.projectreactor:reactor-core'
implementation 'io.netty:netty-all:4.1.22.Final'
implementation libs.netty
implementation libs.reactor
implementation libs.guava
}

View File

@@ -1,9 +1,13 @@
package mc.server;
import lombok.extern.slf4j.Slf4j;
import mc.server.di.DaggerNetworkComponent;
import mc.server.di.NetworkComponent;
import mc.server.network.Server;
import mc.protocol.NettyServer;
import mc.protocol.packets.PingPacket;
import mc.protocol.packets.client.HandshakePacket;
import mc.protocol.packets.client.LoginStartPacket;
import mc.protocol.packets.client.StatusServerRequest;
import mc.protocol.packets.server.DisconnectPacket;
import mc.protocol.packets.server.StatusServerResponse;
@Slf4j
public class Main {
@@ -11,8 +15,49 @@ public class Main {
public static void main(String[] args) {
log.info("hello");
NetworkComponent networkComponent = DaggerNetworkComponent.create();
Server server = networkComponent.getServer();
NettyServer server = NettyServer.createServer();
server.packetFlux(HandshakePacket.class)
.doOnNext(channel -> log.info("{}", channel.getPacket()))
.subscribe(channel -> channel.setState(channel.getPacket().getNextState()));
server.packetFlux(PingPacket.class)
.doOnNext(channel -> log.info("{}", channel.getPacket()))
.subscribe(channel -> channel.getCtx().writeAndFlush(channel.getPacket()).channel().disconnect());
server.packetFlux(StatusServerRequest.class)
.doOnNext(channel -> log.info("{}", channel.getPacket()))
.subscribe(channel -> {
StatusServerResponse response = new StatusServerResponse();
response.setInfo("{\n" +
" \"version\": {\n" +
" \"name\": \"1.12.2\",\n" +
" \"protocol\": 340\n" +
" },\n" +
" \"players\": {\n" +
" \"max\": 0,\n" +
" \"online\": 0,\n" +
" \"sample\": []\n" +
" },\n" +
" \"description\": {\n" +
" \"text\": \"Hello world\"\n" +
" }\n" +
"}");
channel.getCtx().writeAndFlush(response);
});
server.packetFlux(LoginStartPacket.class)
.doOnNext(channel -> log.info("{}", channel.getPacket()))
.subscribe(channel -> {
DisconnectPacket disconnectPacket = new DisconnectPacket();
disconnectPacket.setReason("{\n" +
" \"text\": \"Server is not available.\"\n" +
"}");
channel.getCtx().writeAndFlush(disconnectPacket).channel().disconnect();
});
server.bind("127.0.0.1", 25565);
}
}

View File

@@ -1,10 +0,0 @@
package mc.server.di;
import dagger.Component;
import mc.server.network.Server;
@Component(modules = NetworkModule.class)
public interface NetworkComponent {
Server getServer();
}

View File

@@ -1,92 +0,0 @@
package mc.server.di;
import dagger.Module;
import dagger.Provides;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
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.extern.slf4j.Slf4j;
import mc.protocol.io.codec.ProtocolDecoder;
import mc.protocol.io.codec.ProtocolEncoder;
import mc.protocol.io.codec.ProtocolSplitter;
import mc.server.network.Server;
import mc.server.network.netty.handler.HandshakeHandler;
import mc.server.network.netty.NettyServer;
import mc.server.network.netty.handler.KeepAliveHandler;
import mc.server.network.netty.handler.LoginHandler;
import mc.server.network.netty.handler.StatusHandler;
import javax.inject.Provider;
import java.util.LinkedHashMap;
import java.util.Map;
@Module
@Slf4j
public class NetworkModule {
@Provides
Server provideServer(ServerBootstrap serverBootstrap) {
return new NettyServer(serverBootstrap);
}
@Provides
ServerBootstrap provideServerBootstrap(ChannelInitializer<SocketChannel> channelChannelInitializer) {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(new NioEventLoopGroup(1), new NioEventLoopGroup())
.channel(NioServerSocketChannel.class)
.childHandler(channelChannelInitializer);
return bootstrap;
}
@Provides
ChannelInitializer<SocketChannel> provideChannelChannelInitializer(Provider<Map<String, ChannelHandler>> channelHandlerMapProvider) {
return new ChannelInitializer<>() {
@Override
protected void initChannel(SocketChannel socketChannel) {
ChannelPipeline pipeline = socketChannel.pipeline();
channelHandlerMapProvider.get().forEach(pipeline::addLast);
}
};
}
@Provides
Map<String, ChannelHandler> provideChannelHandlerMap(
Provider<StatusHandler> statusHandlerProvider,
Provider<LoginHandler> loginHandlerProvider,
Provider<KeepAliveHandler> keepAliveHandlerProvider
) {
Map<String, ChannelHandler> map = new LinkedHashMap<>();
map.put("logger", new LoggingHandler(LogLevel.DEBUG));
map.put("protocol_splitter", new ProtocolSplitter());
map.put("protocol_decoder", new ProtocolDecoder(true));
map.put("protocol_encoder", new ProtocolEncoder());
map.put("handshake_handler", new HandshakeHandler(
statusHandlerProvider, loginHandlerProvider, keepAliveHandlerProvider));
return map;
}
@Provides
StatusHandler provideStatusHandler() {
return new StatusHandler();
}
@Provides
LoginHandler provideLoginHandler() {
return new LoginHandler();
}
@Provides
KeepAliveHandler provideKeepAliveHandler() {
return new KeepAliveHandler();
}
}

View File

@@ -1,6 +0,0 @@
package mc.server.network;
public interface Server {
void bind(String host, int port);
}

View File

@@ -1,26 +0,0 @@
package mc.server.network.netty;
import io.netty.bootstrap.ServerBootstrap;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import mc.server.network.Server;
@Slf4j
@RequiredArgsConstructor
public class NettyServer implements Server {
private final ServerBootstrap serverBootstrap;
@Override
public void bind(String host, int port) {
log.info("Network starting: {}:{}", host, port);
try {
serverBootstrap.bind(host, port).sync().channel().closeFuture().sync();
} catch (InterruptedException e) {
if (log.isTraceEnabled()) {
log.trace("{}: {}", e.getClass().getSimpleName(), e.getMessage(), e);
}
}
}
}

View File

@@ -1,17 +0,0 @@
package mc.server.network.netty.handler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import mc.protocol.packets.Packet;
public abstract class AbstractPacketHandler<P extends Packet> extends SimpleChannelInboundHandler<Packet> {
@SuppressWarnings("unchecked")
@Override
protected void channelRead0(ChannelHandlerContext ctx, Packet msg) throws Exception {
channelRead1(ctx, (P) msg);
}
@SuppressWarnings("java:S112")
protected abstract void channelRead1(ChannelHandlerContext ctx, P packet) throws Exception;
}

View File

@@ -1,33 +0,0 @@
package mc.server.network.netty.handler;
import io.netty.channel.ChannelHandlerContext;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import mc.protocol.NetworkAttributes;
import mc.protocol.State;
import mc.protocol.packets.client.HandshakePacket;
import javax.inject.Provider;
@Slf4j
@RequiredArgsConstructor
public class HandshakeHandler extends AbstractPacketHandler<HandshakePacket> {
private final Provider<StatusHandler> statusHandlerProvider;
private final Provider<LoginHandler> loginHandlerProvider;
private final Provider<KeepAliveHandler> keepAliveHandlerProvider;
@Override
protected void channelRead1(ChannelHandlerContext ctx, HandshakePacket packet) {
log.info("{}", packet);
ctx.channel().attr(NetworkAttributes.STATE).set(packet.getNextState());
if (State.STATUS == packet.getNextState()) {
ctx.pipeline().replace("handshake_handler", "status_handler", statusHandlerProvider.get());
ctx.pipeline().addAfter("status_handler", "keepalive_handler", keepAliveHandlerProvider.get());
} else if (State.LOGIN == packet.getNextState()) {
ctx.channel().pipeline().replace("handshake_handler", "login_handler", loginHandlerProvider.get());
}
}
}

View File

@@ -1,16 +0,0 @@
package mc.server.network.netty.handler;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import mc.protocol.packets.PingPacket;
@Slf4j
public class KeepAliveHandler extends AbstractPacketHandler<PingPacket> {
@Override
protected void channelRead1(ChannelHandlerContext ctx, PingPacket packet) {
log.info("{}", packet);
ctx.writeAndFlush(packet).channel().disconnect();
}
}

View File

@@ -1,18 +0,0 @@
package mc.server.network.netty.handler;
import io.netty.channel.ChannelHandlerContext;
import mc.protocol.packets.client.LoginStartPacket;
import mc.protocol.packets.server.DisconnectPacket;
public class LoginHandler extends AbstractPacketHandler<LoginStartPacket> {
@Override
protected void channelRead1(ChannelHandlerContext ctx, LoginStartPacket packet) {
DisconnectPacket disconnectPacket = new DisconnectPacket();
disconnectPacket.setReason("{\n" +
" \"text\": \"Server is not available.\"\n" +
"}");
ctx.channel().writeAndFlush(disconnectPacket).channel().disconnect();
}
}

View File

@@ -1,33 +0,0 @@
package mc.server.network.netty.handler;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import mc.protocol.packets.client.StatusServerRequest;
import mc.protocol.packets.server.StatusServerResponse;
@Slf4j
public class StatusHandler extends AbstractPacketHandler<StatusServerRequest> {
@Override
protected void channelRead1(ChannelHandlerContext ctx, StatusServerRequest packet) {
log.info("{}", packet);
StatusServerResponse response = new StatusServerResponse();
response.setInfo("{\n" +
" \"version\": {\n" +
" \"name\": \"1.12.2\",\n" +
" \"protocol\": 340\n" +
" },\n" +
" \"players\": {\n" +
" \"max\": 0,\n" +
" \"online\": 0,\n" +
" \"sample\": []\n" +
" },\n" +
" \"description\": {\n" +
" \"text\": \"Hello world\"\n" +
" }\n" +
"}");
ctx.channel().writeAndFlush(response);
}
}