Archived
0

Bridge: первая итерация поддержки Sponge

This commit is contained in:
2017-05-17 13:09:51 +03:00
parent c37089a39a
commit b921a3611e
16 changed files with 399 additions and 102 deletions

View File

@@ -45,13 +45,13 @@ dependencies {
exclude group: 'com.google.code'
exclude group: 'com.google.code.findbugs'
exclude group: 'com.google.code.gson'
exclude group: 'com.google.inject'
exclude group: 'com.github.ben-manes.caffeine'
exclude group: 'com.flowpowered'
exclude group: 'org.slf4j'
exclude group: 'org.apache.commons'
exclude group: 'org.ow2.asm'
exclude group: 'ninja.leaping.configurate'
exclude group: 'ninja.leaping.configurate', module: 'configurate-gson'
exclude group: 'ninja.leaping.configurate', module: 'configurate-hocon'
}
compile group: 'io.netty', name: 'netty-codec', version: nettyVersion
}

View File

@@ -0,0 +1,37 @@
/*
* 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;
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();
}
}

View File

@@ -4,47 +4,25 @@
*/
package asys.bridge.bukkit;
import asys.bridge.client.Client;
import asys.mcsmanager.packets.CS_Ping;
import io.netty.channel.Channel;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public class BridgePlugin extends JavaPlugin {
public static BridgePlugin INSTANCE;
private Client client;
private ScheduledExecutorService ses;
private ScheduledFuture<?> sesFuture, sesPingFuture;
private int tryConnect = 0;
private BridgeBukkitImpl bridgeBukkit;
@Override
public void onEnable() {
INSTANCE = this;
saveDefaultConfig();
startReconnect();
this.bridgeBukkit = new BridgeBukkitImpl(this);
this.bridgeBukkit.startReconnect();
}
@Override
public void onDisable() {
if (sesFuture != null) {
sesFuture.cancel(false);
}
stopPing();
if (client.isConnected()) {
getLogger().info("Disconnect...");
client.disconnect();
}
INSTANCE = null;
this.bridgeBukkit.stopReconnect();
this.bridgeBukkit.stopPing();
this.bridgeBukkit.disconnect();
}
@Override
@@ -52,53 +30,4 @@ public class BridgePlugin extends JavaPlugin {
sender.sendMessage("ASys Bridge by DmitriyMX");
return true;
}
public void startReconnect() {
client = new Client();
ses = Executors.newScheduledThreadPool(2);
sesFuture = ses.scheduleAtFixedRate(() -> {
getLogger().info(String.format("Connect(%d) to ASys...", ++tryConnect));
client.connect(getConfig().getString("host"), getConfig().getInt("port"));
if (client.isConnected()) {
stopReconnect();
} else {
getLogger().warning(
String.format("Connection(%d) fail. Try reconnect...", tryConnect));
}
}, 0L, 5L, TimeUnit.SECONDS);
}
public void stopReconnect() {
if (sesFuture != null) {
sesFuture.cancel(false);
sesFuture = null;
tryConnect = 0;
}
}
public void startPing(Channel channel) {
sesPingFuture = ses.scheduleAtFixedRate(() -> {
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();
}
}, 0L, 5L, TimeUnit.SECONDS);
}
public void stopPing() {
if (sesPingFuture != null) {
sesPingFuture.cancel(false);
}
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -0,0 +1,80 @@
/*
* DmitriyMX <d.mihailov@samson-rus.com>
* 2017-05-17
*/
package asys.bridge.client;
import asys.mcsmanager.packets.CS_Ping;
import io.netty.channel.Channel;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
public abstract class AbstractBridge implements IBridge {
private Client client;
private ScheduledExecutorService ses;
private ScheduledFuture<?> sesFuture, sesPingFuture;
private int tryConnect = 0;
@Override
public void startReconnect() {
client = new Client(this);
ses = Executors.newScheduledThreadPool(2);
sesFuture = ses.scheduleAtFixedRate(() -> {
getLogger().info(String.format("Connect(%d) to ASys...", ++tryConnect));
client.connect(getConfig().getString("host"), getConfig().getInt("port"));
if (client.isConnected()) {
stopReconnect();
} else {
getLogger().warn(String.format("Connection(%d) fail. Try reconnect...", tryConnect));
}
}, 0L, 5L, TimeUnit.SECONDS);
}
@Override
public void stopReconnect() {
if (sesFuture != null) {
sesFuture.cancel(false);
sesFuture = null;
tryConnect = 0;
}
}
@Override
public void startPing(Channel channel) {
sesPingFuture = ses.scheduleAtFixedRate(() -> {
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();
}
}, 0L, 5L, TimeUnit.SECONDS);
}
@Override
public void stopPing() {
if (sesPingFuture != null) {
sesPingFuture.cancel(false);
}
}
@Override
public void disconnect() {
if (client.isConnected()) {
getLogger().info("Disconnect...");
client.disconnect();
}
}
}

