Archived
0

Merge remote-tracking branch 'origin/dev-webconsole' into local-merge

# Conflicts:
#	bridge-protocol/build.gradle
#	bridge/src/main/java/asys/bridge/bukkit/BridgePlugin.java
#	bridge/src/main/java/asys/bridge/client/ClientPacketHandler.java
#	mcserver-manager/build.gradle
#	mcserver-manager/src/main/java/asys/mcsmanager/server/ServerPacketHandler.java
This commit is contained in:
2017-06-08 13:27:05 +03:00
19 changed files with 905 additions and 55 deletions

View File

@@ -5,7 +5,6 @@
package asys.mcsmanager;
import asys.api.Config;
import asys.mcsmanager.server.Server;
import asys.webinterface.api.Webinterface;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
@@ -20,7 +19,8 @@ public class Activator implements BundleActivator, ServiceListener {
private ServiceTracker<?, Webinterface> serviceTracker;
private MCSM_WebModule module;
private Webinterface webinterface;
private Server serverManager;
private asys.mcsmanager.server.Server serverManager;
private asys.mcsmanager.websocket.Server webconsoleServer;
@Override
public void start(BundleContext context) throws Exception {
@@ -43,13 +43,21 @@ public class Activator implements BundleActivator, ServiceListener {
int port = config.getInt("asys.mcsmanager.port", 8779);
String passcode = config.getString("asys.mcsmanager.passcode", "testpasscode");
logger.debug("Start server manager: {}:{}", host, port);
serverManager = new Server();
serverManager = new asys.mcsmanager.server.Server();
serverManager.start(host, port, passcode, manager);
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);
serviceConfigTracker.close();
}
@Override
public void stop(BundleContext context) throws Exception {
webconsoleServer.shutdown();
serverManager.shutdown();
if (webinterface != null) {

View File

@@ -26,6 +26,7 @@ public class MCSM_WebModule extends WebModule {
private final String MODULE_NAME = "mcsmanager";
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) {
@@ -66,6 +67,19 @@ public class MCSM_WebModule extends WebModule {
this.sendContent(httpExchange, 0, stream);
return true;
}
//FIXME дублирование кода
matcher = URL_PATTERN_CSS.matcher(urlPath);
if (matcher.find()) {
InputStream stream = getClass().getResourceAsStream("/" + matcher.group(1) + ".css");
if (stream == null) {
this.sendHttpCode(httpExchange, 404, "not found");
return true;
}
httpExchange.getResponseHeaders().add("Content-Type", "text/css;charset=utf-8");
this.sendContent(httpExchange, 0, stream);
return true;
}
}
return false;

View File

@@ -4,7 +4,11 @@
*/
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;
@@ -13,19 +17,43 @@ 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) {
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;
}
@@ -47,4 +75,22 @@ public class Manager {
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()
)));
}
}
}

View File

@@ -28,7 +28,8 @@ class ServerPacketHandler extends ChannelInboundHandlerAdapter implements IPacke
private static final BiMap<Integer, Class<? extends Packet>> pingPackets = ImmutableBiMap.of(
3, CS_Ping.class,
4, CS_ConsoleMessage.class
4, CS_ConsoleMessage.class,
5, SC_Command.class
);
private static Map<Class<? extends Packet>, IPacketHandler> pingHandlers;
@@ -56,6 +57,12 @@ class ServerPacketHandler extends ChannelInboundHandlerAdapter implements IPacke
super.channelActive(context);
}
@Override
public void channelInactive(ChannelHandlerContext context) throws Exception {
manager.removeClientId(context.channel().attr(CLIENTID).get());
super.channelInactive(context);
}
@Override
public void handle(Packet packet, ChannelHandlerContext context) {
if (packet.getClass() == CS_Handshake.class) {
@@ -77,7 +84,7 @@ class ServerPacketHandler extends ChannelInboundHandlerAdapter implements IPacke
return;
}
if (!manager.addClientId(packet.getClientId())) {
if (!manager.addClientId(packet.getClientId(), context.channel())) {
try {
context.channel().writeAndFlush(HandshakeResult.CLIENTID_EXISTS).sync().channel().close();
} catch (InterruptedException ignore) {
@@ -98,6 +105,6 @@ class ServerPacketHandler extends ChannelInboundHandlerAdapter implements IPacke
}
private void handleCSConsoleMessage(CS_ConsoleMessage packet) {
LoggerFactory.getLogger(getClass()).debug("[L:{}] {}", packet.getLevel(), packet.getMessage());
manager.sendBroadcastToWebConsoleListeners(packet);
}
}

View File

@@ -0,0 +1,42 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2017-05-09
*/
package asys.mcsmanager.websocket;
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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static asys.mcsmanager.websocket.Server.manager;
public class FrameHandler extends SimpleChannelInboundHandler<WebSocketFrame> {
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());
}
@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));
}
} else {
logger.warn("unsupport frame type: {}", frame.getClass().getName());
}
}
}

View File

@@ -0,0 +1,59 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2017-05-08
*/
package asys.mcsmanager.websocket;
import asys.mcsmanager.Manager;
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;
import io.netty.handler.codec.http.HttpObjectAggregator;
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;
bossGroup = new NioEventLoopGroup(1);
workerGroup = new NioEventLoopGroup();
ServerBootstrap serverBootstrap = createServerBootstrap();
serverBootstrap.bind(host, port);
}
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 HttpServerCodec(),
new HttpObjectAggregator(65536),
new WebSocketServerProtocolHandler("/", null, true),
new FrameHandler()
);
}
};
}
}