mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-01 09:28:21 +08:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
2eccc978f0
@ -38,6 +38,13 @@
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-all</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
<resources>
|
||||
|
@ -0,0 +1,8 @@
|
||||
package net.mamoe.mirai.network;
|
||||
|
||||
/**
|
||||
* @author Him188moe @ Mirai Project
|
||||
*/
|
||||
public class BinaryStream {
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package net.mamoe.mirai.network.packet;
|
||||
|
||||
/**
|
||||
* @author Him188moe @ Mirai Project
|
||||
*/
|
||||
public interface Packet {
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package net.mamoe.mirai.network.packet;
|
||||
|
||||
/**
|
||||
* @author Him188moe @ Mirai Project
|
||||
*/
|
||||
public @interface PacketId {
|
||||
/**
|
||||
* 获取用于识别的包 ID
|
||||
*/
|
||||
int value();
|
||||
}
|
@ -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() {
|
||||
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
@ -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();
|
||||
}
|
10
mirai-core/src/test/java/NetworkTest.java
Normal file
10
mirai-core/src/test/java/NetworkTest.java
Normal file
@ -0,0 +1,10 @@
|
||||
/**
|
||||
* @author Him188moe @ Mirai Project
|
||||
*/
|
||||
public class NetworkTest {
|
||||
public static void main(String[] args) {
|
||||
|
||||
|
||||
Long.valueOf("", 16);
|
||||
}
|
||||
}
|
7
pom.xml
7
pom.xml
@ -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>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user