Archived
0

MCSM: Сервер управления серверами minecraft

This commit is contained in:
2017-04-27 04:57:33 +03:00
parent b442d6afa3
commit 2117b440ff
14 changed files with 413 additions and 4 deletions

View File

@@ -1,16 +1,31 @@
group = 'asys' group = 'asys'
version = '0.3-SNAPSHOT' version = '0.4-SNAPSHOT'
apply plugin: 'osgi' apply plugin: 'osgi'
configurations {
included
compile.extendsFrom included
}
jar { jar {
dependsOn configurations.included
manifest { manifest {
name = 'ASys MC server manager' name = 'ASys MC server manager'
instruction 'Bundle-Activator', 'asys.mcsmanager.Activator' instruction 'Bundle-Activator', 'asys.mcsmanager.Activator'
instruction 'Import-Package', '!io.netty.*', 'javax.security.cert', 'org.slf4j.helpers', '*'
} }
from { configurations.included.collect { it.isDirectory() ? it : zipTree(it).matching{exclude{it.path.contains('META-INF')} } } }
}
ext {
nettyVersion = '4.1.9.Final'
} }
dependencies { dependencies {
compile project(':core') compile project(':core')
compile project(':webinterface') compile project(':webinterface')
included group: 'io.netty', name: 'netty-codec', version: nettyVersion
} }

View File

@@ -4,6 +4,7 @@
*/ */
package asys.mcsmanager; package asys.mcsmanager;
import asys.mcsmanager.server.Server;
import asys.webinterface.api.Webinterface; import asys.webinterface.api.Webinterface;
import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext; import org.osgi.framework.BundleContext;
@@ -18,25 +19,32 @@ public class Activator implements BundleActivator, ServiceListener {
private ServiceTracker<?, Webinterface> serviceTracker; private ServiceTracker<?, Webinterface> serviceTracker;
private MCSM_WebModule module; private MCSM_WebModule module;
private Webinterface webinterface; private Webinterface webinterface;
private Server serverManager;
@Override @Override
public void start(BundleContext context) throws Exception { public void start(BundleContext context) throws Exception {
module = new MCSM_WebModule(); module = new MCSM_WebModule();
logger.debug("Get service: {}", Webinterface.class);
serviceTracker = new ServiceTracker<>(context, Webinterface.class, null);
logger.debug("Register service listener"); logger.debug("Register service listener");
context.addServiceListener(this); context.addServiceListener(this);
logger.debug("Get service: {}", Webinterface.class); logger.debug("Start server manager: {}:{}", "127.0.0.1", 8779);
serviceTracker = new ServiceTracker<>(context, Webinterface.class, null); serverManager = new Server();
serverManager.start("127.0.0.1", 8779);
} }
@Override @Override
public void stop(BundleContext context) throws Exception { public void stop(BundleContext context) throws Exception {
serverManager.shutdown();
if (webinterface != null) { if (webinterface != null) {
webinterface.removeModule(module.getName()); webinterface.removeModule(module.getName());
} }
serviceTracker.close();
context.removeServiceListener(this); context.removeServiceListener(this);
serviceTracker.close();
} }
@Override @Override

View File

@@ -0,0 +1,40 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2017-04-26
*/
package asys.mcsmanager.packets;
import io.netty.buffer.ByteBuf;
public class CS_Handshake extends Packet {
private String clientId;
private String passcode;
public CS_Handshake() {
}
public CS_Handshake(String clientId, String passcode) {
this.clientId = clientId;
this.passcode = passcode;
}
public String getClientId() {
return clientId;
}
public String getPasscode() {
return passcode;
}
@Override
public void readSelfData(ByteBuf buffer) {
this.clientId = this.readString(buffer);
this.passcode = this.readString(buffer);
}
@Override
public void writeSelfData(ByteBuf buffer) {
this.writeString(buffer, clientId);
this.writeString(buffer, passcode);
}
}

View File

@@ -0,0 +1,48 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2017-04-26
*/
package asys.mcsmanager.packets;
import io.netty.buffer.ByteBuf;
public class CS_Ping extends Packet {
private long time;
private int tps;
private int countPlayers;
public CS_Ping() {
}
public CS_Ping(long time, int tps, int countPlayers) {
this.time = time;
this.tps = tps;
this.countPlayers = countPlayers;
}
public long getTime() {
return time;
}
public int getTps() {
return tps;
}
public int getCountPlayers() {
return countPlayers;
}
@Override
public void readSelfData(ByteBuf buffer) {
this.time = buffer.readLong();
this.tps = buffer.readUnsignedByte();
this.countPlayers = buffer.readUnsignedShort();
}
@Override
public void writeSelfData(ByteBuf buffer) {
buffer.writeLong(time);
buffer.writeByte(tps);
buffer.writeShort(countPlayers);
}
}

View File

@@ -0,0 +1,11 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2017-04-26
*/
package asys.mcsmanager.packets;
import io.netty.channel.ChannelHandlerContext;
public interface IPacketHandler {
void handle(Packet packet, ChannelHandlerContext context);
}

View File

@@ -0,0 +1,34 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2017-04-26
*/
package asys.mcsmanager.packets;
import io.netty.buffer.ByteBuf;
public abstract class Packet {
public String readString(ByteBuf buffer) {
int length = buffer.readUnsignedShort();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++) {
sb.append(buffer.readChar());
}
return sb.toString();
}
public void writeString(ByteBuf buffer, String string) {
int length = string.length();
buffer.writeShort(length);
if (length > 0) {
for (int i = 0; i < length; i++) {
buffer.writeChar(string.charAt(i));
}
}
}
public abstract void readSelfData(ByteBuf buffer);
public abstract void writeSelfData(ByteBuf buffer);
}

