From 88076d2c25f4a1a23fbf964c862754b312c97455 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Sun, 11 Jun 2017 22:52:07 +0300 Subject: [PATCH] =?UTF-8?q?MCSM:=20=D1=80=D0=B5=D1=84=D0=B0=D0=BA=D1=82?= =?UTF-8?q?=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81?= =?UTF-8?q?=D0=B0=20Manager?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mcserver-manager/build.gradle | 2 +- .../main/java/asys/mcsmanager/Activator.java | 9 +- .../java/asys/mcsmanager/MCSM_WebModule.java | 9 +- .../main/java/asys/mcsmanager/Manager.java | 103 +++++++----------- .../main/java/asys/mcsmanager/ServerInfo.java | 12 +- .../java/asys/mcsmanager/server/Server.java | 5 +- .../server/ServerPacketHandler.java | 18 +-- .../mcsmanager/websocket/FrameHandler.java | 23 ++-- .../asys/mcsmanager/websocket/Server.java | 5 +- .../src/main/resources/components.js | 18 ++- 10 files changed, 93 insertions(+), 111 deletions(-) diff --git a/mcserver-manager/build.gradle b/mcserver-manager/build.gradle index e47c984..d7c4fed 100644 --- a/mcserver-manager/build.gradle +++ b/mcserver-manager/build.gradle @@ -1,5 +1,5 @@ group = 'asys' -version = '0.8.13-SNAPSHOT' +version = '0.10-SNAPSHOT' apply plugin: 'osgi' diff --git a/mcserver-manager/src/main/java/asys/mcsmanager/Activator.java b/mcserver-manager/src/main/java/asys/mcsmanager/Activator.java index 676eaff..ff05c31 100644 --- a/mcserver-manager/src/main/java/asys/mcsmanager/Activator.java +++ b/mcserver-manager/src/main/java/asys/mcsmanager/Activator.java @@ -29,9 +29,7 @@ public class Activator implements BundleActivator, ServiceListener { Config config = serviceConfigTracker.getService(); if (config == null) throw new RuntimeException("Service 'Config' is not avalable!"); - Manager manager = new Manager(); - - module = new MCSM_WebModule(manager); + module = new MCSM_WebModule(); logger.debug("Get service: {}", Webinterface.class); 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"); logger.debug("Start server manager: {}:{}", host, port); 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"); port = config.getInt("asys.mcsmanager.webconsole.port", 8770); logger.debug("Start webconsole server: {}:{}", host, port); webconsoleServer = new asys.mcsmanager.websocket.Server(); - webconsoleServer.start(host, port, manager); + webconsoleServer.start(host, port); serviceConfigTracker.close(); } @@ -82,7 +80,6 @@ public class Activator implements BundleActivator, ServiceListener { logger.debug("service not found =("); } } catch (InterruptedException ignore) { - // ignore } } } diff --git a/mcserver-manager/src/main/java/asys/mcsmanager/MCSM_WebModule.java b/mcserver-manager/src/main/java/asys/mcsmanager/MCSM_WebModule.java index 758a1cc..6ace2db 100644 --- a/mcserver-manager/src/main/java/asys/mcsmanager/MCSM_WebModule.java +++ b/mcserver-manager/src/main/java/asys/mcsmanager/MCSM_WebModule.java @@ -27,11 +27,6 @@ public class MCSM_WebModule extends WebModule { private final String MODULE_URL = "/"+MODULE_NAME; 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 Manager manager; - - MCSM_WebModule(Manager manager) { - this.manager = manager; - } @Override public String getName() { @@ -89,7 +84,7 @@ public class MCSM_WebModule extends WebModule { if (httpExchange.getRequestURI().getQuery() != null && !httpExchange.getRequestURI().getQuery().isEmpty()) { Map query = this.queryToMap(httpExchange.getRequestURI().getQuery()); - ServerInfo serverInfo = manager.getInfo(query.get("clientid")); + ServerInfo serverInfo = Manager.getInstance().getServer(query.get("clientid")); if (serverInfo == null) { this.sendJson(httpExchange, "{}"); } else { @@ -102,6 +97,6 @@ public class MCSM_WebModule extends WebModule { } private JsonElement serverList() { - return GSON.toJsonTree(manager.getServerList()); + return GSON.toJsonTree(Manager.getInstance().getServerList()); } } diff --git a/mcserver-manager/src/main/java/asys/mcsmanager/Manager.java b/mcserver-manager/src/main/java/asys/mcsmanager/Manager.java index 4f06e68..d8cd3ae 100644 --- a/mcserver-manager/src/main/java/asys/mcsmanager/Manager.java +++ b/mcserver-manager/src/main/java/asys/mcsmanager/Manager.java @@ -5,92 +5,73 @@ 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 serversMap = new HashMap<>(); - private Map serverChannels = new HashMap<>(); - private List webconsoleListener = new ArrayList<>(); + private static Manager instance = new Manager(); + private Map serverMap = new HashMap<>(); + private Map> webconsoleListeners = new HashMap<>(); - /** - * Добавляем в список ClientID - * @param clientId id сервера. Чувствителен к регистру - * @return false, если сервер с таким 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 static Manager getInstance() { + return instance; } - public void removeClientId(String clientId) { - if (clientId != null) { - serverChannels.remove(clientId); - } + private Manager(){ } - 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; + public void addServer(String serverName, Channel channel) { + this.serverMap.put(serverName, new ServerInfo(serverName, channel)); } - /** - * Дополнить информация о сервере. - * Если сервер отсутствует в списке, информация будет потеряна. - * @param clientId id сервера. Чувствителен к регистру - * @param pingPacket - */ - public void putInfo(String clientId, CS_Ping pingPacket) { - if (!serversMap.containsKey(clientId)) return; - serversMap.get(clientId).putPing(pingPacket); + public boolean existsServer(String serverName) { + return this.serverMap.containsKey(serverName); + } + + public ServerInfo getServer(String serverName) { + return this.serverMap.get(serverName); } public Set getServerList() { - return serversMap.keySet(); + return this.serverMap.keySet(); } - public ServerInfo getInfo(String clientId) { - return serversMap.get(clientId); + 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(Channel channel) { - this.webconsoleListener.add(channel); + public void addWebconsoleListener(String serverName, Channel channel) { + this.webconsoleListeners + .computeIfAbsent(serverName, v -> new ArrayList<>()) + .add(channel); } - public void removeWebConsoleListener(Channel channel) { - this.webconsoleListener.remove(channel); + public void removeWebconsoleListener(String serverName, Channel channel) { + this.webconsoleListeners.get(serverName).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() - ))); + 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)); } } } diff --git a/mcserver-manager/src/main/java/asys/mcsmanager/ServerInfo.java b/mcserver-manager/src/main/java/asys/mcsmanager/ServerInfo.java index fd29a74..6e14ca8 100644 --- a/mcserver-manager/src/main/java/asys/mcsmanager/ServerInfo.java +++ b/mcserver-manager/src/main/java/asys/mcsmanager/ServerInfo.java @@ -5,6 +5,7 @@ package asys.mcsmanager; import asys.mcsmanager.packets.CS_Ping; +import io.netty.channel.Channel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -14,18 +15,23 @@ import java.util.LinkedList; public class ServerInfo { private final Logger logger = LoggerFactory.getLogger(ServerInfo.class); private final String name; + private Channel channel; private int lastOnline; - private Deque pingDeque; + private Deque pingDeque = new LinkedList<>(); - public ServerInfo(String name) { + public ServerInfo(String name, Channel channel) { this.name = name; - this.pingDeque = new LinkedList<>(); + this.channel = channel; } public String getName() { return name; } + public Channel getChannel() { + return channel; + } + public int getLastOnline() { return lastOnline; } diff --git a/mcserver-manager/src/main/java/asys/mcsmanager/server/Server.java b/mcserver-manager/src/main/java/asys/mcsmanager/server/Server.java index f2743f5..e0d0f49 100644 --- a/mcserver-manager/src/main/java/asys/mcsmanager/server/Server.java +++ b/mcserver-manager/src/main/java/asys/mcsmanager/server/Server.java @@ -4,7 +4,6 @@ */ package asys.mcsmanager.server; -import asys.mcsmanager.Manager; import asys.mcsmanager.packets.CS_Ping; import asys.mcsmanager.packets.Packet; import asys.mcsmanager.packets.codec.PacketDecoder; @@ -25,11 +24,9 @@ public class Server { ); private EventLoopGroup bossGroup, workerGroup; 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.manager = manager; bossGroup = new NioEventLoopGroup(1); workerGroup = new NioEventLoopGroup(); diff --git a/mcserver-manager/src/main/java/asys/mcsmanager/server/ServerPacketHandler.java b/mcserver-manager/src/main/java/asys/mcsmanager/server/ServerPacketHandler.java index bb4bd42..3997d3a 100644 --- a/mcserver-manager/src/main/java/asys/mcsmanager/server/ServerPacketHandler.java +++ b/mcserver-manager/src/main/java/asys/mcsmanager/server/ServerPacketHandler.java @@ -4,6 +4,7 @@ */ package asys.mcsmanager.server; +import asys.mcsmanager.Manager; import asys.mcsmanager.packets.*; import com.google.common.collect.BiMap; import com.google.common.collect.ImmutableBiMap; @@ -16,7 +17,6 @@ import java.util.Map; import static asys.mcsmanager.packets.codec.Params.KNOWN_HANDLERS; import static asys.mcsmanager.packets.codec.Params.KNOWN_PACKETS; -import static asys.mcsmanager.server.Server.manager; class ServerPacketHandler extends ChannelInboundHandlerAdapter implements IPacketHandler { private static final BiMap> handshakePackets = ImmutableBiMap.of( @@ -58,7 +58,7 @@ class ServerPacketHandler extends ChannelInboundHandlerAdapter implements IPacke @Override public void channelInactive(ChannelHandlerContext context) throws Exception { - manager.removeClientId(context.channel().attr(CLIENTID).get()); + Manager.getInstance().removeServer(context.channel().attr(CLIENTID).get()); super.channelInactive(context); } @@ -69,7 +69,7 @@ class ServerPacketHandler extends ChannelInboundHandlerAdapter implements IPacke } else if (packet.getClass() == CS_Ping.class) { handleCSPing((CS_Ping) packet, context); } else if (packet.getClass() == CS_ConsoleMessage.class) { - handleCSConsoleMessage((CS_ConsoleMessage) packet); + handleCSConsoleMessage(context.channel().attr(CLIENTID).get(), (CS_ConsoleMessage) packet); } } @@ -78,18 +78,18 @@ class ServerPacketHandler extends ChannelInboundHandlerAdapter implements IPacke try { context.channel().writeAndFlush(HandshakeResult.INVALID_PASSCODE).sync().channel().close(); } catch (InterruptedException ignore) { - // ignore } return; } - if (!manager.addClientId(packet.getClientId(), context.channel())) { + if (Manager.getInstance().existsServer(packet.getClientId())) { try { context.channel().writeAndFlush(HandshakeResult.CLIENTID_EXISTS).sync().channel().close(); } catch (InterruptedException ignore) { - // ignore } return; + } else { + Manager.getInstance().addServer(packet.getClientId(), context.channel()); } context.channel().write(HandshakeResult.OK); @@ -100,10 +100,10 @@ class ServerPacketHandler extends ChannelInboundHandlerAdapter implements IPacke } private void handleCSPing(CS_Ping packet, ChannelHandlerContext context) { - manager.putInfo(context.channel().attr(CLIENTID).get(), packet); + Manager.getInstance().getServer(context.channel().attr(CLIENTID).get()).putPing(packet); } - private void handleCSConsoleMessage(CS_ConsoleMessage packet) { - manager.sendBroadcastToWebConsoleListeners(packet); + private void handleCSConsoleMessage(String serverName, CS_ConsoleMessage packet) { + Manager.getInstance().broadcastConsoleMessage(serverName, packet); } } diff --git a/mcserver-manager/src/main/java/asys/mcsmanager/websocket/FrameHandler.java b/mcserver-manager/src/main/java/asys/mcsmanager/websocket/FrameHandler.java index 1dbd305..2b96750 100644 --- a/mcserver-manager/src/main/java/asys/mcsmanager/websocket/FrameHandler.java +++ b/mcserver-manager/src/main/java/asys/mcsmanager/websocket/FrameHandler.java @@ -4,36 +4,35 @@ */ package asys.mcsmanager.websocket; +import asys.mcsmanager.Manager; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; import io.netty.handler.codec.http.websocketx.WebSocketFrame; +import io.netty.util.AttributeKey; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static asys.mcsmanager.websocket.Server.manager; - public class FrameHandler extends SimpleChannelInboundHandler { + private static final AttributeKey WC_SERVERNAME = AttributeKey.valueOf("WC_SERVERNAME"); private final Logger logger = LoggerFactory.getLogger(FrameHandler.class); - @Override - public void channelActive(ChannelHandlerContext ctx) throws Exception { - manager.addWebConsoleListener(ctx.channel()); - super.channelActive(ctx); - } - @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { - manager.removeWebConsoleListener(ctx.channel()); + Manager.getInstance().removeWebconsoleListener(ctx.channel().attr(WC_SERVERNAME).get(), ctx.channel()); } @Override protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception { if (frame instanceof TextWebSocketFrame) { String requestText = ((TextWebSocketFrame)frame).text(); - if (requestText.startsWith(":")) { - //FIXME убрать костыли - manager.sendCommand(null, requestText.substring(1)); + if (requestText.startsWith("]")) { + String serverName = requestText.substring(1); + ctx.channel().attr(WC_SERVERNAME).set(serverName); + Manager.getInstance().addWebconsoleListener(serverName, ctx.channel()); + } else if (requestText.startsWith(":")) { + String command = requestText.substring(1); + Manager.getInstance().sendCommand(ctx.channel().attr(WC_SERVERNAME).get(), command); } } else { logger.warn("unsupport frame type: {}", frame.getClass().getName()); diff --git a/mcserver-manager/src/main/java/asys/mcsmanager/websocket/Server.java b/mcserver-manager/src/main/java/asys/mcsmanager/websocket/Server.java index a9b30c4..b73e5d1 100644 --- a/mcserver-manager/src/main/java/asys/mcsmanager/websocket/Server.java +++ b/mcserver-manager/src/main/java/asys/mcsmanager/websocket/Server.java @@ -4,7 +4,6 @@ */ package asys.mcsmanager.websocket; -import asys.mcsmanager.Manager; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelInitializer; import io.netty.channel.EventLoopGroup; @@ -16,11 +15,9 @@ import io.netty.handler.codec.http.HttpServerCodec; import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; public class Server { - static Manager manager; private EventLoopGroup bossGroup, workerGroup; - public void start(String host, int port, Manager manager) { - Server.manager = manager; + public void start(String host, int port) { bossGroup = new NioEventLoopGroup(1); workerGroup = new NioEventLoopGroup(); diff --git a/mcserver-manager/src/main/resources/components.js b/mcserver-manager/src/main/resources/components.js index 5e9e803..5b5d359 100644 --- a/mcserver-manager/src/main/resources/components.js +++ b/mcserver-manager/src/main/resources/components.js @@ -142,12 +142,15 @@ var ScrollingContent = React.createClass({ var WebConsole = React.createClass({ ws: null, - connect: function(){ + connect: function(serverName){ if (this.ws !== null) return; var _this = this; 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.onerror = function(e){ console.debug('WS: error'); console.error(e); }; this.ws.onmessage = function(event){ @@ -195,7 +198,7 @@ var WebConsole = React.createClass({ var ServerInfo = React.createClass({ tabStateWebConsole: function(state) { if (state === 1) { - this.refs.webconsole.connect(); + this.refs.webconsole.connect(this.state.title); this.refs.webconsole.focusInput(); } }, @@ -211,7 +214,7 @@ var ServerInfo = React.createClass({ return( ce('div', null, 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: [{ key: 'Online players', color: '#37d668', @@ -223,6 +226,13 @@ 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.tabs.setState({activeTab: 0}); + } } });