Merge branch 'dev-webconsole' into dev-zond
# Conflicts: # bridge/build.gradle # bridge/src/main/java/asys/bridge/bukkit/BridgePlugin.java # bridge/src/main/java/asys/bridge/client/ClientPacketHandler.java
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
group = 'asys'
|
group = 'asys'
|
||||||
version = '0.4-SNAPSHOT'
|
version = '0.5-SNAPSHOT'
|
||||||
|
|
||||||
task jar(type: Jar, overwrite: true) {
|
task jar(type: Jar, overwrite: true) {
|
||||||
// не собирать jar
|
// не собирать jar
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* DmitriyMX <dimon550@gmail.com>
|
||||||
|
* 2017-06-11
|
||||||
|
*/
|
||||||
|
package asys.mcsmanager.packets;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
|
||||||
|
public class SC_ToggleSendMessages extends Packet {
|
||||||
|
private boolean needSend;
|
||||||
|
|
||||||
|
public SC_ToggleSendMessages() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public SC_ToggleSendMessages(boolean needSend) {
|
||||||
|
this.needSend = needSend;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isNeedSend() {
|
||||||
|
return needSend;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readSelfData(ByteBuf buffer) {
|
||||||
|
needSend = (buffer.readUnsignedByte() == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeSelfData(ByteBuf buffer) {
|
||||||
|
buffer.writeByte(needSend ? 1 : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
group = 'asys'
|
group = 'asys'
|
||||||
version = '0.7-SNAPSHOT'
|
version = '0.8-SNAPSHOT'
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
maven { url 'https://hub.spigotmc.org/nexus/content/groups/public/' }
|
maven { url 'https://hub.spigotmc.org/nexus/content/groups/public/' }
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* DmitriyMX <d.mihailov@samson-rus.com>
|
||||||
|
* 2017-05-17
|
||||||
|
*/
|
||||||
|
package asys.bridge.bukkit;
|
||||||
|
|
||||||
|
import asys.bridge.client.AbstractBridge;
|
||||||
|
import asys.bridge.client.IBridge;
|
||||||
|
import asys.bridge.client.IConfig;
|
||||||
|
import asys.bridge.client.ILogger;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import org.apache.logging.log4j.LogManager;
|
||||||
|
import org.apache.logging.log4j.core.Logger;
|
||||||
|
|
||||||
|
public class BridgeBukkitImpl extends AbstractBridge implements IBridge {
|
||||||
|
private BridgePlugin plugin;
|
||||||
|
private LoggerBukkitImpl logger;
|
||||||
|
private ConfigBukkitImpl configBukkit;
|
||||||
|
|
||||||
|
public BridgeBukkitImpl(BridgePlugin plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.logger = new LoggerBukkitImpl(plugin.getLogger());
|
||||||
|
this.configBukkit = new ConfigBukkitImpl(plugin.getConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ILogger getLogger() {
|
||||||
|
return logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IConfig getConfig() {
|
||||||
|
return configBukkit;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCountOnlinePlayers() {
|
||||||
|
return plugin.getServer().getOnlinePlayers().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispatchCommand(String command) {
|
||||||
|
plugin.getServer().dispatchCommand(
|
||||||
|
plugin.getServer().getConsoleSender(),
|
||||||
|
command
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,44 +4,26 @@
|
|||||||
*/
|
*/
|
||||||
package asys.bridge.bukkit;
|
package asys.bridge.bukkit;
|
||||||
|
|
||||||
import asys.bridge.client.Client;
|
|
||||||
import asys.mcsmanager.packets.CS_Ping;
|
|
||||||
import io.netty.channel.Channel;
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.core.Logger;
|
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
public class BridgePlugin extends JavaPlugin {
|
public class BridgePlugin extends JavaPlugin {
|
||||||
public static BridgePlugin INSTANCE;
|
private BridgeBukkitImpl bridgeBukkit;
|
||||||
private Client client;
|
|
||||||
private TaskTicker connectTicker, pingTicker;
|
|
||||||
private int tryConnect = 0;
|
|
||||||
private boolean needReconnect = true;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onLoad() {
|
||||||
if (INSTANCE == null) {
|
|
||||||
INSTANCE = this;
|
|
||||||
saveDefaultConfig();
|
saveDefaultConfig();
|
||||||
|
this.bridgeBukkit = new BridgeBukkitImpl(this);
|
||||||
startReconnect();
|
this.bridgeBukkit.startReconnect();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
setNeedReconnect(false);
|
this.bridgeBukkit.setNeedReconnect(false);
|
||||||
stopReconnect();
|
this.bridgeBukkit.stopPing();
|
||||||
stopPing();
|
this.bridgeBukkit.stopReconnect();
|
||||||
|
this.bridgeBukkit.disconnect();
|
||||||
if (client.isConnected()) {
|
|
||||||
getLogger().info("Disconnect...");
|
|
||||||
client.disconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
INSTANCE = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -49,65 +31,4 @@ public class BridgePlugin extends JavaPlugin {
|
|||||||
sender.sendMessage("ASys Bridge by DmitriyMX");
|
sender.sendMessage("ASys Bridge by DmitriyMX");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startReconnect() {
|
|
||||||
client = new Client();
|
|
||||||
connectTicker = new TaskTicker().setStepTimeMs(5000L);
|
|
||||||
connectTicker.setTask(() -> {
|
|
||||||
getLogger().info(String.format("Connect(%d) to Zond...", ++tryConnect));
|
|
||||||
if (getConfig().getInt("mode") == 1) {
|
|
||||||
client.connect(getConfig().getString("host"), getConfig().getInt("port"));
|
|
||||||
} else {
|
|
||||||
client.connect("127.0.0.1", getConfig().getInt("port"));
|
|
||||||
}
|
|
||||||
if (client.isConnected()) {
|
|
||||||
stopReconnect();
|
|
||||||
} else {
|
|
||||||
getLogger().warning(
|
|
||||||
String.format("Connection(%d) fail. Try reconnect...", tryConnect));
|
|
||||||
}
|
|
||||||
}).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stopReconnect() {
|
|
||||||
if (connectTicker != null) {
|
|
||||||
connectTicker.stop();
|
|
||||||
tryConnect = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void startPing(Channel channel) {
|
|
||||||
pingTicker = new TaskTicker().setStepTimeMs(5000L);
|
|
||||||
pingTicker.setTask(() -> {
|
|
||||||
channel.write(new CS_Ping(
|
|
||||||
System.currentTimeMillis(),
|
|
||||||
20.0D, //FIXME
|
|
||||||
getServer().getOnlinePlayers().size()
|
|
||||||
));
|
|
||||||
if (channel.isWritable()) {
|
|
||||||
channel.flush();
|
|
||||||
} else {
|
|
||||||
getLogger().warning("Lost connection!");
|
|
||||||
channel.close();
|
|
||||||
stopPing();
|
|
||||||
|
|
||||||
getLogger().warning("Try reconnect...");
|
|
||||||
startReconnect();
|
|
||||||
}
|
|
||||||
}).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stopPing() {
|
|
||||||
if (pingTicker != null) {
|
|
||||||
pingTicker.stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isNeedReconnect() {
|
|
||||||
return needReconnect;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setNeedReconnect(boolean needReconnect) {
|
|
||||||
this.needReconnect = needReconnect;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* DmitriyMX <d.mihailov@samson-rus.com>
|
||||||
|
* 2017-05-17
|
||||||
|
*/
|
||||||
|
package asys.bridge.bukkit;
|
||||||
|
|
||||||
|
import asys.bridge.client.IConfig;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
|
||||||
|
public class ConfigBukkitImpl implements IConfig {
|
||||||
|
private FileConfiguration fileConfiguration;
|
||||||
|
|
||||||
|
public ConfigBukkitImpl(FileConfiguration fileConfiguration) {
|
||||||
|
this.fileConfiguration = fileConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getString(String path) {
|
||||||
|
return fileConfiguration.getString(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getInt(String path) {
|
||||||
|
return fileConfiguration.getInt(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* DmitriyMX <d.mihailov@samson-rus.com>
|
||||||
|
* 2017-05-17
|
||||||
|
*/
|
||||||
|
package asys.bridge.bukkit;
|
||||||
|
|
||||||
|
import asys.bridge.client.ILogger;
|
||||||
|
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
public class LoggerBukkitImpl implements ILogger {
|
||||||
|
private Logger logger;
|
||||||
|
|
||||||
|
LoggerBukkitImpl(Logger logger) {
|
||||||
|
this.logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void info(String string) {
|
||||||
|
logger.info(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void warn(String string) {
|
||||||
|
logger.warning(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void error(String string) {
|
||||||
|
logger.severe(string);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,23 +10,23 @@ public class TaskTicker implements Runnable {
|
|||||||
private Thread thread;
|
private Thread thread;
|
||||||
private boolean loop = false;
|
private boolean loop = false;
|
||||||
|
|
||||||
TaskTicker setTask(Runnable task) {
|
public TaskTicker setTask(Runnable task) {
|
||||||
this.task = task;
|
this.task = task;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskTicker setStepTimeMs(long stepTimeMs) {
|
public TaskTicker setStepTimeMs(long stepTimeMs) {
|
||||||
this.stepTimeMs = stepTimeMs;
|
this.stepTimeMs = stepTimeMs;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void start() {
|
public void start() {
|
||||||
thread = new Thread(this, "TaskTicker");
|
thread = new Thread(this, "TaskTicker");
|
||||||
loop = true;
|
loop = true;
|
||||||
thread.start();
|
thread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void stop() {
|
public void stop() {
|
||||||
loop = false;
|
loop = false;
|
||||||
if (thread != null) {
|
if (thread != null) {
|
||||||
thread.interrupt();
|
thread.interrupt();
|
||||||
|
|||||||
86
bridge/src/main/java/asys/bridge/client/AbstractBridge.java
Normal file
86
bridge/src/main/java/asys/bridge/client/AbstractBridge.java
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* DmitriyMX <d.mihailov@samson-rus.com>
|
||||||
|
* 2017-05-17
|
||||||
|
*/
|
||||||
|
package asys.bridge.client;
|
||||||
|
|
||||||
|
import asys.bridge.bukkit.TaskTicker;
|
||||||
|
import asys.mcsmanager.packets.CS_Ping;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
|
||||||
|
public abstract class AbstractBridge implements IBridge {
|
||||||
|
private Client client;
|
||||||
|
private TaskTicker connectTicker, pingTicker;
|
||||||
|
private int tryConnect = 0;
|
||||||
|
private boolean needReconnect = true;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startReconnect() {
|
||||||
|
client = new Client(this);
|
||||||
|
connectTicker = new TaskTicker().setStepTimeMs(5000L);
|
||||||
|
connectTicker.setTask(() -> {
|
||||||
|
getLogger().info(String.format("Connect(%d) to Zond...", ++tryConnect));
|
||||||
|
client.connect(getConfig().getString("host"), getConfig().getInt("port"));
|
||||||
|
if (client.isConnected()) {
|
||||||
|
stopReconnect();
|
||||||
|
} else {
|
||||||
|
getLogger().warn(String.format("Connection(%d) fail. Try reconnect...", tryConnect));
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isNeedReconnect() {
|
||||||
|
return needReconnect;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setNeedReconnect(boolean value) {
|
||||||
|
this.needReconnect = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stopReconnect() {
|
||||||
|
if (connectTicker != null) {
|
||||||
|
connectTicker.stop();
|
||||||
|
tryConnect = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startPing(Channel channel) {
|
||||||
|
pingTicker = new TaskTicker().setStepTimeMs(5000L);
|
||||||
|
pingTicker.setTask(() -> {
|
||||||
|
channel.write(new CS_Ping(
|
||||||
|
System.currentTimeMillis(),
|
||||||
|
20.0D, //FIXME fake tps
|
||||||
|
getCountOnlinePlayers()
|
||||||
|
));
|
||||||
|
if (channel.isWritable()) {
|
||||||
|
channel.flush();
|
||||||
|
} else {
|
||||||
|
getLogger().warn("Lost connection!");
|
||||||
|
channel.close();
|
||||||
|
stopPing();
|
||||||
|
|
||||||
|
getLogger().warn("Try reconnect...");
|
||||||
|
startReconnect();
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stopPing() {
|
||||||
|
if (pingTicker != null) {
|
||||||
|
pingTicker.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void disconnect() {
|
||||||
|
if (client.isConnected()) {
|
||||||
|
getLogger().info("Disconnect...");
|
||||||
|
client.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,6 +19,11 @@ public class Client {
|
|||||||
private EventLoopGroup group;
|
private EventLoopGroup group;
|
||||||
private Bootstrap bootstrap;
|
private Bootstrap bootstrap;
|
||||||
private ChannelFuture channelFuture;
|
private ChannelFuture channelFuture;
|
||||||
|
private IBridge bridge;
|
||||||
|
|
||||||
|
public Client(IBridge bridge) {
|
||||||
|
this.bridge = bridge;
|
||||||
|
}
|
||||||
|
|
||||||
public void connect(String host, int port) {
|
public void connect(String host, int port) {
|
||||||
if (group == null || bootstrap == null) {
|
if (group == null || bootstrap == null) {
|
||||||
@@ -55,7 +60,7 @@ public class Client {
|
|||||||
new PacketEncoder(),
|
new PacketEncoder(),
|
||||||
new PacketDecoder(),
|
new PacketDecoder(),
|
||||||
new PacketHandler(),
|
new PacketHandler(),
|
||||||
new ClientPacketHandler()
|
new ClientPacketHandler(bridge)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
*/
|
*/
|
||||||
package asys.bridge.client;
|
package asys.bridge.client;
|
||||||
|
|
||||||
import asys.bridge.bukkit.BridgePlugin;
|
|
||||||
import asys.mcsmanager.packets.*;
|
import asys.mcsmanager.packets.*;
|
||||||
import com.google.common.collect.BiMap;
|
import com.google.common.collect.BiMap;
|
||||||
import com.google.common.collect.ImmutableBiMap;
|
import com.google.common.collect.ImmutableBiMap;
|
||||||
@@ -18,22 +17,18 @@ import static asys.mcsmanager.packets.codec.Params.KNOWN_HANDLERS;
|
|||||||
import static asys.mcsmanager.packets.codec.Params.KNOWN_PACKETS;
|
import static asys.mcsmanager.packets.codec.Params.KNOWN_PACKETS;
|
||||||
|
|
||||||
public class ClientPacketHandler extends ChannelInboundHandlerAdapter implements IPacketHandler {
|
public class ClientPacketHandler extends ChannelInboundHandlerAdapter implements IPacketHandler {
|
||||||
private static final BiMap<Integer, Class<? extends Packet>> handshakePackets = ImmutableBiMap.of(
|
private static Map<Class<? extends Packet>, IPacketHandler> knownHandlers;
|
||||||
1, CS_Handshake.class,
|
|
||||||
2, SC_HandshakeResult.class
|
|
||||||
);
|
|
||||||
private static Map<Class<? extends Packet>, IPacketHandler> handshakeHandlers;
|
|
||||||
|
|
||||||
private static final BiMap<Integer, Class<? extends Packet>> pingPackets = ImmutableBiMap.of(
|
private static final BiMap<Integer, Class<? extends Packet>> knownPackets = ImmutableBiMap.of(
|
||||||
3, CS_Ping.class,
|
3, CS_Ping.class,
|
||||||
4, CS_ConsoleMessage.class,
|
|
||||||
5, SC_Command.class
|
5, SC_Command.class
|
||||||
);
|
);
|
||||||
|
private IBridge bridge;
|
||||||
|
|
||||||
ClientPacketHandler() {
|
ClientPacketHandler(IBridge bridge) {
|
||||||
if (handshakeHandlers == null) {
|
this.bridge = bridge;
|
||||||
handshakeHandlers = ImmutableMap.of(
|
if (knownHandlers == null) {
|
||||||
SC_HandshakeResult.class, this,
|
knownHandlers = ImmutableMap.of(
|
||||||
SC_Command.class, this
|
SC_Command.class, this
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -41,33 +36,18 @@ public class ClientPacketHandler extends ChannelInboundHandlerAdapter implements
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void channelActive(ChannelHandlerContext context) throws Exception {
|
public void channelActive(ChannelHandlerContext context) throws Exception {
|
||||||
BridgePlugin.INSTANCE.getLogger().info("channelActive");
|
bridge.getLogger().info("channelActive");
|
||||||
if (BridgePlugin.INSTANCE.getConfig().getInt("mode") == 1) {
|
context.channel().attr(KNOWN_PACKETS).set(knownPackets);
|
||||||
context.channel().attr(KNOWN_PACKETS).set(handshakePackets);
|
context.channel().attr(KNOWN_HANDLERS).set(knownHandlers);
|
||||||
context.channel().attr(KNOWN_HANDLERS).set(handshakeHandlers);
|
|
||||||
|
|
||||||
|
|
||||||
CS_Handshake packet = new CS_Handshake(
|
|
||||||
BridgePlugin.INSTANCE.getConfig().getString("clientId"),
|
|
||||||
BridgePlugin.INSTANCE.getConfig().getString("passcode"));
|
|
||||||
BridgePlugin.INSTANCE.getLogger().info("send Handshake packet...");
|
|
||||||
context.channel().writeAndFlush(packet);
|
|
||||||
} else {
|
|
||||||
context.channel().attr(KNOWN_PACKETS).set(pingPackets);
|
|
||||||
BridgePlugin.INSTANCE.getLogger().info("Handshake: SKIP. Used Zond.");
|
|
||||||
BridgePlugin.INSTANCE.startPing(context.channel());
|
|
||||||
}
|
|
||||||
super.channelActive(context);
|
super.channelActive(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void channelInactive(ChannelHandlerContext context) throws Exception {
|
public void channelInactive(ChannelHandlerContext context) throws Exception {
|
||||||
if (BridgePlugin.INSTANCE != null) {
|
bridge.stopPing();
|
||||||
BridgePlugin.INSTANCE.stopPing();
|
if (bridge.isNeedReconnect()) {
|
||||||
if (BridgePlugin.INSTANCE.isNeedReconnect()) {
|
bridge.getLogger().warn("Lost connection! Try reconnect...");
|
||||||
BridgePlugin.INSTANCE.getLogger().warning("Lost connection! Try reconnect...");
|
bridge.startReconnect();
|
||||||
BridgePlugin.INSTANCE.startReconnect();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
context.channel().attr(KNOWN_PACKETS).remove();
|
context.channel().attr(KNOWN_PACKETS).remove();
|
||||||
context.channel().attr(KNOWN_HANDLERS).remove();
|
context.channel().attr(KNOWN_HANDLERS).remove();
|
||||||
@@ -76,33 +56,14 @@ public class ClientPacketHandler extends ChannelInboundHandlerAdapter implements
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(Packet packet, ChannelHandlerContext context) {
|
public void handle(Packet packet, ChannelHandlerContext context) {
|
||||||
BridgePlugin.INSTANCE.getLogger().info("handle : " + packet.getClass().getSimpleName());
|
bridge.getLogger().info("handle : " + packet.getClass().getSimpleName());
|
||||||
if (packet instanceof SC_HandshakeResult) {
|
if (packet instanceof SC_Command) {
|
||||||
if (BridgePlugin.INSTANCE.getConfig().getInt("mode") == 1) {
|
|
||||||
handleHandshakeResult((SC_HandshakeResult) packet, context);
|
|
||||||
}
|
|
||||||
} else if (packet instanceof SC_Command) {
|
|
||||||
handleCommand((SC_Command) packet);
|
handleCommand((SC_Command) packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleHandshakeResult(SC_HandshakeResult packet, ChannelHandlerContext context) {
|
|
||||||
if (packet.getErrorCode() != 0) {
|
|
||||||
BridgePlugin.INSTANCE.getLogger().severe(
|
|
||||||
String.format("Handshake: #%d %s", packet.getErrorCode(), packet.getMessage()));
|
|
||||||
BridgePlugin.INSTANCE.setNeedReconnect(false);
|
|
||||||
} else {
|
|
||||||
context.channel().attr(KNOWN_PACKETS).set(pingPackets);
|
|
||||||
BridgePlugin.INSTANCE.getLogger().info("Handshake: OK");
|
|
||||||
BridgePlugin.INSTANCE.startPing(context.channel());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleCommand(SC_Command packet) {
|
private void handleCommand(SC_Command packet) {
|
||||||
BridgePlugin.INSTANCE.getLogger().info("Command: " + packet.getCommand());
|
bridge.getLogger().info("Command: " + packet.getCommand());
|
||||||
BridgePlugin.INSTANCE.getServer().dispatchCommand(
|
bridge.dispatchCommand(packet.getCommand());
|
||||||
BridgePlugin.INSTANCE.getServer().getConsoleSender(),
|
|
||||||
packet.getCommand()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
21
bridge/src/main/java/asys/bridge/client/IBridge.java
Normal file
21
bridge/src/main/java/asys/bridge/client/IBridge.java
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* DmitriyMX <d.mihailov@samson-rus.com>
|
||||||
|
* 2017-05-17
|
||||||
|
*/
|
||||||
|
package asys.bridge.client;
|
||||||
|
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
|
||||||
|
public interface IBridge {
|
||||||
|
ILogger getLogger();
|
||||||
|
IConfig getConfig();
|
||||||
|
int getCountOnlinePlayers();
|
||||||
|
void dispatchCommand(String command);
|
||||||
|
void startReconnect();
|
||||||
|
boolean isNeedReconnect();
|
||||||
|
void setNeedReconnect(boolean value);
|
||||||
|
void stopReconnect();
|
||||||
|
void startPing(Channel channel);
|
||||||
|
void stopPing();
|
||||||
|
void disconnect();
|
||||||
|
}
|
||||||
10
bridge/src/main/java/asys/bridge/client/IConfig.java
Normal file
10
bridge/src/main/java/asys/bridge/client/IConfig.java
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
/*
|
||||||
|
* DmitriyMX <d.mihailov@samson-rus.com>
|
||||||
|
* 2017-05-17
|
||||||
|
*/
|
||||||
|
package asys.bridge.client;
|
||||||
|
|
||||||
|
public interface IConfig {
|
||||||
|
String getString(String path);
|
||||||
|
int getInt(String path);
|
||||||
|
}
|
||||||
11
bridge/src/main/java/asys/bridge/client/ILogger.java
Normal file
11
bridge/src/main/java/asys/bridge/client/ILogger.java
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* DmitriyMX <d.mihailov@samson-rus.com>
|
||||||
|
* 2017-05-17
|
||||||
|
*/
|
||||||
|
package asys.bridge.client;
|
||||||
|
|
||||||
|
public interface ILogger {
|
||||||
|
void info(String string);
|
||||||
|
void warn(String string);
|
||||||
|
void error(String string);
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
group = 'asys'
|
group = 'asys'
|
||||||
version = '0.8.13-SNAPSHOT'
|
version = '0.10.4-SNAPSHOT'
|
||||||
|
|
||||||
apply plugin: 'osgi'
|
apply plugin: 'osgi'
|
||||||
|
|
||||||
@@ -8,6 +8,10 @@ configurations {
|
|||||||
compile.extendsFrom include
|
compile.extendsFrom include
|
||||||
}
|
}
|
||||||
|
|
||||||
|
compileJava {
|
||||||
|
dependsOn ':bridge-protocol:compileJava'
|
||||||
|
}
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
manifest {
|
manifest {
|
||||||
name = 'ASys MC server manager'
|
name = 'ASys MC server manager'
|
||||||
|
|||||||
@@ -29,9 +29,7 @@ public class Activator implements BundleActivator, ServiceListener {
|
|||||||
Config config = serviceConfigTracker.getService();
|
Config config = serviceConfigTracker.getService();
|
||||||
if (config == null) throw new RuntimeException("Service 'Config' is not avalable!");
|
if (config == null) throw new RuntimeException("Service 'Config' is not avalable!");
|
||||||
|
|
||||||
Manager manager = new Manager();
|
module = new MCSM_WebModule();
|
||||||
|
|
||||||
module = new MCSM_WebModule(manager);
|
|
||||||
|
|
||||||
logger.debug("Get service: {}", Webinterface.class);
|
logger.debug("Get service: {}", Webinterface.class);
|
||||||
serviceTracker = new ServiceTracker<>(context, Webinterface.class, null);
|
serviceTracker = new ServiceTracker<>(context, Webinterface.class, null);
|
||||||
@@ -44,13 +42,13 @@ public class Activator implements BundleActivator, ServiceListener {
|
|||||||
String passcode = config.getString("asys.mcsmanager.passcode", "testpasscode");
|
String passcode = config.getString("asys.mcsmanager.passcode", "testpasscode");
|
||||||
logger.debug("Start server manager: {}:{}", host, port);
|
logger.debug("Start server manager: {}:{}", host, port);
|
||||||
serverManager = new asys.mcsmanager.server.Server();
|
serverManager = new asys.mcsmanager.server.Server();
|
||||||
serverManager.start(host, port, passcode, manager);
|
serverManager.start(host, port, passcode);
|
||||||
|
|
||||||
host = config.getString("asys.mcsmanager.webconsole.host", "127.0.0.1");
|
host = config.getString("asys.mcsmanager.webconsole.host", "127.0.0.1");
|
||||||
port = config.getInt("asys.mcsmanager.webconsole.port", 8770);
|
port = config.getInt("asys.mcsmanager.webconsole.port", 8770);
|
||||||
logger.debug("Start webconsole server: {}:{}", host, port);
|
logger.debug("Start webconsole server: {}:{}", host, port);
|
||||||
webconsoleServer = new asys.mcsmanager.websocket.Server();
|
webconsoleServer = new asys.mcsmanager.websocket.Server();
|
||||||
webconsoleServer.start(host, port, manager);
|
webconsoleServer.start(host, port);
|
||||||
|
|
||||||
serviceConfigTracker.close();
|
serviceConfigTracker.close();
|
||||||
}
|
}
|
||||||
@@ -82,7 +80,6 @@ public class Activator implements BundleActivator, ServiceListener {
|
|||||||
logger.debug("service not found =(");
|
logger.debug("service not found =(");
|
||||||
}
|
}
|
||||||
} catch (InterruptedException ignore) {
|
} catch (InterruptedException ignore) {
|
||||||
// ignore
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
84
mcserver-manager/src/main/java/asys/mcsmanager/Linker.java
Normal file
84
mcserver-manager/src/main/java/asys/mcsmanager/Linker.java
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* DmitriyMX <dimon550@gmail.com>
|
||||||
|
* 2017-05-01
|
||||||
|
*/
|
||||||
|
package asys.mcsmanager;
|
||||||
|
|
||||||
|
import asys.mcsmanager.packets.CS_ConsoleMessage;
|
||||||
|
import asys.mcsmanager.packets.SC_Command;
|
||||||
|
import asys.mcsmanager.packets.SC_ToggleSendMessages;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class Linker {
|
||||||
|
private static Linker instance = new Linker();
|
||||||
|
private Map<String, ServerInfo> serverMap = new HashMap<>();
|
||||||
|
private Map<String, List<Channel>> webconsoleListeners = new HashMap<>();
|
||||||
|
|
||||||
|
public static Linker getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Linker(){
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addServer(String serverName, Channel channel) {
|
||||||
|
this.serverMap.put(serverName, new ServerInfo(serverName, channel));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean existsServer(String serverName) {
|
||||||
|
return this.serverMap.containsKey(serverName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerInfo getServer(String serverName) {
|
||||||
|
return this.serverMap.get(serverName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> getServerList() {
|
||||||
|
return this.serverMap.keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeServer(String serverName) {
|
||||||
|
this.serverMap.remove(serverName);
|
||||||
|
if (this.webconsoleListeners.containsKey(serverName)) {
|
||||||
|
this.webconsoleListeners.get(serverName).forEach(Channel::close);
|
||||||
|
this.webconsoleListeners.remove(serverName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addWebconsoleListener(String serverName, Channel channel) {
|
||||||
|
List<Channel> channels = this.webconsoleListeners.computeIfAbsent(serverName, v -> new ArrayList<>());
|
||||||
|
if (channels.size() == 0) {
|
||||||
|
this.serverMap.get(serverName).getChannel().writeAndFlush(new SC_ToggleSendMessages(true));
|
||||||
|
}
|
||||||
|
channels.add(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeWebconsoleListener(String serverName, Channel channel) {
|
||||||
|
List<Channel> channels = this.webconsoleListeners.get(serverName);
|
||||||
|
channels.remove(channel);
|
||||||
|
if (channels.size() == 0) {
|
||||||
|
this.serverMap.get(serverName).getChannel().writeAndFlush(new SC_ToggleSendMessages(false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void broadcastConsoleMessage(String serverName, CS_ConsoleMessage packet) {
|
||||||
|
if (this.webconsoleListeners.containsKey(serverName)) {
|
||||||
|
this.webconsoleListeners.get(serverName).forEach(channel -> {
|
||||||
|
channel.writeAndFlush(new TextWebSocketFrame(String.format(
|
||||||
|
"[L:%d] %s",
|
||||||
|
packet.getLevel(),
|
||||||
|
packet.getMessage()
|
||||||
|
)));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendCommand(String serverName, String command) {
|
||||||
|
if (this.serverMap.containsKey(serverName)) {
|
||||||
|
this.serverMap.get(serverName).getChannel().writeAndFlush(new SC_Command(command));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,11 +27,6 @@ public class MCSM_WebModule extends WebModule {
|
|||||||
private final String MODULE_URL = "/"+MODULE_NAME;
|
private final String MODULE_URL = "/"+MODULE_NAME;
|
||||||
private final Pattern URL_PATTERN_JS = Pattern.compile(MODULE_URL+"/(\\w+)\\.js");
|
private final Pattern URL_PATTERN_JS = Pattern.compile(MODULE_URL+"/(\\w+)\\.js");
|
||||||
private final Pattern URL_PATTERN_CSS = Pattern.compile(MODULE_URL+"/(\\w+)\\.css");
|
private final Pattern URL_PATTERN_CSS = Pattern.compile(MODULE_URL+"/(\\w+)\\.css");
|
||||||
private Manager manager;
|
|
||||||
|
|
||||||
MCSM_WebModule(Manager manager) {
|
|
||||||
this.manager = manager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
@@ -89,7 +84,7 @@ public class MCSM_WebModule extends WebModule {
|
|||||||
if (httpExchange.getRequestURI().getQuery() != null &&
|
if (httpExchange.getRequestURI().getQuery() != null &&
|
||||||
!httpExchange.getRequestURI().getQuery().isEmpty()) {
|
!httpExchange.getRequestURI().getQuery().isEmpty()) {
|
||||||
Map<String, String> query = this.queryToMap(httpExchange.getRequestURI().getQuery());
|
Map<String, String> query = this.queryToMap(httpExchange.getRequestURI().getQuery());
|
||||||
ServerInfo serverInfo = manager.getInfo(query.get("clientid"));
|
ServerInfo serverInfo = Linker.getInstance().getServer(query.get("clientid"));
|
||||||
if (serverInfo == null) {
|
if (serverInfo == null) {
|
||||||
this.sendJson(httpExchange, "{}");
|
this.sendJson(httpExchange, "{}");
|
||||||
} else {
|
} else {
|
||||||
@@ -102,6 +97,6 @@ public class MCSM_WebModule extends WebModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private JsonElement serverList() {
|
private JsonElement serverList() {
|
||||||
return GSON.toJsonTree(manager.getServerList());
|
return GSON.toJsonTree(Linker.getInstance().getServerList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,96 +0,0 @@
|
|||||||
/*
|
|
||||||
* DmitriyMX <dimon550@gmail.com>
|
|
||||||
* 2017-05-01
|
|
||||||
*/
|
|
||||||
package asys.mcsmanager;
|
|
||||||
|
|
||||||
import asys.mcsmanager.packets.CS_ConsoleMessage;
|
|
||||||
import asys.mcsmanager.packets.CS_Ping;
|
|
||||||
import asys.mcsmanager.packets.SC_Command;
|
|
||||||
import io.netty.channel.Channel;
|
|
||||||
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class Manager {
|
|
||||||
private Logger logger = LoggerFactory.getLogger(Manager.class);
|
|
||||||
private Map<String, ServerInfo> serversMap = new HashMap<>();
|
|
||||||
private Map<String, Channel> serverChannels = new HashMap<>();
|
|
||||||
private List<Channel> webconsoleListener = new ArrayList<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Добавляем в список ClientID
|
|
||||||
* @param clientId id сервера. Чувствителен к регистру
|
|
||||||
* @return <code>false</code>, если сервер с таким id уже имеется
|
|
||||||
*/
|
|
||||||
public boolean addClientId(String clientId, Channel channel) {
|
|
||||||
if (serversMap.containsKey(clientId)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.debug("addClientId: {}", clientId);
|
|
||||||
serversMap.put(clientId, new ServerInfo(clientId));
|
|
||||||
serverChannels.put(clientId, channel);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeClientId(String clientId) {
|
|
||||||
if (clientId != null) {
|
|
||||||
serverChannels.remove(clientId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean sendCommand(String clientId, String command) {
|
|
||||||
/*
|
|
||||||
if (serverChannels.containsKey(clientId)) {
|
|
||||||
serverChannels.get(clientId).writeAndFlush(new SC_Command(command));
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
//FIXME временный костыль
|
|
||||||
Channel channel = serverChannels.entrySet().iterator().next().getValue();
|
|
||||||
channel.writeAndFlush(new SC_Command(command));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Дополнить информация о сервере.
|
|
||||||
* Если сервер отсутствует в списке, информация будет потеряна.
|
|
||||||
* @param clientId id сервера. Чувствителен к регистру
|
|
||||||
* @param pingPacket
|
|
||||||
*/
|
|
||||||
public void putInfo(String clientId, CS_Ping pingPacket) {
|
|
||||||
if (!serversMap.containsKey(clientId)) return;
|
|
||||||
serversMap.get(clientId).putPing(pingPacket);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<String> getServerList() {
|
|
||||||
return serversMap.keySet();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ServerInfo getInfo(String clientId) {
|
|
||||||
return serversMap.get(clientId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addWebConsoleListener(Channel channel) {
|
|
||||||
this.webconsoleListener.add(channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeWebConsoleListener(Channel channel) {
|
|
||||||
this.webconsoleListener.remove(channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void sendBroadcastToWebConsoleListeners(CS_ConsoleMessage message) {
|
|
||||||
for (Channel channel : this.webconsoleListener) {
|
|
||||||
channel.writeAndFlush(new TextWebSocketFrame(String.format(
|
|
||||||
"[L:%d] %s",
|
|
||||||
message.getLevel(),
|
|
||||||
message.getMessage()
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
package asys.mcsmanager;
|
package asys.mcsmanager;
|
||||||
|
|
||||||
import asys.mcsmanager.packets.CS_Ping;
|
import asys.mcsmanager.packets.CS_Ping;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -14,18 +15,23 @@ import java.util.LinkedList;
|
|||||||
public class ServerInfo {
|
public class ServerInfo {
|
||||||
private final Logger logger = LoggerFactory.getLogger(ServerInfo.class);
|
private final Logger logger = LoggerFactory.getLogger(ServerInfo.class);
|
||||||
private final String name;
|
private final String name;
|
||||||
|
private Channel channel;
|
||||||
private int lastOnline;
|
private int lastOnline;
|
||||||
private Deque<CS_Ping> pingDeque;
|
private Deque<CS_Ping> pingDeque = new LinkedList<>();
|
||||||
|
|
||||||
public ServerInfo(String name) {
|
public ServerInfo(String name, Channel channel) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.pingDeque = new LinkedList<>();
|
this.channel = channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Channel getChannel() {
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
|
||||||
public int getLastOnline() {
|
public int getLastOnline() {
|
||||||
return lastOnline;
|
return lastOnline;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
*/
|
*/
|
||||||
package asys.mcsmanager.server;
|
package asys.mcsmanager.server;
|
||||||
|
|
||||||
import asys.mcsmanager.Manager;
|
|
||||||
import asys.mcsmanager.packets.CS_Ping;
|
import asys.mcsmanager.packets.CS_Ping;
|
||||||
import asys.mcsmanager.packets.Packet;
|
import asys.mcsmanager.packets.Packet;
|
||||||
import asys.mcsmanager.packets.codec.PacketDecoder;
|
import asys.mcsmanager.packets.codec.PacketDecoder;
|
||||||
@@ -25,11 +24,9 @@ public class Server {
|
|||||||
);
|
);
|
||||||
private EventLoopGroup bossGroup, workerGroup;
|
private EventLoopGroup bossGroup, workerGroup;
|
||||||
static String passcode;
|
static String passcode;
|
||||||
static Manager manager;
|
|
||||||
|
|
||||||
public void start(String host, int port, String passcode, Manager manager) {
|
public void start(String host, int port, String passcode) {
|
||||||
Server.passcode = passcode;
|
Server.passcode = passcode;
|
||||||
Server.manager = manager;
|
|
||||||
bossGroup = new NioEventLoopGroup(1);
|
bossGroup = new NioEventLoopGroup(1);
|
||||||
workerGroup = new NioEventLoopGroup();
|
workerGroup = new NioEventLoopGroup();
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
package asys.mcsmanager.server;
|
package asys.mcsmanager.server;
|
||||||
|
|
||||||
|
import asys.mcsmanager.Linker;
|
||||||
import asys.mcsmanager.packets.*;
|
import asys.mcsmanager.packets.*;
|
||||||
import com.google.common.collect.BiMap;
|
import com.google.common.collect.BiMap;
|
||||||
import com.google.common.collect.ImmutableBiMap;
|
import com.google.common.collect.ImmutableBiMap;
|
||||||
@@ -17,7 +18,6 @@ import java.util.Map;
|
|||||||
|
|
||||||
import static asys.mcsmanager.packets.codec.Params.KNOWN_HANDLERS;
|
import static asys.mcsmanager.packets.codec.Params.KNOWN_HANDLERS;
|
||||||
import static asys.mcsmanager.packets.codec.Params.KNOWN_PACKETS;
|
import static asys.mcsmanager.packets.codec.Params.KNOWN_PACKETS;
|
||||||
import static asys.mcsmanager.server.Server.manager;
|
|
||||||
|
|
||||||
class ServerPacketHandler extends ChannelInboundHandlerAdapter implements IPacketHandler {
|
class ServerPacketHandler extends ChannelInboundHandlerAdapter implements IPacketHandler {
|
||||||
private static final BiMap<Integer, Class<? extends Packet>> handshakePackets = ImmutableBiMap.of(
|
private static final BiMap<Integer, Class<? extends Packet>> handshakePackets = ImmutableBiMap.of(
|
||||||
@@ -26,10 +26,11 @@ class ServerPacketHandler extends ChannelInboundHandlerAdapter implements IPacke
|
|||||||
);
|
);
|
||||||
private static Map<Class<? extends Packet>, IPacketHandler> handshakeHandlers;
|
private static Map<Class<? extends Packet>, IPacketHandler> handshakeHandlers;
|
||||||
|
|
||||||
private static final BiMap<Integer, Class<? extends Packet>> pingPackets = ImmutableBiMap.of(
|
private static final BiMap<Integer, Class<? extends Packet>> knownPackets = ImmutableBiMap.of(
|
||||||
3, CS_Ping.class,
|
3, CS_Ping.class,
|
||||||
4, CS_ConsoleMessage.class,
|
4, CS_ConsoleMessage.class,
|
||||||
5, SC_Command.class
|
5, SC_Command.class,
|
||||||
|
6, SC_ToggleSendMessages.class
|
||||||
);
|
);
|
||||||
private static Map<Class<? extends Packet>, IPacketHandler> pingHandlers;
|
private static Map<Class<? extends Packet>, IPacketHandler> pingHandlers;
|
||||||
|
|
||||||
@@ -59,7 +60,7 @@ class ServerPacketHandler extends ChannelInboundHandlerAdapter implements IPacke
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void channelInactive(ChannelHandlerContext context) throws Exception {
|
public void channelInactive(ChannelHandlerContext context) throws Exception {
|
||||||
manager.removeClientId(context.channel().attr(CLIENTID).get());
|
Linker.getInstance().removeServer(context.channel().attr(CLIENTID).get());
|
||||||
super.channelInactive(context);
|
super.channelInactive(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,7 +71,7 @@ class ServerPacketHandler extends ChannelInboundHandlerAdapter implements IPacke
|
|||||||
} else if (packet.getClass() == CS_Ping.class) {
|
} else if (packet.getClass() == CS_Ping.class) {
|
||||||
handleCSPing((CS_Ping) packet, context);
|
handleCSPing((CS_Ping) packet, context);
|
||||||
} else if (packet.getClass() == CS_ConsoleMessage.class) {
|
} else if (packet.getClass() == CS_ConsoleMessage.class) {
|
||||||
handleCSConsoleMessage((CS_ConsoleMessage) packet);
|
handleCSConsoleMessage(context.channel().attr(CLIENTID).get(), (CS_ConsoleMessage) packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,32 +80,32 @@ class ServerPacketHandler extends ChannelInboundHandlerAdapter implements IPacke
|
|||||||
try {
|
try {
|
||||||
context.channel().writeAndFlush(HandshakeResult.INVALID_PASSCODE).sync().channel().close();
|
context.channel().writeAndFlush(HandshakeResult.INVALID_PASSCODE).sync().channel().close();
|
||||||
} catch (InterruptedException ignore) {
|
} catch (InterruptedException ignore) {
|
||||||
// ignore
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!manager.addClientId(packet.getClientId(), context.channel())) {
|
if (Linker.getInstance().existsServer(packet.getClientId())) {
|
||||||
try {
|
try {
|
||||||
context.channel().writeAndFlush(HandshakeResult.CLIENTID_EXISTS).sync().channel().close();
|
context.channel().writeAndFlush(HandshakeResult.CLIENTID_EXISTS).sync().channel().close();
|
||||||
} catch (InterruptedException ignore) {
|
} catch (InterruptedException ignore) {
|
||||||
// ignore
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
} else {
|
||||||
|
Linker.getInstance().addServer(packet.getClientId(), context.channel());
|
||||||
}
|
}
|
||||||
|
|
||||||
context.channel().write(HandshakeResult.OK);
|
context.channel().write(HandshakeResult.OK);
|
||||||
context.channel().attr(CLIENTID).set(packet.getClientId());
|
context.channel().attr(CLIENTID).set(packet.getClientId());
|
||||||
context.channel().attr(KNOWN_PACKETS).set(pingPackets);
|
context.channel().attr(KNOWN_PACKETS).set(knownPackets);
|
||||||
context.channel().attr(KNOWN_HANDLERS).set(pingHandlers);
|
context.channel().attr(KNOWN_HANDLERS).set(pingHandlers);
|
||||||
context.channel().flush();
|
context.channel().flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleCSPing(CS_Ping packet, ChannelHandlerContext context) {
|
private void handleCSPing(CS_Ping packet, ChannelHandlerContext context) {
|
||||||
manager.putInfo(context.channel().attr(CLIENTID).get(), packet);
|
Linker.getInstance().getServer(context.channel().attr(CLIENTID).get()).putPing(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleCSConsoleMessage(CS_ConsoleMessage packet) {
|
private void handleCSConsoleMessage(String serverName, CS_ConsoleMessage packet) {
|
||||||
manager.sendBroadcastToWebConsoleListeners(packet);
|
Linker.getInstance().broadcastConsoleMessage(serverName, packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,36 +4,35 @@
|
|||||||
*/
|
*/
|
||||||
package asys.mcsmanager.websocket;
|
package asys.mcsmanager.websocket;
|
||||||
|
|
||||||
|
import asys.mcsmanager.Linker;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.SimpleChannelInboundHandler;
|
import io.netty.channel.SimpleChannelInboundHandler;
|
||||||
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
|
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
|
||||||
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
|
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
|
||||||
|
import io.netty.util.AttributeKey;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import static asys.mcsmanager.websocket.Server.manager;
|
|
||||||
|
|
||||||
public class FrameHandler extends SimpleChannelInboundHandler<WebSocketFrame> {
|
public class FrameHandler extends SimpleChannelInboundHandler<WebSocketFrame> {
|
||||||
|
private static final AttributeKey<String> WC_SERVERNAME = AttributeKey.valueOf("WC_SERVERNAME");
|
||||||
private final Logger logger = LoggerFactory.getLogger(FrameHandler.class);
|
private final Logger logger = LoggerFactory.getLogger(FrameHandler.class);
|
||||||
|
|
||||||
@Override
|
|
||||||
public void channelActive(ChannelHandlerContext ctx) throws Exception {
|
|
||||||
manager.addWebConsoleListener(ctx.channel());
|
|
||||||
super.channelActive(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||||
manager.removeWebConsoleListener(ctx.channel());
|
Linker.getInstance().removeWebconsoleListener(ctx.channel().attr(WC_SERVERNAME).get(), ctx.channel());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception {
|
protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception {
|
||||||
if (frame instanceof TextWebSocketFrame) {
|
if (frame instanceof TextWebSocketFrame) {
|
||||||
String requestText = ((TextWebSocketFrame)frame).text();
|
String requestText = ((TextWebSocketFrame)frame).text();
|
||||||
if (requestText.startsWith(":")) {
|
if (requestText.startsWith("]")) {
|
||||||
//FIXME убрать костыли
|
String serverName = requestText.substring(1);
|
||||||
manager.sendCommand(null, requestText.substring(1));
|
ctx.channel().attr(WC_SERVERNAME).set(serverName);
|
||||||
|
Linker.getInstance().addWebconsoleListener(serverName, ctx.channel());
|
||||||
|
} else if (requestText.startsWith(":")) {
|
||||||
|
String command = requestText.substring(1);
|
||||||
|
Linker.getInstance().sendCommand(ctx.channel().attr(WC_SERVERNAME).get(), command);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.warn("unsupport frame type: {}", frame.getClass().getName());
|
logger.warn("unsupport frame type: {}", frame.getClass().getName());
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
*/
|
*/
|
||||||
package asys.mcsmanager.websocket;
|
package asys.mcsmanager.websocket;
|
||||||
|
|
||||||
import asys.mcsmanager.Manager;
|
|
||||||
import io.netty.bootstrap.ServerBootstrap;
|
import io.netty.bootstrap.ServerBootstrap;
|
||||||
import io.netty.channel.ChannelInitializer;
|
import io.netty.channel.ChannelInitializer;
|
||||||
import io.netty.channel.EventLoopGroup;
|
import io.netty.channel.EventLoopGroup;
|
||||||
@@ -16,11 +15,9 @@ import io.netty.handler.codec.http.HttpServerCodec;
|
|||||||
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
|
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
|
||||||
|
|
||||||
public class Server {
|
public class Server {
|
||||||
static Manager manager;
|
|
||||||
private EventLoopGroup bossGroup, workerGroup;
|
private EventLoopGroup bossGroup, workerGroup;
|
||||||
|
|
||||||
public void start(String host, int port, Manager manager) {
|
public void start(String host, int port) {
|
||||||
Server.manager = manager;
|
|
||||||
bossGroup = new NioEventLoopGroup(1);
|
bossGroup = new NioEventLoopGroup(1);
|
||||||
workerGroup = new NioEventLoopGroup();
|
workerGroup = new NioEventLoopGroup();
|
||||||
|
|
||||||
|
|||||||
@@ -76,26 +76,34 @@ var ScrollingContent = React.createClass({
|
|||||||
ownHeight: 0,
|
ownHeight: 0,
|
||||||
scrollRatio: 0,
|
scrollRatio: 0,
|
||||||
lastPageY: 0,
|
lastPageY: 0,
|
||||||
|
autoScroll: true,
|
||||||
updateScrollParams: function () {
|
updateScrollParams: function () {
|
||||||
this.totalHeight = this.refs.content.scrollHeight;
|
this.totalHeight = this.refs.content.scrollHeight;
|
||||||
this.ownHeight = this.refs.content.clientHeight;
|
this.ownHeight = this.refs.content.clientHeight;
|
||||||
this.scrollRatio = this.ownHeight / this.totalHeight;
|
this.scrollRatio = this.ownHeight / this.totalHeight;
|
||||||
if (isNaN(this.scrollRatio)) this.scrollRatio = 0;
|
if (isNaN(this.scrollRatio)) this.scrollRatio = 0;
|
||||||
|
|
||||||
this.refs.scroll.style.height = this.scrollRatio * 100 + "%";
|
var h = this.scrollRatio * 100;
|
||||||
|
if (h < 100) {
|
||||||
|
if (this.autoScroll) {
|
||||||
|
this.refs.content.scrollTop = this.totalHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.refs.scroll.style.height = h + "%";
|
||||||
this.refs.scroll.style.top = (this.refs.content.scrollTop / this.totalHeight) * 100 + "%";
|
this.refs.scroll.style.top = (this.refs.content.scrollTop / this.totalHeight) * 100 + "%";
|
||||||
|
}
|
||||||
},
|
},
|
||||||
toggleSelect: function (value, event) { return value; },
|
toggleSelect: function (value, event) { return value; },
|
||||||
handleScrollMouseDown: function (event) {
|
handleMouseDown: function (event) {
|
||||||
this.lastPageY = event.pageY;
|
this.lastPageY = event.pageY;
|
||||||
document.body.classList.add('scroll-grabbed');
|
document.body.classList.add('scroll-grabbed');
|
||||||
this.refs.scroll.classList.add('scroll-grabbed');
|
this.refs.scroll.classList.add('scroll-grabbed');
|
||||||
|
|
||||||
document.onselectstart = this.toggleSelect.bind(null, false);
|
document.onselectstart = this.toggleSelect.bind(null, false);
|
||||||
document.addEventListener('mousemove', this.handleScrollMouseMove);
|
document.addEventListener('mousemove', this.handleMouseMove);
|
||||||
document.addEventListener('mouseup', this.handleScrollMouseUp);
|
document.addEventListener('mouseup', this.handleMouseUp);
|
||||||
},
|
},
|
||||||
handleScrollMouseMove: function (event) {
|
handleMouseMove: function (event) {
|
||||||
var delta = event.pageY - this.lastPageY;
|
var delta = event.pageY - this.lastPageY;
|
||||||
this.lastPageY = event.pageY;
|
this.lastPageY = event.pageY;
|
||||||
|
|
||||||
@@ -105,18 +113,25 @@ var ScrollingContent = React.createClass({
|
|||||||
_this.refs.scroll.style.top = (_this.refs.content.scrollTop / _this.totalHeight) * 100 + "%";
|
_this.refs.scroll.style.top = (_this.refs.content.scrollTop / _this.totalHeight) * 100 + "%";
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleScrollMouseUp: function (event) {
|
handleMouseUp: function (event) {
|
||||||
document.body.classList.remove('scroll-grabbed');
|
document.body.classList.remove('scroll-grabbed');
|
||||||
this.refs.scroll.classList.remove('scroll-grabbed');
|
this.refs.scroll.classList.remove('scroll-grabbed');
|
||||||
|
|
||||||
document.onselectstart = this.toggleSelect.bind(null, true);
|
document.onselectstart = this.toggleSelect.bind(null, true);
|
||||||
document.removeEventListener('mousemove', this.handleScrollMouseMove);
|
document.removeEventListener('mousemove', this.handleMouseMove);
|
||||||
document.removeEventListener('mouseup', this.handleScrollMouseUp);
|
document.removeEventListener('mouseup', this.handleMouseUp);
|
||||||
|
},
|
||||||
|
handleScroll: function (event) {
|
||||||
|
var zH = this.refs.gencon.offsetHeight;
|
||||||
|
var bottomPoint = ((this.refs.content.scrollTop / this.totalHeight) * zH) +
|
||||||
|
(this.scrollRatio * zH);
|
||||||
|
|
||||||
|
this.autoScroll = (bottomPoint === zH);
|
||||||
},
|
},
|
||||||
/*--------------------*/
|
/*--------------------*/
|
||||||
render: function () {
|
render: function () {
|
||||||
return (
|
return (
|
||||||
ce('div', {className: this.props.className},
|
ce('div', {className: this.props.className, ref: 'gencon'},
|
||||||
ce('div', {className: 'wrapper'},
|
ce('div', {className: 'wrapper'},
|
||||||
ce('div', {className: 'content', ref: 'content'}, this.props.children)
|
ce('div', {className: 'content', ref: 'content'}, this.props.children)
|
||||||
),
|
),
|
||||||
@@ -126,7 +141,8 @@ var ScrollingContent = React.createClass({
|
|||||||
},
|
},
|
||||||
componentDidMount: function () {
|
componentDidMount: function () {
|
||||||
this.updateScrollParams();
|
this.updateScrollParams();
|
||||||
this.refs.scroll.addEventListener('mousedown', this.handleScrollMouseDown);
|
this.refs.scroll.addEventListener('mousedown', this.handleMouseDown);
|
||||||
|
this.refs.content.addEventListener('scroll', this.handleScroll);
|
||||||
|
|
||||||
var _this = this;
|
var _this = this;
|
||||||
this.refs.content.addEventListener('scroll', function(){
|
this.refs.content.addEventListener('scroll', function(){
|
||||||
@@ -142,12 +158,15 @@ var ScrollingContent = React.createClass({
|
|||||||
|
|
||||||
var WebConsole = React.createClass({
|
var WebConsole = React.createClass({
|
||||||
ws: null,
|
ws: null,
|
||||||
connect: function(){
|
connect: function(serverName){
|
||||||
if (this.ws !== null) return;
|
if (this.ws !== null) return;
|
||||||
var _this = this;
|
var _this = this;
|
||||||
|
|
||||||
this.ws = new WebSocket("ws://127.0.0.1:8770"); //FIXME указывать ip:port из настроек
|
this.ws = new WebSocket("ws://127.0.0.1:8770"); //FIXME указывать ip:port из настроек
|
||||||
this.ws.onopen = function(){ console.debug('WS: open...'); };
|
this.ws.onopen = function(){
|
||||||
|
console.debug('WS: open...');
|
||||||
|
_this.ws.send(']'+serverName);
|
||||||
|
};
|
||||||
this.ws.onclose = function(){ console.debug('WS: close...'); };
|
this.ws.onclose = function(){ console.debug('WS: close...'); };
|
||||||
this.ws.onerror = function(e){ console.debug('WS: error'); console.error(e); };
|
this.ws.onerror = function(e){ console.debug('WS: error'); console.error(e); };
|
||||||
this.ws.onmessage = function(event){
|
this.ws.onmessage = function(event){
|
||||||
@@ -195,7 +214,7 @@ var WebConsole = React.createClass({
|
|||||||
var ServerInfo = React.createClass({
|
var ServerInfo = React.createClass({
|
||||||
tabStateWebConsole: function(state) {
|
tabStateWebConsole: function(state) {
|
||||||
if (state === 1) {
|
if (state === 1) {
|
||||||
this.refs.webconsole.connect();
|
this.refs.webconsole.connect(this.state.title);
|
||||||
this.refs.webconsole.focusInput();
|
this.refs.webconsole.focusInput();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -211,7 +230,7 @@ var ServerInfo = React.createClass({
|
|||||||
return(
|
return(
|
||||||
ce('div', null,
|
ce('div', null,
|
||||||
ce('h2', {style: {'margin-top': '0px'}}, this.state.title),
|
ce('h2', {style: {'margin-top': '0px'}}, this.state.title),
|
||||||
ce(Tabs, {tabs: ['Онлайн', 'Консоль'], stateCallback: this.tabStateWebConsole},
|
ce(Tabs, {tabs: ['Онлайн', 'Консоль'], stateCallback: this.tabStateWebConsole, ref: 'tabs'},
|
||||||
ce(NvLineChart, {datum: [{
|
ce(NvLineChart, {datum: [{
|
||||||
key: 'Online players',
|
key: 'Online players',
|
||||||
color: '#37d668',
|
color: '#37d668',
|
||||||
@@ -223,6 +242,14 @@ var ServerInfo = React.createClass({
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
componentWillUpdate: function(nextProps, nextState) {
|
||||||
|
if (this.state.title === null) return;
|
||||||
|
if (this.state.title !== nextState.title) {
|
||||||
|
this.refs.webconsole.disconnect();
|
||||||
|
this.refs.webconsole.setState({lines: []});
|
||||||
|
this.refs.tabs.setState({activeTab: 0});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -79,8 +79,8 @@ var ContentModule = React.createClass({
|
|||||||
});
|
});
|
||||||
|
|
||||||
element = ce('div', {className: 'row'},
|
element = ce('div', {className: 'row'},
|
||||||
ce('div', {className: 'col-md-4'}, ce(ServerList, null, serverListItems)),
|
ce('div', {className: 'col-md-3'}, ce(ServerList, null, serverListItems)),
|
||||||
ce('div', {className: 'col-md-8'}, ce(ServerInfo, {ref: "serverInfo"}))
|
ce('div', {className: 'col-md-9'}, ce(ServerInfo, {ref: "serverInfo"}))
|
||||||
);
|
);
|
||||||
} else if (this.state.nvScriptReady < 0) {
|
} else if (this.state.nvScriptReady < 0) {
|
||||||
element = ce('span', null, 'error');
|
element = ce('span', null, 'error');
|
||||||
|
|||||||
Reference in New Issue
Block a user