View File

@@ -19,6 +19,11 @@ public class Client {
private EventLoopGroup group;
private Bootstrap bootstrap;
private ChannelFuture channelFuture;
private IBridge bridge;
public Client(IBridge bridge) {
this.bridge = bridge;
}
public void connect(String host, int port) {
if (group == null || bootstrap == null) {
@@ -55,7 +60,7 @@ public class Client {
new PacketEncoder(),
new PacketDecoder(),
new PacketHandler(),
new ClientPacketHandler()
new ClientPacketHandler(bridge)
);
}
};

View File

@@ -27,8 +27,10 @@ public class ClientPacketHandler extends ChannelInboundHandlerAdapter implements
private static final BiMap<Integer, Class<? extends Packet>> pingPackets = ImmutableBiMap.of(
3, CS_Ping.class
);
private IBridge bridge;
ClientPacketHandler() {
ClientPacketHandler(IBridge bridge) {
this.bridge = bridge;
if (handshakeHandlers == null) {
handshakeHandlers = ImmutableMap.of(
SC_HandshakeResult.class, this
@@ -38,26 +40,24 @@ public class ClientPacketHandler extends ChannelInboundHandlerAdapter implements
@Override
public void channelActive(ChannelHandlerContext context) throws Exception {
BridgePlugin.INSTANCE.getLogger().info("channelActive");
bridge.getLogger().info("channelActive");
context.channel().attr(KNOWN_PACKETS).set(handshakePackets);
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...");
bridge.getConfig().getString("clientId"),
bridge.getConfig().getString("passcode"));
bridge.getLogger().info("send Handshake packet...");
context.channel().writeAndFlush(packet);
super.channelActive(context);
}
@Override
public void channelInactive(ChannelHandlerContext context) throws Exception {
if (BridgePlugin.INSTANCE != null) {
BridgePlugin.INSTANCE.getLogger().warning("Lost connection!");
BridgePlugin.INSTANCE.stopPing();
BridgePlugin.INSTANCE.getLogger().warning("Try reconnect...");
BridgePlugin.INSTANCE.startReconnect();
}
bridge.getLogger().warn("Lost connection!");
bridge.stopPing();
bridge.getLogger().warn("Try reconnect...");
bridge.startReconnect();
context.channel().attr(KNOWN_PACKETS).remove();
context.channel().attr(KNOWN_HANDLERS).remove();
super.channelInactive(context);
@@ -65,15 +65,15 @@ public class ClientPacketHandler extends ChannelInboundHandlerAdapter implements
@Override
public void handle(Packet packet, ChannelHandlerContext context) {
BridgePlugin.INSTANCE.getLogger().info("handle : " + packet.getClass().getSimpleName());
bridge.getLogger().info("handle : " + packet.getClass().getSimpleName());
SC_HandshakeResult pkt = (SC_HandshakeResult) packet;
if (pkt.getErrorCode() != 0) {
BridgePlugin.INSTANCE.getLogger().severe(
bridge.getLogger().error(
String.format("Handshake: #%d %s", pkt.getErrorCode(), pkt.getMessage()));
} else {
context.channel().attr(KNOWN_PACKETS).set(pingPackets);
BridgePlugin.INSTANCE.getLogger().info("Handshake: OK");
BridgePlugin.INSTANCE.startPing(context.channel());
bridge.getLogger().info("Handshake: OK");
bridge.startPing(context.channel());
}
}
}

View File

@@ -0,0 +1,18 @@
/*
* 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 startReconnect();
void stopReconnect();
void startPing(Channel channel);
void stopPing();
void disconnect();
}

View 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);
}

View 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);
}

View File

@@ -4,14 +4,71 @@
*/
package asys.bridge.sponge;
import com.google.inject.Inject;
import ninja.leaping.configurate.ConfigurationNode;
import ninja.leaping.configurate.loader.ConfigurationLoader;
import ninja.leaping.configurate.yaml.YAMLConfigurationLoader;
import org.slf4j.Logger;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.event.Listener;
import org.spongepowered.api.event.game.state.GameConstructionEvent;
import org.spongepowered.api.plugin.Plugin;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.Files;
import java.nio.file.Path;
@Plugin(id = "asysbridge", name = "ASysBridge", version = "0.6-SNAPSHOT")
public class BridgeSponge {
@Inject
private Logger logger;
private ConfigurationNode configurationNode;
private BridgeSpongeImpl bridgeSponge;
@Listener
public void initPlugin(GameConstructionEvent event) {
// hello?
public void initPlugin(GameConstructionEvent event) throws IOException {
initConfig();
this.bridgeSponge = new BridgeSpongeImpl(this);
this.bridgeSponge.startReconnect();
}
private void initConfig() throws IOException {
Path configPath = Sponge.getConfigManager().getPluginConfig(this).getConfigPath();
if (!Files.exists(configPath)) {
saveDefaultConfig(configPath);
}
ConfigurationLoader<ConfigurationNode> loader =
YAMLConfigurationLoader.builder().setPath(configPath).build();
configurationNode = loader.load();
}
Logger getLogger() {
return this.logger;
}
ConfigurationNode getConfigurationNode() {
return configurationNode;
}
private void saveDefaultConfig(Path configPath) throws IOException {
URL configUrl = Sponge.getAssetManager().getAsset("config.yml").get().getUrl();
URLConnection urlConnection = configUrl.openConnection();
InputStream inputStream = urlConnection.getInputStream();
if(!configPath.toFile().getParentFile().mkdirs()) {
if (!configPath.toFile().getParentFile().exists()) {
throw new IOException("Can't create folder: " + configPath.toFile().getParentFile().getAbsolutePath());
}
}
FileOutputStream fileOutputStream = new FileOutputStream(configPath.toFile());
byte[] buf = new byte[1024];
int len;
while ((len = inputStream.read(buf)) > 0) {
fileOutputStream.write(buf, 0, len);
}
fileOutputStream.close();
inputStream.close();
}
}

View File

@@ -0,0 +1,35 @@
/*
* DmitriyMX <d.mihailov@samson-rus.com>
* 2017-05-17
*/
package asys.bridge.sponge;
import asys.bridge.client.AbstractBridge;
import asys.bridge.client.IBridge;
import asys.bridge.client.IConfig;
import asys.bridge.client.ILogger;
public class BridgeSpongeImpl extends AbstractBridge implements IBridge {
private LoggerSpongeImpl loggerSponge;
private ConfigSpongeImpl configSponge;
BridgeSpongeImpl(BridgeSponge spongePlugin) {
this.loggerSponge = new LoggerSpongeImpl(spongePlugin.getLogger());
this.configSponge = new ConfigSpongeImpl(spongePlugin.getConfigurationNode());
}
@Override
public ILogger getLogger() {
return loggerSponge;
}
@Override
public IConfig getConfig() {
return configSponge;
}
@Override
public int getCountOnlinePlayers() {
return 0; //FIXME fake online
}
}

View File

@@ -0,0 +1,26 @@
/*
* DmitriyMX <d.mihailov@samson-rus.com>
* 2017-05-17
*/
package asys.bridge.sponge;
import asys.bridge.client.IConfig;
import ninja.leaping.configurate.ConfigurationNode;
public class ConfigSpongeImpl implements IConfig {
private ConfigurationNode configurationNode;
ConfigSpongeImpl(ConfigurationNode configurationNode) {
this.configurationNode = configurationNode;
}
@Override
public String getString(String path) {
return configurationNode.getNode(path).getString();
}
@Override
public int getInt(String path) {
return configurationNode.getNode(path).getInt();
}
}

View File

@@ -0,0 +1,31 @@
/*
* DmitriyMX <d.mihailov@samson-rus.com>
* 2017-05-17
*/
package asys.bridge.sponge;
import asys.bridge.client.ILogger;
import org.slf4j.Logger;
public class LoggerSpongeImpl implements ILogger {
private Logger logger;
LoggerSpongeImpl(Logger logger) {
this.logger = logger;
}
@Override
public void info(String string) {
logger.info(string);
}
@Override
public void warn(String string) {
logger.warn(string);
}
@Override
public void error(String string) {
logger.error(string);
}
}

View File

@@ -13,13 +13,13 @@ subprojects {
}
subprojects {
if (!it.name.startsWith('bridge')) {
ext {
slf4jVersion = '1.7.21'
}
ext { slf4jVersion = '1.7.21' }
dependencies {
compile group: 'org.slf4j', name: 'slf4j-api', version: slf4jVersion
}
if (!it.name.startsWith('bridge')) {
dependencies {
compile group: 'org.slf4j', name: 'slf4j-api', version: slf4jVersion
compile group: 'org.osgi', name: 'org.osgi.core', version: '6.0.0'
}
}