Merge remote-tracking branch 'origin/master'

This commit is contained in:
liujiahua123123 2019-08-08 22:12:18 +08:00
commit 2eccc978f0
11 changed files with 293 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,8 @@
package net.mamoe.mirai.network;
/**
* @author Him188moe @ Mirai Project
*/
public class BinaryStream {
}

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

@ -0,0 +1,8 @@
package net.mamoe.mirai.network.packet;
/**
* @author Him188moe @ Mirai Project
*/
public interface Packet {
}

View File

@ -0,0 +1,11 @@
package net.mamoe.mirai.network.packet;
/**
* @author Him188moe @ Mirai Project
*/
public @interface PacketId {
/**
* 获取用于识别的包 ID
*/
int value();
}

View File

@ -0,0 +1,14 @@
package net.mamoe.mirai.network.packet.client;
import net.mamoe.mirai.network.packet.PacketId;
/**
* @author Him188moe @ Mirai Project
*/
@PacketId(5)
public class ClientLoginPacket extends ClientPacket {
@Override
public void encode() {
}
}

View File

@ -0,0 +1,24 @@
package net.mamoe.mirai.network.packet.client;
import net.mamoe.mirai.network.packet.Packet;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
/**
* @author Him188moe @ Mirai Project
*/
public abstract class ClientPacket extends DataOutputStream implements Packet {
public ClientPacket() {
super(new ByteArrayOutputStream());
}
protected void writeQQHex(long qq) {
this.write
}
/**
* Encode this packet
*/
public abstract void encode();
}

View File

@ -0,0 +1,23 @@
package net.mamoe.mirai.network.packet.server;
import net.mamoe.mirai.network.packet.Packet;
import org.jetbrains.annotations.NotNull;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.InputStream;
/**
* @author Him188moe @ Mirai Project
*/
public abstract class ServerPacket extends DataInputStream implements Packet {
public ServerPacket(@NotNull InputStream in) {
super(in);
}
public ServerPacket(@NotNull byte[] in) {
this(new ByteArrayInputStream(in));
}
public abstract void decode();
}

View File

@ -0,0 +1,10 @@
/**
* @author Him188moe @ Mirai Project
*/
public class NetworkTest {
public static void main(String[] args) {
Long.valueOf("", 16);
}
}

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>