View File

@@ -0,0 +1,40 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2017-04-26
*/
package asys.mcsmanager.packets;
import io.netty.buffer.ByteBuf;
public class SC_HandshakeResult extends Packet {
private int errorCode;
private String message;
public SC_HandshakeResult() {
}
public SC_HandshakeResult(int errorCode, String message) {
this.errorCode = errorCode;
this.message = message;
}
public int getErrorCode() {
return errorCode;
}
public String getMessage() {
return message;
}
@Override
public void readSelfData(ByteBuf buffer) {
this.errorCode = buffer.readUnsignedByte();
this.message = this.readString(buffer);
}
@Override
public void writeSelfData(ByteBuf buffer) {
buffer.writeByte(errorCode);
this.writeString(buffer, message);
}
}

View File

@@ -0,0 +1,30 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2017-04-26
*/
package asys.mcsmanager.packets.codec;
import asys.mcsmanager.packets.Packet;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ReplayingDecoder;
import java.util.List;
import static asys.mcsmanager.packets.codec.Params.KNOWN_HANDLERS;
import static asys.mcsmanager.packets.codec.Params.KNOWN_PACKETS;
public class PacketDecoder extends ReplayingDecoder<Packet> {
@Override
protected void decode(ChannelHandlerContext contect, ByteBuf inBuf, List<Object> out) throws Exception {
int id = inBuf.readUnsignedByte();
Class<? extends Packet> pktClass = contect.channel().attr(KNOWN_PACKETS).get().get(id);
if (pktClass == null) return;
if (contect.channel().attr(KNOWN_HANDLERS).get().containsKey(pktClass)) {
Packet packet = pktClass.newInstance();
packet.readSelfData(inBuf);
out.add(packet);
}
}
}

View File

@@ -0,0 +1,23 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2017-04-26
*/
package asys.mcsmanager.packets.codec;
import asys.mcsmanager.packets.Packet;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import static asys.mcsmanager.packets.codec.Params.KNOWN_PACKETS;
public class PacketEncoder extends MessageToByteEncoder<Packet> {
@Override
protected void encode(ChannelHandlerContext context, Packet packet, ByteBuf outBuf) throws Exception {
Integer id = context.channel().attr(KNOWN_PACKETS).get().inverse().get(packet.getClass());
if (id == null) return; //TODO в логгере хорошо бы информировать о дропе исходящего пакета
outBuf.writeByte(id);
packet.writeSelfData(outBuf);
}
}

View File

