update project structure

This commit is contained in:
Him188moe 2019-08-08 21:16:26 +08:00
parent c17e95300a
commit a2fae796fa
4 changed files with 195 additions and 0 deletions

View File

@ -38,6 +38,13 @@
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
</dependency>
</dependencies>
<build>
<resources>

View File

@ -0,0 +1,58 @@
package net.mamoe.mirai.network;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.bytes.ByteArrayDecoder;
import io.netty.handler.codec.bytes.ByteArrayEncoder;
/**
* JPRE 网络层启动器.
* 本类用于启动网络服务器. 包接受器请参考 {@link NetworkPacketHandler}
* (插件请不要使用本类, 用了也会因端口占用而抛出异常)
*
* @author Him188 @ JPRE Project
*/
public final class Network {
private static ServerBootstrap server;
/**
* 启动网络服务器. 会阻塞线程直到关闭网络服务器.
*
* @param port 端口号
* @throws RuntimeException 服务器已经启动时抛出
*/
public static void start(int port) throws InterruptedException {
if (server != null) {
throw new RuntimeException("there is already a ServerBootstrap instance");
}
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
server = new ServerBootstrap();
server.group(bossGroup, workerGroup);
server.channel(NioServerSocketChannel.class);
//b.option(ChannelOption.SO_BACKLOG, 100);
//b.handler(new LoggingHandler(LogLevel.INFO));
server.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("bytesDecoder", new ByteArrayDecoder());
pipeline.addLast("bytesEncoder", new ByteArrayEncoder());
pipeline.addLast("handler", new NetworkPacketHandler());
}
});
server.bind(port).sync().channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}

View File

@ -0,0 +1,123 @@
package net.mamoe.mirai.network;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import java.io.IOException;
import java.net.InetSocketAddress;
/**
* 网络数据包接收器. 该类属于网络层, 插件一般不需要使用
*
* @author Him188 @ JPRE Project
*/
public class NetworkPacketHandler extends SimpleChannelInboundHandler<byte[]> {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
super.channelRead(ctx, msg);
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, byte[] data) throws Exception {
synchronized (this) {
handlePacket(ctx, data);
}
}
private byte[] temp = new byte[0];
/**
* Synchronized by {@code synchronized (this)} in {@link #channelRead0}
*/
private void handlePacket(ChannelHandlerContext ctx, byte[] data) {
try {
temp = Utils.arrayAppend(temp, data);
while (temp.length != 0) {
int position = Utils.arraySearch(temp, Protocol.SIGNATURE);
if (position < 0) {
return;//收到的是子包, 数据未结尾
}
byte[] d = Utils.arrayGetCenter(temp, 0, position);
temp = Utils.arrayDelete(temp, position + Protocol.SIGNATURE.length);
JPREMain.getInstance().getScheduler().addTask(() -> processPacket(ctx, d));
}
} catch (Exception e) {
e.printStackTrace();
}
}
//TODO 改为 public, 并将 ctx 改为插件可扩展的消息源以实现多源化
private void processPacket(ChannelHandlerContext ctx, byte[] data) {
if (data.length == 0) {
return;
}
processPacket(ctx, new BinaryStream(data));
}
private void processPacket(ChannelHandlerContext ctx, BinaryStream stream) {
//System.out.println(stream);
for (MPQClient client : clients) {
if (client.is((InetSocketAddress) ctx.channel().remoteAddress())) {
client.getFrame().getScheduler().addTask(() -> {
try {
client.dataReceive(stream);
} catch (Exception e) {
e.printStackTrace();
}
});
return;
}
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (cause instanceof IOException) { //远程主机强迫关闭了一个现有的连接
return;
}
super.exceptionCaught(ctx, cause);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx);
FrameConnectionEvent event = null;
for (MPQClient client : clients) {
if (client.is((InetSocketAddress) ctx.channel().remoteAddress())) {
event = new FrameConnectionEvent(client.getFrame());
client.setAddress((InetSocketAddress) ctx.channel().remoteAddress());
client.setCtx(ctx);
break;
}
}
if (event == null) {
Frame frame = new Frame(getJPREMain());
MPQClient client = new MPQClient(frame, (InetSocketAddress) ctx.channel().remoteAddress(), ctx);
clients.add(client);
event = new FrameConnectionEvent(frame);
}
event.getFrame().getPluginManager().callEvent(event);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("[Network] RemoteClient: " + ctx.channel().remoteAddress() + " disconnected.");
for (MPQClient client : clients) {
if (client.is((InetSocketAddress) ctx.channel().remoteAddress())) {
FrameDisconnectionEvent event = new FrameDisconnectionEvent(client.getFrame());
client.getFrame().getPluginManager().callEvent(event);
break;
}
}
super.channelInactive(ctx);
}
}

View File

@ -92,6 +92,13 @@
<version>2.8.5</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/io.netty/netty-all -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.38.Final</version>
</dependency>
</dependencies>
</dependencyManagement>