@@ -0,0 +1,18 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2017-04-26
*/
package asys.mcsmanager.packets.codec;
import asys.mcsmanager.packets.Packet;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import static asys.mcsmanager.packets.codec.Params.KNOWN_HANDLERS;
public class PacketHandler extends SimpleChannelInboundHandler<Packet> {
@Override
protected void channelRead0(ChannelHandlerContext context, Packet packet) throws Exception {
context.channel().attr(KNOWN_HANDLERS).get().get(packet.getClass()).handle(packet, context);
}
}

View File

@@ -0,0 +1,17 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2017-04-26
*/
package asys.mcsmanager.packets.codec;
import asys.mcsmanager.packets.Packet;
import asys.mcsmanager.packets.IPacketHandler;
import com.google.common.collect.BiMap;
import io.netty.util.AttributeKey;
import java.util.Map;
public final class Params {
public static final AttributeKey<BiMap<Integer, Class<? extends Packet>>> KNOWN_PACKETS = AttributeKey.newInstance("KNOWN_PACKETS");
public static final AttributeKey<Map<Class<? extends Packet>, IPacketHandler>> KNOWN_HANDLERS = AttributeKey.newInstance("KNOWN_HANDLERS");
}

View File

@@ -0,0 +1,12 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2017-04-26
*/
package asys.mcsmanager.server;
import asys.mcsmanager.packets.SC_HandshakeResult;
abstract class HandshakeResult {
static final SC_HandshakeResult OK = new SC_HandshakeResult(0, "OK");
static final SC_HandshakeResult INVALID_PASSCODE = new SC_HandshakeResult(1, "Invalid passcode");
}

View File

@@ -0,0 +1,67 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2017-04-26
*/
package asys.mcsmanager.server;
import asys.mcsmanager.packets.CS_Ping;
import asys.mcsmanager.packets.Packet;
import asys.mcsmanager.packets.codec.PacketDecoder;
import asys.mcsmanager.packets.codec.PacketEncoder;
import asys.mcsmanager.packets.codec.PacketHandler;
import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableBiMap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class Server {
public static final BiMap<Integer, Class<? extends Packet>> knownPackets = ImmutableBiMap.of(
1, CS_Ping.class
);
private EventLoopGroup bossGroup, workerGroup;
public void start(String host, int port) {
bossGroup = new NioEventLoopGroup(1);
workerGroup = new NioEventLoopGroup();
ServerBootstrap serverBootstrap = createServerBootstrap();
try {
serverBootstrap.bind(host, port).sync().channel().closeFuture().sync();
} catch (InterruptedException e) {
shutdown();
}
}
public void shutdown() {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
private ServerBootstrap createServerBootstrap() {
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(createChannelInitializer());
return bootstrap;
}
private ChannelInitializer createChannelInitializer() {
return new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(
new PacketEncoder(),
new PacketDecoder(),
new PacketHandler(),
new ServerPacketHandler()
);
}
};
}
}

View File

@@ -0,0 +1,46 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2017-04-26
*/
package asys.mcsmanager.server;
import asys.mcsmanager.packets.CS_Handshake;
import asys.mcsmanager.packets.IPacketHandler;
import asys.mcsmanager.packets.Packet;
import asys.mcsmanager.packets.SC_HandshakeResult;
import asys.mcsmanager.packets.codec.Params;
import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableBiMap;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
class ServerPacketHandler extends ChannelInboundHandlerAdapter implements IPacketHandler {
private static final BiMap<Integer, Class<? extends Packet>> handshakePackets = ImmutableBiMap.of(
1, CS_Handshake.class,
2, SC_HandshakeResult.class
);
private static final String PASSCODE = "testpassphrase";
@Override
public void channelActive(ChannelHandlerContext context) throws Exception {
context.channel().attr(Params.KNOWN_PACKETS).set(handshakePackets);
super.channelActive(context);
}
@Override
public void handle(Packet packet, ChannelHandlerContext context) {
if (packet.getClass() == CS_Handshake.class) handleCSHandshake((CS_Handshake) packet, context);
}
private void handleCSHandshake(CS_Handshake packet, ChannelHandlerContext context) {
if (!packet.getPasscode().equalsIgnoreCase(PASSCODE)) {
try {
context.channel().writeAndFlush(HandshakeResult.INVALID_PASSCODE).sync().channel().close();
} catch (InterruptedException ignore) {
// ignore
}
} else {
context.channel().writeAndFlush(HandshakeResult.OK);
}
}
}