mirror of
https://github.com/BGHDDevelopment/PlayerBalancer.git
synced 2024-11-23 11:15:30 +01:00
Version 2.0 (Initial commit)
This commit is contained in:
commit
c8399b12e0
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
target/
|
||||
*.iml
|
||||
*.jar
|
||||
.idea/
|
||||
dependency-reduced-pom.xml
|
2
README.md
Normal file
2
README.md
Normal file
@ -0,0 +1,2 @@
|
||||
# LobbyBalancer
|
||||
[Spigot](https://www.spigotmc.org/resources/10788/)
|
103
pom.xml
Normal file
103
pom.xml
Normal file
@ -0,0 +1,103 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>me.jaimemartz</groupId>
|
||||
<artifactId>lobbybalancer</artifactId>
|
||||
<version>2.0</version>
|
||||
<name>LobbyBalancer</name>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>bungee-repo</id>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>md_5-snapshots</id>
|
||||
<url>http://repo.md-5.net/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>inventive-repo</id>
|
||||
<url>http://repo.inventivetalent.org/content/groups/public/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<build>
|
||||
<defaultGoal>clean install</defaultGoal>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<version>3.1</version>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>2.3</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<minimizeJar>true</minimizeJar>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>net.md-5</groupId>
|
||||
<artifactId>bungeecord-api</artifactId>
|
||||
<version>1.9-SNAPSHOT</version>
|
||||
<type>jar</type>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.imaginarycode.minecraft</groupId>
|
||||
<artifactId>RedisBungee</artifactId>
|
||||
<version>0.3.8-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.inventivetalent.update</groupId>
|
||||
<artifactId>bungee</artifactId>
|
||||
<version>1.0.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>me.jaimemartz</groupId>
|
||||
<artifactId>faucet-bungee</artifactId>
|
||||
<version>1.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.maxmind.geoip2</groupId>
|
||||
<artifactId>geoip2</artifactId>
|
||||
<version>2.8.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
226
src/main/java/me/jaimemartz/lobbybalancer/LobbyBalancer.java
Normal file
226
src/main/java/me/jaimemartz/lobbybalancer/LobbyBalancer.java
Normal file
@ -0,0 +1,226 @@
|
||||
package me.jaimemartz.lobbybalancer;
|
||||
|
||||
import com.imaginarycode.minecraft.redisbungee.RedisBungee;
|
||||
import me.jaimemartz.faucet.ConfigFactory;
|
||||
import me.jaimemartz.lobbybalancer.commands.BackwardCommand;
|
||||
import me.jaimemartz.lobbybalancer.commands.MainCommand;
|
||||
import me.jaimemartz.lobbybalancer.configuration.ConfigEntries;
|
||||
import me.jaimemartz.lobbybalancer.connection.ServerAssignRegistry;
|
||||
import me.jaimemartz.lobbybalancer.listener.*;
|
||||
import me.jaimemartz.lobbybalancer.ping.PingManager;
|
||||
import me.jaimemartz.lobbybalancer.section.SectionManager;
|
||||
import me.jaimemartz.lobbybalancer.utils.AdapterFix;
|
||||
import me.jaimemartz.lobbybalancer.utils.GeolocationManager;
|
||||
import me.jaimemartz.lobbybalancer.utils.PlayerLocker;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.plugin.Command;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
import net.md_5.bungee.config.Configuration;
|
||||
import org.inventivetalent.update.bungee.BungeeUpdater;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class LobbyBalancer extends Plugin {
|
||||
public static final String USER_ID = "%%__USER__%%";
|
||||
public static final String RESOURCE_ID = "%%__RESOURCE__%%";
|
||||
public static final String NONCE_ID = "%%__NONCE__%%";
|
||||
|
||||
private boolean failed = false;
|
||||
|
||||
private ConfigFactory factory;
|
||||
private PingManager pingManager;
|
||||
private SectionManager sectionManager;
|
||||
private Command backwardCommand, mainCommand;
|
||||
private GeolocationManager geolocationManager;
|
||||
private Listener connectListener, kickListener, messageListener, reloadListener;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
instance = this;
|
||||
if (factory == null) {
|
||||
factory = new ConfigFactory(this);
|
||||
factory.register(0, "config.yml");
|
||||
factory.submit(ConfigEntries.class);
|
||||
}
|
||||
enable();
|
||||
}
|
||||
|
||||
private void enable() {
|
||||
factory.load(0, true);
|
||||
|
||||
mainCommand = new MainCommand(this);
|
||||
getProxy().getPluginManager().registerCommand(this, mainCommand);
|
||||
|
||||
if (ConfigEntries.AUTO_RELOAD_ENABLED.get()) {
|
||||
reloadListener = new ProxyReloadListener(this);
|
||||
getProxy().getPluginManager().registerListener(this, reloadListener);
|
||||
}
|
||||
|
||||
if (ConfigEntries.PLUGIN_ENABLED.get()) {
|
||||
if (ConfigEntries.CHECK_UPDATES_ENABLED.get()) {
|
||||
try {
|
||||
new BungeeUpdater(this, 10788);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
sectionManager = new SectionManager(this);
|
||||
|
||||
try {
|
||||
sectionManager.load();
|
||||
|
||||
if (ConfigEntries.SERVER_CHECK_ENABLED.get()) {
|
||||
pingManager = new PingManager(this);
|
||||
pingManager.start();
|
||||
}
|
||||
|
||||
if (ConfigEntries.BACKWARD_COMMAND_ENABLED.get()) {
|
||||
backwardCommand = new BackwardCommand(this);
|
||||
getProxy().getPluginManager().registerCommand(this, backwardCommand);
|
||||
}
|
||||
|
||||
connectListener = new ServerConnectListener(this);
|
||||
getProxy().getPluginManager().registerListener(this, connectListener);
|
||||
|
||||
messageListener = new PluginMessageListener(this);
|
||||
getProxy().getPluginManager().registerListener(this, messageListener);
|
||||
|
||||
getProxy().getPluginManager().registerListener(this, new PlayerDisconnectListener(this));
|
||||
|
||||
getProxy().registerChannel("LobbyBalancer");
|
||||
|
||||
if (ConfigEntries.RECONNECT_KICK_ENABLED.get()) {
|
||||
kickListener = new ServerKickListener(this);
|
||||
getProxy().getPluginManager().registerListener(this, kickListener);
|
||||
}
|
||||
|
||||
if (ConfigEntries.GEOLOCATION_ENABLED.get()) {
|
||||
LobbyBalancer.printStartupInfo("The geolocation feature has not been tested in depth");
|
||||
try {
|
||||
geolocationManager = new GeolocationManager(this);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
getLogger().info("The plugin has finished loading without any problems");
|
||||
} catch (RuntimeException e) {
|
||||
failed = true;
|
||||
getLogger().severe("The plugin could not continue loading due to an unexpected exception");
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
getLogger().warning("The plugin is disabled, so nothing will work except the main command");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
disable();
|
||||
}
|
||||
|
||||
private void disable() {
|
||||
getProxy().getPluginManager().unregisterCommand(mainCommand);
|
||||
mainCommand = null;
|
||||
if (ConfigEntries.AUTO_RELOAD_ENABLED.get()) {
|
||||
getProxy().getPluginManager().unregisterListener(reloadListener);
|
||||
reloadListener = null;
|
||||
}
|
||||
|
||||
if (ConfigEntries.PLUGIN_ENABLED.get()) {
|
||||
//Do not try to do anything if the plugin has not loaded correctly
|
||||
if (hasFailed()) return;
|
||||
|
||||
if (ConfigEntries.BACKWARD_COMMAND_ENABLED.get()) {
|
||||
getProxy().getPluginManager().unregisterCommand(backwardCommand);
|
||||
backwardCommand = null;
|
||||
}
|
||||
|
||||
getProxy().getPluginManager().unregisterListener(connectListener);
|
||||
connectListener = null;
|
||||
|
||||
getProxy().getPluginManager().unregisterListener(messageListener);
|
||||
messageListener = null;
|
||||
|
||||
if (ConfigEntries.RECONNECT_KICK_ENABLED.get()) {
|
||||
getProxy().getPluginManager().unregisterListener(kickListener);
|
||||
kickListener = null;
|
||||
}
|
||||
|
||||
sectionManager.flush();
|
||||
AdapterFix.getFakeServers().clear();
|
||||
|
||||
if (ConfigEntries.ASSIGN_TARGETS_ENABLED.get()) {
|
||||
ServerAssignRegistry.getTable().clear();
|
||||
}
|
||||
}
|
||||
PlayerLocker.flush();
|
||||
failed = false;
|
||||
}
|
||||
|
||||
public void reloadPlugin() {
|
||||
printStartupInfo("Reloading the plugin...");
|
||||
long starting = System.currentTimeMillis();
|
||||
|
||||
disable();
|
||||
enable();
|
||||
|
||||
long ending = System.currentTimeMillis() - starting;
|
||||
printStartupInfo("The plugin has been reloaded, took %sms", ending);
|
||||
}
|
||||
|
||||
public static int getPlayerCount(ServerInfo server) {
|
||||
if (ConfigEntries.REDIS_BUNGEE_ENABLED.get()) {
|
||||
try {
|
||||
RedisBungee.getApi().getPlayersOnServer(server.getName()).size();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return server.getPlayers().size();
|
||||
}
|
||||
|
||||
public static void checkSendMessage(CommandSender sender, String message) {
|
||||
if (message != null) {
|
||||
sender.sendMessage(TextComponent.fromLegacyText(message));
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean printStartupInfo(String format, Object... args) {
|
||||
if (ConfigEntries.SILENT_STARTUP.get()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
instance.getLogger().info(String.format(format, args));
|
||||
return true;
|
||||
}
|
||||
|
||||
public GeolocationManager getGeolocationManager() {
|
||||
return geolocationManager;
|
||||
}
|
||||
|
||||
public PingManager getPingManager() {
|
||||
return pingManager;
|
||||
}
|
||||
|
||||
public SectionManager getSectionManager() {
|
||||
return sectionManager;
|
||||
}
|
||||
|
||||
public boolean hasFailed() {
|
||||
return failed;
|
||||
}
|
||||
|
||||
public Configuration getConfig() {
|
||||
return factory.get(0).getHandle();
|
||||
}
|
||||
|
||||
private static LobbyBalancer instance;
|
||||
public static LobbyBalancer getInstance() {
|
||||
return instance;
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
package me.jaimemartz.lobbybalancer.commands;
|
||||
|
||||
import me.jaimemartz.faucet.Messager;
|
||||
import me.jaimemartz.lobbybalancer.LobbyBalancer;
|
||||
import me.jaimemartz.lobbybalancer.configuration.ConfigEntries;
|
||||
import me.jaimemartz.lobbybalancer.connection.ConnectionIntent;
|
||||
import me.jaimemartz.lobbybalancer.section.ServerSection;
|
||||
import me.jaimemartz.lobbybalancer.utils.PlayerLocker;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.plugin.Command;
|
||||
import net.md_5.bungee.config.Configuration;
|
||||
|
||||
public class BackwardCommand extends Command {
|
||||
private final LobbyBalancer plugin;
|
||||
public BackwardCommand(LobbyBalancer plugin) {
|
||||
super(ConfigEntries.BACKWARD_COMMAND_NAME.get(), ConfigEntries.BACKWARD_COMMAND_PERMISSION.get(), (ConfigEntries.BACKWARD_COMMAND_ALIASES.get().stream()).toArray(String[]::new));
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender, String[] args) {
|
||||
Messager msgr = new Messager(sender);
|
||||
if (sender instanceof ProxiedPlayer) {
|
||||
ProxiedPlayer player = (ProxiedPlayer) sender;
|
||||
|
||||
ServerSection section = plugin.getSectionManager().getByServer(player.getServer().getInfo());
|
||||
if (section != null) {
|
||||
if ((ConfigEntries.BACKWARD_COMMAND_IGNORED_SECTIONS.get()).contains(section.getName())) {
|
||||
msgr.send(ConfigEntries.UNAVAILABLE_MESSAGE.get());
|
||||
}
|
||||
|
||||
PlayerLocker.lock(player);
|
||||
|
||||
if (ConfigEntries.BACKWARD_COMMAND_ARGUMENTS.get() && args.length == 1) {
|
||||
ServerSection target = plugin.getSectionManager().getByName(args[0]);
|
||||
|
||||
if (target == null) {
|
||||
msgr.send(ConfigEntries.UNKNOWN_SECTION_MESSAGE.get());
|
||||
}
|
||||
|
||||
new ConnectionIntent(plugin, player, target) {
|
||||
@Override
|
||||
public void connect(ServerInfo server) {
|
||||
player.connect(server);
|
||||
PlayerLocker.unlock(player);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
Configuration rules = plugin.getConfig().getSection("settings.backward-command.rules");
|
||||
String name = rules.getString(section.getName());
|
||||
ServerSection target = plugin.getSectionManager().getByName(name);
|
||||
|
||||
if (target == null) {
|
||||
target = section.getParent();
|
||||
}
|
||||
|
||||
if (target == null) {
|
||||
msgr.send(ConfigEntries.UNAVAILABLE_MESSAGE.get());
|
||||
}
|
||||
|
||||
new ConnectionIntent(plugin, player, target) {
|
||||
@Override
|
||||
public void connect(ServerInfo server) {
|
||||
player.connect(server);
|
||||
PlayerLocker.unlock(player);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
} else {
|
||||
msgr.send(ConfigEntries.UNAVAILABLE_MESSAGE.get());
|
||||
}
|
||||
} else {
|
||||
msgr.send(ChatColor.RED + "This command can only be executed by a player");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
package me.jaimemartz.lobbybalancer.commands;
|
||||
|
||||
import me.jaimemartz.faucet.Messager;
|
||||
import me.jaimemartz.lobbybalancer.LobbyBalancer;
|
||||
import me.jaimemartz.lobbybalancer.utils.PasteHelper;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.plugin.Command;
|
||||
|
||||
public class MainCommand extends Command {
|
||||
private final LobbyBalancer plugin;
|
||||
|
||||
public MainCommand(LobbyBalancer plugin) {
|
||||
super("balancer");
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(final CommandSender sender, String[] args) {
|
||||
Messager msgr = new Messager(sender);
|
||||
if (args.length == 0) {
|
||||
msgr.send(
|
||||
"&e=====================================================",
|
||||
"&7Information: LobbyBalancer version " + plugin.getDescription().getVersion(),
|
||||
"&7Available commands:",
|
||||
"&3/balancer &7- &cShows this message",
|
||||
"&3/balancer paste &7- &cCreates a paste with the important files",
|
||||
"&3/balancer reload &7- &cReloads the plugin completely",
|
||||
"&e====================================================="
|
||||
);
|
||||
} else {
|
||||
switch (args[0]) {
|
||||
case "paste": {
|
||||
if (sender.hasPermission("lobbybalancer.admin")) {
|
||||
PasteHelper.LOGS.send(plugin, sender, "Last log file paste link: {link}");
|
||||
PasteHelper.PLUGIN.send(plugin, sender, "Plugin config paste link: {link}");
|
||||
PasteHelper.BUNGEE.send(plugin, sender, "Bungee config paste link (sensitive): {link}");
|
||||
} else {
|
||||
msgr.send(ChatColor.RED + "You do not have permission to execute this command!");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "reload": {
|
||||
if (sender.hasPermission("lobbybalancer.admin")) {
|
||||
msgr.send(ChatColor.GREEN + "Reloading the configuration, this may take a while...");
|
||||
plugin.reloadPlugin();
|
||||
msgr.send(ChatColor.GREEN + "The configuration has been reloaded");
|
||||
} else {
|
||||
msgr.send(ChatColor.RED + "You do not have permission to execute this command!");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
msgr.send(ChatColor.RED + "This is not a valid argument for this command!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package me.jaimemartz.lobbybalancer.configuration;
|
||||
|
||||
import me.jaimemartz.faucet.ConfigEntry;
|
||||
import me.jaimemartz.faucet.ConfigEntryHolder;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class ConfigEntries implements ConfigEntryHolder {
|
||||
public static final ConfigEntry<String> CONFIG_VERSION = new ConfigEntry<>(0, "version", null);
|
||||
public static final ConfigEntry<Boolean> PLUGIN_ENABLED = new ConfigEntry<>(0, "settings.enabled", false);
|
||||
public static final ConfigEntry<Boolean> SILENT_STARTUP = new ConfigEntry<>(0, "settings.silent-startup", false);
|
||||
public static final ConfigEntry<Boolean> CHECK_UPDATES_ENABLED = new ConfigEntry<>(0, "settings.check-updates", true);
|
||||
|
||||
public static final ConfigEntry<Boolean> SERVER_CHECK_ENABLED = new ConfigEntry<>(0, "settings.server_check.enabled", true);
|
||||
public static final ConfigEntry<String> SERVER_CHECK_MODE = new ConfigEntry<>(0, "settings.server_check.tactic", "CUSTOM");
|
||||
public static final ConfigEntry<Integer> SERVER_CHECK_ATTEMPTS = new ConfigEntry<>(0, "settings.server_check.attempts", 5);
|
||||
public static final ConfigEntry<Integer> SERVER_CHECK_INTERVAL = new ConfigEntry<>(0, "settings.server_check.interval", 10000);
|
||||
public static final ConfigEntry<Boolean> SERVER_CHECK_PRINT_INFO = new ConfigEntry<>(0, "settings.server_check.print-info", false);
|
||||
public static final ConfigEntry<List<String>> SERVER_CHECK_MARKER_MOTDS = new ConfigEntry<>(0, "settings.server_check.marker-motds", Arrays.asList("Server is not accessible", "Gamemode has already started"));
|
||||
|
||||
public static final ConfigEntry<Boolean> GEOLOCATION_ENABLED = new ConfigEntry<>(0, "settings.geolocation.enabled", true);
|
||||
|
||||
public static final ConfigEntry<Boolean> RECONNECT_KICK_ENABLED = new ConfigEntry<>(0, "settings.reconnect-kick.enabled", true);
|
||||
public static final ConfigEntry<Boolean> RECONNECT_KICK_INVERTED = new ConfigEntry<>(0, "settings.reconnect-kick.inverted", false);
|
||||
public static final ConfigEntry<List<String>> RECONNECT_KICK_REASONS = new ConfigEntry<>(0, "settings.reconnect-kick.reasons", Collections.emptyList());
|
||||
public static final ConfigEntry<Boolean> RECONNECT_KICK_PRINT_INFO = new ConfigEntry<>(0, "settings.reconnect-kick.print-info", false);
|
||||
public static final ConfigEntry<List<String>> RECONNECT_KICK_IGNORED_SECTIONS = new ConfigEntry<>(0, "settings.reconnect-kick.ignored", Collections.emptyList());
|
||||
public static final ConfigEntry<String> RECONNECT_KICK_MESSAGE = new ConfigEntry<>(0, "settings.reconnect-kick.message", "&cYou have been kicked from &a{from} &cand you are being moved to &a{to}&c, reason: &a{reason}");
|
||||
|
||||
public static final ConfigEntry<Boolean> BACKWARD_COMMAND_ENABLED = new ConfigEntry<>(0, "settings.backward-command.enabled", true);
|
||||
public static final ConfigEntry<String> BACKWARD_COMMAND_NAME = new ConfigEntry<>(0, "settings.backward-command.name", "backward");
|
||||
public static final ConfigEntry<List<String>> BACKWARD_COMMAND_ALIASES = new ConfigEntry<>(0, "settings.backward-command.aliases", Arrays.asList("lobby", "hub", "back"));
|
||||
public static final ConfigEntry<String> BACKWARD_COMMAND_PERMISSION = new ConfigEntry<>(0, "settings.backward-command.permission", "");
|
||||
public static final ConfigEntry<List<String>> BACKWARD_COMMAND_IGNORED_SECTIONS = new ConfigEntry<>(0, "settings.backward-command.ignored", Collections.emptyList());
|
||||
public static final ConfigEntry<Boolean> BACKWARD_COMMAND_ARGUMENTS = new ConfigEntry<>(0, "settings.backward-command.arguments", true);
|
||||
|
||||
public static final ConfigEntry<Boolean> AUTO_RELOAD_ENABLED = new ConfigEntry<>(0, "settings.auto-reload", true);
|
||||
public static final ConfigEntry<Boolean> REDIS_BUNGEE_ENABLED = new ConfigEntry<>(0, "settings.redis-bungee", false);
|
||||
public static final ConfigEntry<Boolean> ASSIGN_TARGETS_ENABLED = new ConfigEntry<>(0, "settings.assign-targets", false);
|
||||
|
||||
public static final ConfigEntry<String> CONNECTING_MESSAGE = new ConfigEntry<>(0, "settings.messages.connecting", "&aConnecting to {server}");
|
||||
public static final ConfigEntry<String> FAILURE_MESSAGE = new ConfigEntry<>(0, "settings.messages.failure", "&cCould not find a server to connect to");
|
||||
public static final ConfigEntry<String> UNAVAILABLE_MESSAGE = new ConfigEntry<>(0, "settings.messages.unavailable", "&cThis command cannot be executed on this server");
|
||||
public static final ConfigEntry<String> UNKNOWN_SECTION_MESSAGE = new ConfigEntry<>(0, "settings.messages.unknown", "&cCould not find a section with that name");
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
package me.jaimemartz.lobbybalancer.configuration;
|
||||
|
||||
import me.jaimemartz.faucet.ConfigEntry;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ConfigHelper {
|
||||
public static Object get(ConfigEntry<Object> entry) {
|
||||
return entry.get();
|
||||
}
|
||||
|
||||
public static String getString(ConfigEntry<String> entry) {
|
||||
return entry.get();
|
||||
}
|
||||
|
||||
public static List<String> getStringList(ConfigEntry<List<String>> entry) {
|
||||
return entry.get();
|
||||
}
|
||||
|
||||
public static boolean getBoolean(ConfigEntry<Boolean> entry) {
|
||||
return entry.get();
|
||||
}
|
||||
|
||||
public static List<Boolean> getBooleanList(ConfigEntry<List<Boolean>> entry) {
|
||||
return entry.get();
|
||||
}
|
||||
|
||||
public static byte getByte(ConfigEntry<Byte> entry) {
|
||||
return entry.get();
|
||||
}
|
||||
|
||||
public static List<Byte> getByteList(ConfigEntry<List<Byte>> entry) {
|
||||
return entry.get();
|
||||
}
|
||||
|
||||
public static char getChar(ConfigEntry<Character> entry) {
|
||||
return entry.get();
|
||||
}
|
||||
|
||||
public static List<Character> getCharList(ConfigEntry<List<Character>> entry) {
|
||||
return entry.get();
|
||||
}
|
||||
|
||||
public static double getDouble(ConfigEntry<Double> entry) {
|
||||
return entry.get();
|
||||
}
|
||||
|
||||
public static List<Double> getDoubleList(ConfigEntry<List<Double>> entry) {
|
||||
return entry.get();
|
||||
}
|
||||
|
||||
public static float getFloat(ConfigEntry<Float> entry) {
|
||||
return entry.get();
|
||||
}
|
||||
|
||||
public static List<Float> getFloatList(ConfigEntry<List<Float>> entry) {
|
||||
return entry.get();
|
||||
}
|
||||
|
||||
public static int getInt(ConfigEntry<Integer> entry) {
|
||||
return entry.get();
|
||||
}
|
||||
|
||||
public static List<Integer> getIntList(ConfigEntry<List<Integer>> entry) {
|
||||
return entry.get();
|
||||
}
|
||||
|
||||
public static long getLong(ConfigEntry<Long> entry) {
|
||||
return entry.get();
|
||||
}
|
||||
|
||||
public static List<Long> getLongList(ConfigEntry<List<Long>> entry) {
|
||||
return entry.get();
|
||||
}
|
||||
|
||||
public static short getShort(ConfigEntry<Short> entry) {
|
||||
return entry.get();
|
||||
}
|
||||
|
||||
public static List<Short> getShortList(ConfigEntry<List<Short>> entry) {
|
||||
return entry.get();
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
package me.jaimemartz.lobbybalancer.connection;
|
||||
|
||||
import me.jaimemartz.faucet.Messager;
|
||||
import me.jaimemartz.lobbybalancer.LobbyBalancer;
|
||||
import me.jaimemartz.lobbybalancer.configuration.ConfigEntries;
|
||||
import me.jaimemartz.lobbybalancer.ping.ServerStatus;
|
||||
import me.jaimemartz.lobbybalancer.section.ServerSection;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class ConnectionIntent {
|
||||
public ConnectionIntent(LobbyBalancer plugin, ProxiedPlayer player, ServerSection section) {
|
||||
ServerInfo target = this.findTarget(plugin, player, section);
|
||||
Messager msgr = new Messager(player);
|
||||
|
||||
if (target != null) {
|
||||
msgr.send((ConfigEntries.CONNECTING_MESSAGE.get()).replace("{server}", target.getName()));
|
||||
this.connect(target);
|
||||
} else {
|
||||
msgr.send(ConfigEntries.FAILURE_MESSAGE.get());
|
||||
this.failure();
|
||||
}
|
||||
}
|
||||
|
||||
private ServerInfo findTarget(LobbyBalancer plugin, ProxiedPlayer player, ServerSection section) {
|
||||
if (ConfigEntries.ASSIGN_TARGETS_ENABLED.get()) {
|
||||
if (ServerAssignRegistry.hasAssignedServer(player, section)) {
|
||||
ServerInfo target = ServerAssignRegistry.getAssignedServer(player, section);
|
||||
ServerStatus status = plugin.getPingManager().getStatus(target);
|
||||
if (status.isAccessible()) {
|
||||
return target;
|
||||
} else {
|
||||
ServerAssignRegistry.revokeTarget(player, section);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProviderType provider = section.getProvider();
|
||||
int intents = ConfigEntries.SERVER_CHECK_ATTEMPTS.get();
|
||||
List<ServerInfo> servers = new ArrayList<>();
|
||||
servers.addAll(section.getServers());
|
||||
|
||||
while (intents-- >= 1) {
|
||||
ServerInfo target = provider.requestTarget(plugin, section, servers, player);
|
||||
if (target == null) continue;
|
||||
|
||||
if (servers.size() == 0) return null;
|
||||
if (servers.size() == 1) return servers.get(0);
|
||||
|
||||
ServerStatus status = plugin.getPingManager().getStatus(target);
|
||||
if (status.isAccessible()) {
|
||||
return target;
|
||||
} else {
|
||||
servers.remove(target);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract void connect(ServerInfo server);
|
||||
|
||||
public void failure() {
|
||||
//Nothing to do
|
||||
}
|
||||
}
|
@ -0,0 +1,137 @@
|
||||
package me.jaimemartz.lobbybalancer.connection;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.maxmind.geoip2.exception.GeoIp2Exception;
|
||||
import com.maxmind.geoip2.model.CountryResponse;
|
||||
import com.maxmind.geoip2.record.Country;
|
||||
import me.jaimemartz.lobbybalancer.LobbyBalancer;
|
||||
import me.jaimemartz.lobbybalancer.configuration.ConfigEntries;
|
||||
import me.jaimemartz.lobbybalancer.ping.ServerStatus;
|
||||
import me.jaimemartz.lobbybalancer.section.ServerSection;
|
||||
import me.jaimemartz.lobbybalancer.utils.ConfigUtils;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.config.Configuration;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public enum ProviderType {
|
||||
NONE(0, "Returns no server") {
|
||||
@Override
|
||||
public ServerInfo requestTarget(LobbyBalancer plugin, ServerSection section, List<ServerInfo> list, ProxiedPlayer player) {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
DIRECT(1, "Returns the only server in the list") {
|
||||
@Override
|
||||
public ServerInfo requestTarget(LobbyBalancer plugin, ServerSection section, List<ServerInfo> list, ProxiedPlayer player) {
|
||||
return Iterables.getOnlyElement(list);
|
||||
}
|
||||
},
|
||||
LOCALIZED(2, "Returns the server that matches a region") {
|
||||
@Override
|
||||
public ServerInfo requestTarget(LobbyBalancer plugin, ServerSection section, List<ServerInfo> list, ProxiedPlayer player) {
|
||||
Configuration rules = plugin.getConfig().getSection("settings.geolocation.rules");
|
||||
if (ConfigEntries.GEOLOCATION_ENABLED.get() && ConfigUtils.isSet(rules, section.getName())) {
|
||||
Configuration rule = rules.getSection(section.getName());
|
||||
InetAddress address = player.getAddress().getAddress();
|
||||
|
||||
try {
|
||||
CountryResponse countryResponse = plugin.getGeolocationManager().getReader().country(address);
|
||||
Country country = countryResponse.getCountry();
|
||||
|
||||
for (String name : rule.getKeys()) {
|
||||
List<String> countries = rule.getStringList(name);
|
||||
if (countries.contains(country.getName().toUpperCase())) {
|
||||
ServerInfo server = plugin.getProxy().getServerInfo(name);
|
||||
if (server != null) {
|
||||
return server;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (IOException | GeoIp2Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return list.get(ThreadLocalRandom.current().nextInt(list.size()));
|
||||
}
|
||||
},
|
||||
LOWEST(3, "Returns the server with the least players online") {
|
||||
@Override
|
||||
public ServerInfo requestTarget(LobbyBalancer plugin, ServerSection section, List<ServerInfo> list, ProxiedPlayer player) {
|
||||
int min = Integer.MAX_VALUE;
|
||||
ServerInfo target = null;
|
||||
|
||||
for (ServerInfo server : list) {
|
||||
int count = LobbyBalancer.getPlayerCount(server);
|
||||
|
||||
if (count < min) {
|
||||
min = count;
|
||||
target = server;
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
},
|
||||
RANDOM(4, "Returns a random server") {
|
||||
@Override
|
||||
public ServerInfo requestTarget(LobbyBalancer plugin, ServerSection section, List<ServerInfo> list, ProxiedPlayer player) {
|
||||
return list.get(ThreadLocalRandom.current().nextInt(list.size()));
|
||||
}
|
||||
},
|
||||
PROGRESSIVE(5, "Returns the first server that is not full") {
|
||||
@Override
|
||||
public ServerInfo requestTarget(LobbyBalancer plugin, ServerSection section, List<ServerInfo> list, ProxiedPlayer player) {
|
||||
for (ServerInfo server : list) {
|
||||
ServerStatus status = plugin.getPingManager().getStatus(server);
|
||||
if (LobbyBalancer.getPlayerCount(server) < status.getMaximumPlayers()) {
|
||||
return server;
|
||||
}
|
||||
}
|
||||
|
||||
return list.get(ThreadLocalRandom.current().nextInt(list.size()));
|
||||
}
|
||||
},
|
||||
FILLER(6, "Returns the server with the most players online that is not full") {
|
||||
@Override
|
||||
public ServerInfo requestTarget(LobbyBalancer plugin, ServerSection section, List<ServerInfo> list, ProxiedPlayer player) {
|
||||
int max = Integer.MIN_VALUE;
|
||||
ServerInfo target = null;
|
||||
|
||||
for (ServerInfo server : list) {
|
||||
ServerStatus status = plugin.getPingManager().getStatus(server);
|
||||
int count = LobbyBalancer.getPlayerCount(server);
|
||||
|
||||
if (count > max && count <= status.getMaximumPlayers()) {
|
||||
max = count;
|
||||
target = server;
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
};
|
||||
|
||||
private final int id;
|
||||
private final String description;
|
||||
|
||||
ProviderType(int id, String description) {
|
||||
this.id = id;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public abstract ServerInfo requestTarget(LobbyBalancer plugin, ServerSection section, List<ServerInfo> list, ProxiedPlayer player);
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package me.jaimemartz.lobbybalancer.connection;
|
||||
|
||||
import com.google.common.collect.HashBasedTable;
|
||||
import com.google.common.collect.Table;
|
||||
import me.jaimemartz.lobbybalancer.section.ServerSection;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class ServerAssignRegistry {
|
||||
private static final Table<ProxiedPlayer, ServerSection, ServerInfo> table = HashBasedTable.create();
|
||||
|
||||
public static void assignTarget(ProxiedPlayer player, ServerSection group, ServerInfo server) {
|
||||
synchronized (table) {
|
||||
table.put(player, group, server);
|
||||
}
|
||||
}
|
||||
|
||||
public static void revokeTarget(ProxiedPlayer player, ServerSection group) {
|
||||
synchronized (table) {
|
||||
table.remove(player, group);
|
||||
}
|
||||
}
|
||||
|
||||
public static ServerInfo getAssignedServer(ProxiedPlayer player, ServerSection group) {
|
||||
synchronized (table) {
|
||||
return table.get(player, group);
|
||||
}
|
||||
}
|
||||
|
||||
public static Map<ServerSection, ServerInfo> getAssignments(ProxiedPlayer player) {
|
||||
synchronized (table) {
|
||||
return table.row(player);
|
||||
}
|
||||
}
|
||||
|
||||
public static void clearAsssignedServers(ProxiedPlayer player) {
|
||||
synchronized (table) {
|
||||
table.row(player).clear();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasAssignedServer(ProxiedPlayer player, ServerSection group) {
|
||||
synchronized (table) {
|
||||
return table.contains(player, group);
|
||||
}
|
||||
}
|
||||
|
||||
public static Table<ProxiedPlayer, ServerSection, ServerInfo> getTable() {
|
||||
synchronized (table) {
|
||||
return table;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package me.jaimemartz.lobbybalancer.listener;
|
||||
|
||||
import me.jaimemartz.lobbybalancer.LobbyBalancer;
|
||||
import me.jaimemartz.lobbybalancer.configuration.ConfigEntries;
|
||||
import me.jaimemartz.lobbybalancer.connection.ServerAssignRegistry;
|
||||
import me.jaimemartz.lobbybalancer.utils.PlayerLocker;
|
||||
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
import net.md_5.bungee.event.EventPriority;
|
||||
|
||||
public class PlayerDisconnectListener implements Listener {
|
||||
private final LobbyBalancer plugin;
|
||||
|
||||
public PlayerDisconnectListener(LobbyBalancer plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onDisconnect(PlayerDisconnectEvent event) {
|
||||
PlayerLocker.unlock(event.getPlayer());
|
||||
|
||||
//Delete this if we want to keep assigned groups even when leaving
|
||||
if (ConfigEntries.ASSIGN_TARGETS_ENABLED.get()) {
|
||||
ServerAssignRegistry.clearAsssignedServers(event.getPlayer());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package me.jaimemartz.lobbybalancer.listener;
|
||||
|
||||
import com.google.common.io.ByteArrayDataInput;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import me.jaimemartz.lobbybalancer.LobbyBalancer;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.Server;
|
||||
import net.md_5.bungee.api.event.PluginMessageEvent;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class PluginMessageListener implements Listener {
|
||||
private final LobbyBalancer plugin;
|
||||
|
||||
public PluginMessageListener(LobbyBalancer plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPluginMessage(PluginMessageEvent event) {
|
||||
if (event.getTag().equals("LobbyBalancer") && event.getSender() instanceof Server) {
|
||||
ByteArrayDataInput in = ByteStreams.newDataInput(event.getData());
|
||||
String request = in.readUTF();
|
||||
ServerInfo sender = ((Server) event.getSender()).getInfo();
|
||||
switch (request) {
|
||||
default: {
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
DataOutputStream out = new DataOutputStream(stream);
|
||||
|
||||
try {
|
||||
out.writeUTF("The plugin message api for LobbyBalancer is not ready yet, it will be implemented in a future version");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
sender.sendData("LobbyBalancer", stream.toByteArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package me.jaimemartz.lobbybalancer.listener;
|
||||
|
||||
import me.jaimemartz.lobbybalancer.LobbyBalancer;
|
||||
import net.md_5.bungee.api.event.ProxyReloadEvent;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
import net.md_5.bungee.event.EventPriority;
|
||||
|
||||
public class ProxyReloadListener implements Listener {
|
||||
private final LobbyBalancer plugin;
|
||||
|
||||
public ProxyReloadListener(LobbyBalancer plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onReload(ProxyReloadEvent event) {
|
||||
plugin.getLogger().info("BungeeCord has been reloaded, reloading the plugin...");
|
||||
plugin.reloadPlugin();
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package me.jaimemartz.lobbybalancer.listener;
|
||||
|
||||
import me.jaimemartz.faucet.Messager;
|
||||
import me.jaimemartz.lobbybalancer.LobbyBalancer;
|
||||
import me.jaimemartz.lobbybalancer.configuration.ConfigEntries;
|
||||
import me.jaimemartz.lobbybalancer.connection.ConnectionIntent;
|
||||
import me.jaimemartz.lobbybalancer.connection.ServerAssignRegistry;
|
||||
import me.jaimemartz.lobbybalancer.section.ServerSection;
|
||||
import me.jaimemartz.lobbybalancer.utils.PlayerLocker;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.ServerConnectEvent;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
import net.md_5.bungee.event.EventPriority;
|
||||
|
||||
public class ServerConnectListener implements Listener {
|
||||
private final LobbyBalancer plugin;
|
||||
|
||||
public ServerConnectListener(LobbyBalancer plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onConnect(ServerConnectEvent event) {
|
||||
ProxiedPlayer player = event.getPlayer();
|
||||
ServerInfo target = event.getTarget();
|
||||
Messager msgr = new Messager(player);
|
||||
ServerSection section = plugin.getSectionManager().getByServer(target);
|
||||
|
||||
if (section == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (section.getServers().contains(target)) {
|
||||
if (PlayerLocker.isLocked(player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.hasPermission("lobbybalancer.bypass")) {
|
||||
msgr.send(ChatColor.RED + "You have not been moved because you have the lobbybalancer.bypass permission");
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.getServer() != null && section.getServers().contains(player.getServer().getInfo())) {
|
||||
if (ConfigEntries.ASSIGN_TARGETS_ENABLED.get()) {
|
||||
ServerAssignRegistry.assignTarget(player, section, target);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new ConnectionIntent(plugin, player, section) {
|
||||
@Override
|
||||
public void connect(ServerInfo server) {
|
||||
if (ConfigEntries.ASSIGN_TARGETS_ENABLED.get()) {
|
||||
ServerAssignRegistry.assignTarget(player, section, server);
|
||||
}
|
||||
event.setTarget(server);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
package me.jaimemartz.lobbybalancer.listener;
|
||||
|
||||
import me.jaimemartz.lobbybalancer.LobbyBalancer;
|
||||
import me.jaimemartz.lobbybalancer.configuration.ConfigEntries;
|
||||
import me.jaimemartz.lobbybalancer.connection.ConnectionIntent;
|
||||
import me.jaimemartz.lobbybalancer.section.ServerSection;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.ServerKickEvent;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.config.Configuration;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
import net.md_5.bungee.event.EventPriority;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class ServerKickListener implements Listener {
|
||||
private final LobbyBalancer plugin;
|
||||
|
||||
public ServerKickListener(LobbyBalancer plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onKick(ServerKickEvent event) {
|
||||
ProxiedPlayer player = event.getPlayer();
|
||||
ServerInfo from = event.getKickedFrom();
|
||||
|
||||
if (player.getServer() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player.getServer().getInfo().equals(from)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ServerSection section = plugin.getSectionManager().getByServer(from);
|
||||
if (section != null) {
|
||||
if ((ConfigEntries.RECONNECT_KICK_IGNORED_SECTIONS.get()).contains(section.getName())) {
|
||||
return;
|
||||
}
|
||||
|
||||
Configuration rules = plugin.getConfig().getSection("settings.reconnect-kick.rules");
|
||||
String name = rules.getString(section.getName());
|
||||
ServerSection target = plugin.getSectionManager().getByName(name);
|
||||
|
||||
if (target == null) {
|
||||
target = section.getParent();
|
||||
if (target == null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
AtomicBoolean matches = new AtomicBoolean(false);
|
||||
String reason = TextComponent.toPlainText(event.getKickReasonComponent());
|
||||
for (String pattern : ConfigEntries.RECONNECT_KICK_REASONS.get()) {
|
||||
if (reason.matches(pattern)) {
|
||||
matches.set(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ConfigEntries.RECONNECT_KICK_INVERTED.get()) {
|
||||
matches.set(!matches.get());
|
||||
}
|
||||
|
||||
if (matches.get()) {
|
||||
new ConnectionIntent(plugin, player, target) {
|
||||
@Override
|
||||
public void connect(ServerInfo server) {
|
||||
LobbyBalancer.checkSendMessage(player, ConfigEntries.RECONNECT_KICK_MESSAGE.get()
|
||||
.replace("{from}", from.getName())
|
||||
.replace("{to}", server.getName())
|
||||
.replace("{reason}", reason)
|
||||
);
|
||||
|
||||
event.setCancelled(true);
|
||||
event.setCancelServer(server);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (ConfigEntries.RECONNECT_KICK_PRINT_INFO.get()) {
|
||||
LobbyBalancer.printStartupInfo(String.format("Kick Reason: \"%s\", Found Match: %s", TextComponent.toPlainText(event.getKickReasonComponent()), matches.get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package me.jaimemartz.lobbybalancer.ping;
|
||||
|
||||
public abstract class PingCallback {
|
||||
public abstract void onPong(ServerStatus info);
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
package me.jaimemartz.lobbybalancer.ping;
|
||||
|
||||
import me.jaimemartz.lobbybalancer.LobbyBalancer;
|
||||
import me.jaimemartz.lobbybalancer.configuration.ConfigEntries;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.scheduler.ScheduledTask;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class PingManager {
|
||||
private final LobbyBalancer plugin;
|
||||
private boolean stopped = true;
|
||||
private PingTacticType tactic;
|
||||
private ScheduledTask task;
|
||||
private final Map<ServerInfo, ServerStatus> storage = new HashMap<>();
|
||||
|
||||
public PingManager(LobbyBalancer plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
if (task != null) {
|
||||
stop();
|
||||
}
|
||||
stopped = false;
|
||||
tactic = PingTacticType.valueOf((ConfigEntries.SERVER_CHECK_MODE.get()).toUpperCase());
|
||||
LobbyBalancer.printStartupInfo(String.format("Starting the ping task, the interval is %s", ConfigEntries.SERVER_CHECK_INTERVAL.get()));
|
||||
task = plugin.getProxy().getScheduler().schedule(plugin, () -> {
|
||||
for (ServerInfo server : plugin.getProxy().getServers().values()) {
|
||||
if (stopped) break;
|
||||
if (server != null) {
|
||||
track(server);
|
||||
}
|
||||
}
|
||||
}, 0L, ConfigEntries.SERVER_CHECK_INTERVAL.get(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (task != null) {
|
||||
task.cancel();
|
||||
task = null;
|
||||
stopped = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void track(ServerInfo server) {
|
||||
tactic.ping(server, new PingCallback() {
|
||||
@Override
|
||||
public void onPong(ServerStatus status) {
|
||||
/* FIXME: 08/01/2017 Not sure if necessary
|
||||
if (status.isAccessible()) {
|
||||
if (LobbyBalancer.getPlayerCount(server) > status.getMaximumPlayers()) {
|
||||
status.setAccessible(false);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
if (ConfigEntries.SERVER_CHECK_PRINT_INFO.get()) {
|
||||
plugin.getLogger().info(String.format(
|
||||
"Tracking server %s, status: [Description: \"%s\", Online Players: %s, Maximum Players: %s, Accessible: %s]",
|
||||
server.getName(), status.getDescription(), status.getOnlinePlayers(), status.getMaximumPlayers(), status.isAccessible())
|
||||
);
|
||||
}
|
||||
storage.put(server, status);
|
||||
}
|
||||
}, plugin);
|
||||
}
|
||||
|
||||
public ServerStatus getStatus(ServerInfo server) {
|
||||
if (stopped) {
|
||||
return new ServerStatus(server.getMotd(), server.getPlayers().size(), Integer.MAX_VALUE);
|
||||
} else {
|
||||
return storage.get(server);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package me.jaimemartz.lobbybalancer.ping;
|
||||
|
||||
import me.jaimemartz.faucet.ServerListPing;
|
||||
import me.jaimemartz.faucet.StatusResponse;
|
||||
import me.jaimemartz.lobbybalancer.LobbyBalancer;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public enum PingTacticType {
|
||||
CUSTOM {
|
||||
ServerListPing utility = new ServerListPing();
|
||||
|
||||
@Override
|
||||
public void ping(ServerInfo server, PingCallback callback, LobbyBalancer plugin) {
|
||||
plugin.getProxy().getScheduler().runAsync(plugin, () -> {
|
||||
try {
|
||||
StatusResponse response = utility.ping(server.getAddress());
|
||||
callback.onPong(new ServerStatus(
|
||||
response.getDescription().toLegacyText(),
|
||||
response.getPlayers().getOnline(),
|
||||
response.getPlayers().getMax()
|
||||
));
|
||||
} catch (IOException e) {
|
||||
callback.onPong(new ServerStatus("Server Unreachable", 0, 0));
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
GENERIC {
|
||||
@Override
|
||||
public void ping(ServerInfo server, PingCallback callback, LobbyBalancer plugin) {
|
||||
try {
|
||||
server.ping((ping, throwable) -> {
|
||||
if (ping != null && throwable == null) {
|
||||
callback.onPong(new ServerStatus(
|
||||
ping.getDescription(),
|
||||
ping.getPlayers().getOnline(),
|
||||
ping.getPlayers().getMax()
|
||||
));
|
||||
} else {
|
||||
callback.onPong(new ServerStatus("Server Unreachable", 0, 0));
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
callback.onPong(new ServerStatus("Server Unreachable", 0, 0));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public abstract void ping(ServerInfo server, PingCallback callback, LobbyBalancer plugin);
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package me.jaimemartz.lobbybalancer.ping;
|
||||
|
||||
import me.jaimemartz.lobbybalancer.configuration.ConfigEntries;
|
||||
|
||||
public final class ServerStatus {
|
||||
private final String description;
|
||||
private final int online, maximum;
|
||||
private boolean accessible;
|
||||
|
||||
public ServerStatus(String description, int online, int maximum) {
|
||||
this.description = description;
|
||||
this.online = online;
|
||||
this.maximum = maximum;
|
||||
boolean accessible = true;
|
||||
if (maximum != 0) {
|
||||
for (String pattern : ConfigEntries.SERVER_CHECK_MARKER_MOTDS.get()) {
|
||||
if (description.contains(pattern) || description.matches(pattern)) {
|
||||
accessible = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (online >= maximum) {
|
||||
accessible = false;
|
||||
}
|
||||
} else {
|
||||
accessible = false;
|
||||
}
|
||||
this.accessible = accessible;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public int getOnlinePlayers() {
|
||||
return online;
|
||||
}
|
||||
|
||||
public int getMaximumPlayers() {
|
||||
return maximum;
|
||||
}
|
||||
|
||||
public boolean isAccessible() {
|
||||
return accessible;
|
||||
}
|
||||
|
||||
public void setAccessible(boolean accessible) {
|
||||
this.accessible = accessible;
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package me.jaimemartz.lobbybalancer.section;
|
||||
|
||||
import me.jaimemartz.faucet.Messager;
|
||||
import me.jaimemartz.lobbybalancer.LobbyBalancer;
|
||||
import me.jaimemartz.lobbybalancer.connection.ConnectionIntent;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.plugin.Command;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class SectionCommand extends Command {
|
||||
private final LobbyBalancer plugin;
|
||||
private final ServerSection section;
|
||||
|
||||
public SectionCommand(LobbyBalancer plugin, String name, String permission, List<String> aliases, ServerSection section) {
|
||||
super(name, permission, aliases.stream().toArray(String[]::new));
|
||||
this.plugin = plugin;
|
||||
this.section = section;
|
||||
plugin.getProxy().getPluginManager().registerCommand(plugin, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender, String[] args) {
|
||||
Messager msgr = new Messager(sender);
|
||||
if (sender instanceof ProxiedPlayer) {
|
||||
ProxiedPlayer player = (ProxiedPlayer) sender;
|
||||
new ConnectionIntent(plugin, player, section) {
|
||||
@Override
|
||||
public void connect(ServerInfo server) {
|
||||
player.connect(server);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
msgr.send(ChatColor.RED + "This command can only be executed by a player");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
package me.jaimemartz.lobbybalancer.section;
|
||||
|
||||
import me.jaimemartz.lobbybalancer.LobbyBalancer;
|
||||
import me.jaimemartz.lobbybalancer.utils.AdapterFix;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.config.Configuration;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class SectionManager {
|
||||
private final LobbyBalancer plugin;
|
||||
private final Map<String, ServerSection> sectionStorage = new ConcurrentHashMap<>();
|
||||
private final Map<ServerInfo, ServerSection> sectionServers = new ConcurrentHashMap<>();
|
||||
|
||||
public SectionManager(LobbyBalancer plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public void load() throws RuntimeException {
|
||||
LobbyBalancer.printStartupInfo("Loading sections from the config, this may take a while...");
|
||||
long starting = System.currentTimeMillis();
|
||||
|
||||
Configuration sections = plugin.getConfig().getSection("sections");
|
||||
sections.getKeys().forEach(name -> {
|
||||
LobbyBalancer.printStartupInfo("Construction of section with name \"%s\"", name);
|
||||
Configuration section = sections.getSection(name);
|
||||
ServerSection object = new ServerSection(name, section, this);
|
||||
sectionStorage.put(name, object);
|
||||
});
|
||||
|
||||
sectionStorage.forEach((name, section) -> {
|
||||
LobbyBalancer.printStartupInfo("Pre-Initialization of section with name \"%s\"", name);
|
||||
section.preInit(plugin);
|
||||
});
|
||||
|
||||
sectionStorage.forEach((name, section) -> {
|
||||
LobbyBalancer.printStartupInfo("Initialization of section with name \"%s\"", name);
|
||||
section.load(plugin);
|
||||
});
|
||||
|
||||
sectionStorage.forEach((name, section) -> {
|
||||
LobbyBalancer.printStartupInfo("Post-Initialization of section with name \"%s\"", name);
|
||||
section.postInit(plugin);
|
||||
});
|
||||
|
||||
AdapterFix.inject(plugin.getProxy());
|
||||
|
||||
long ending = System.currentTimeMillis() - starting;
|
||||
LobbyBalancer.printStartupInfo("A total of %s section(s) have been loaded in %sms", sectionStorage.size(), ending);
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
LobbyBalancer.printStartupInfo("Flushing section storage because of plugin shutdown");
|
||||
sectionStorage.forEach((key, value) -> {
|
||||
value.setValid(false);
|
||||
|
||||
if (value.hasCommand()) {
|
||||
SectionCommand command = value.getCommand();
|
||||
plugin.getProxy().getPluginManager().unregisterCommand(command);
|
||||
}
|
||||
|
||||
if (value.hasServer()) {
|
||||
AdapterFix.removeFakeServer(value.getServer());
|
||||
}
|
||||
});
|
||||
|
||||
sectionStorage.clear();
|
||||
sectionServers.clear();
|
||||
}
|
||||
|
||||
void register(ServerInfo server, ServerSection section) {
|
||||
if (sectionServers.containsKey(server)) {
|
||||
ServerSection other = sectionServers.get(server);
|
||||
throw new IllegalArgumentException(String.format("The server \"%s\" is already in the section \"%s\"", server.getName(), other.getName()));
|
||||
}
|
||||
|
||||
LobbyBalancer.printStartupInfo("Registering server \"%s\" to section \"%s\"", server.getName(), section.getName());
|
||||
sectionServers.put(server, section);
|
||||
}
|
||||
|
||||
public ServerSection getByName(String name) {
|
||||
if (name == null) return null;
|
||||
return sectionStorage.get(name);
|
||||
}
|
||||
|
||||
public ServerSection getByServer(ServerInfo server) {
|
||||
if (server == null) return null;
|
||||
return sectionServers.get(server);
|
||||
}
|
||||
|
||||
public Map<String, ServerSection> getSections() {
|
||||
return Collections.unmodifiableMap(sectionStorage);
|
||||
}
|
||||
|
||||
public boolean hasSection(String name) {
|
||||
return sectionStorage.containsKey(name);
|
||||
}
|
||||
}
|
@ -0,0 +1,197 @@
|
||||
package me.jaimemartz.lobbybalancer.section;
|
||||
|
||||
import me.jaimemartz.lobbybalancer.LobbyBalancer;
|
||||
import me.jaimemartz.lobbybalancer.connection.ProviderType;
|
||||
import me.jaimemartz.lobbybalancer.utils.AdapterFix;
|
||||
import me.jaimemartz.lobbybalancer.utils.ConfigUtils;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.config.Configuration;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ServerSection {
|
||||
private final String name;
|
||||
private final Configuration section;
|
||||
private final SectionManager manager;
|
||||
|
||||
private boolean principal;
|
||||
private ServerSection parent;
|
||||
private List<ServerInfo> servers;
|
||||
private ProviderType provider;
|
||||
private ServerInfo server;
|
||||
private SectionCommand command;
|
||||
private boolean valid = false;
|
||||
|
||||
ServerSection(String name, Configuration section, SectionManager manager) {
|
||||
this.name = name;
|
||||
this.section = section;
|
||||
this.manager = manager;
|
||||
this.servers = new ArrayList<>();
|
||||
}
|
||||
|
||||
void preInit(LobbyBalancer plugin) {
|
||||
principal = section.getBoolean("principal", false);
|
||||
|
||||
if (ConfigUtils.isSet(section, "parent")) {
|
||||
if (principal) {
|
||||
throw new IllegalStateException(String.format("The principal section \"%s\" has a parent set", name));
|
||||
}
|
||||
|
||||
parent = manager.getByName(section.getString("parent"));
|
||||
|
||||
if (parent == null) {
|
||||
throw new IllegalArgumentException(String.format("The section \"%s\" has an invalid parent set", name));
|
||||
}
|
||||
} else {
|
||||
if (!principal) {
|
||||
throw new IllegalArgumentException(String.format("The section \"%s\" does not have a parent set", name));
|
||||
}
|
||||
}
|
||||
|
||||
if (ConfigUtils.isSet(section, "servers")) {
|
||||
section.getStringList("servers").forEach(entry -> {
|
||||
Pattern pattern = Pattern.compile(entry);
|
||||
AtomicBoolean matches = new AtomicBoolean(false);
|
||||
plugin.getProxy().getServers().forEach((key, value) -> {
|
||||
Matcher matcher = pattern.matcher(key);
|
||||
if (matcher.matches()) {
|
||||
LobbyBalancer.printStartupInfo("Found a match with \"%s\" for entry \"%s\"", key, entry);
|
||||
servers.add(value);
|
||||
manager.register(server, this);
|
||||
matches.set(true);
|
||||
}
|
||||
});
|
||||
|
||||
if (!matches.get()) {
|
||||
plugin.getLogger().warning(String.format("Could not match a server with the entry \"%s\"", entry));
|
||||
}
|
||||
});
|
||||
|
||||
LobbyBalancer.printStartupInfo("Recognized %s server(s) out of %s entries", servers.size(), section.getStringList("servers").size());
|
||||
} else {
|
||||
throw new IllegalArgumentException(String.format("The section \"%s\" does not have any servers set", name));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void load(LobbyBalancer plugin) {
|
||||
if (parent != null && parent.parent == this) {
|
||||
throw new IllegalStateException(String.format("The section \"%s\" and \"%s\" are parents of each other", this.name, parent.name));
|
||||
}
|
||||
|
||||
if (principal) {
|
||||
manager.getSections().forEach((name, section) -> {
|
||||
if (section.isPrincipal() && section != this) {
|
||||
throw new IllegalStateException(String.format("The section \"%s\" is already principal", section.getName()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (ConfigUtils.isSet(section, "provider")) {
|
||||
try {
|
||||
provider = ProviderType.valueOf(section.getString("provider").toUpperCase());
|
||||
if (provider == ProviderType.LOCALIZED) {
|
||||
Configuration rules = plugin.getConfig().getSection("settings.geolocation.rules");
|
||||
if (!ConfigUtils.isSet(rules, name)) {
|
||||
throw new IllegalStateException(String.format("The section \"%s\" does not have a rule set in the geolocation section", this.name));
|
||||
}
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
if (principal) {
|
||||
throw new IllegalArgumentException(String.format("The principal section \"%s\" does not have a provider set", name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void postInit(LobbyBalancer plugin) {
|
||||
if (provider == null) {
|
||||
ServerSection sect = this.parent;
|
||||
while (sect.provider == null) {
|
||||
sect = sect.parent;
|
||||
}
|
||||
|
||||
LobbyBalancer.printStartupInfo("The section \"%s\" inherits the provider from parent section \"%s\"", this.name, sect.name);
|
||||
provider = sect.provider;
|
||||
}
|
||||
|
||||
if (provider == null) {
|
||||
throw new IllegalStateException(String.format("The section \"%s\" does not have a provider", name));
|
||||
}
|
||||
|
||||
if (ConfigUtils.isSet(section, "server")) {
|
||||
int port = (int) Math.floor(Math.random() * (0xFFFF + 1));
|
||||
ServerInfo server = plugin.getProxy().constructServerInfo("@" + section.getString("server"), new InetSocketAddress("0.0.0.0", port), String.format("Server of Section %s", name), false);
|
||||
plugin.getSectionManager().register(server, this);
|
||||
AdapterFix.addFakeServer(server);
|
||||
}
|
||||
|
||||
if (ConfigUtils.isSet(section, "command")) {
|
||||
Configuration other = section.getSection("command");
|
||||
|
||||
String name = other.getString("name");
|
||||
String permission = other.getString("permission");
|
||||
List<String> aliases = other.getStringList("aliases");
|
||||
|
||||
command = new SectionCommand(plugin, name, permission, aliases, this);
|
||||
plugin.getProxy().getPluginManager().registerCommand(plugin, command);
|
||||
}
|
||||
|
||||
this.setValid(true);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
protected Configuration getSection() {
|
||||
return section;
|
||||
}
|
||||
|
||||
public boolean isPrincipal() {
|
||||
return principal;
|
||||
}
|
||||
|
||||
public ServerSection getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public List<ServerInfo> getServers() {
|
||||
return servers;
|
||||
}
|
||||
|
||||
public ProviderType getProvider() {
|
||||
return provider;
|
||||
}
|
||||
|
||||
public ServerInfo getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
public SectionCommand getCommand() {
|
||||
return command;
|
||||
}
|
||||
|
||||
public boolean hasServer() {
|
||||
return server != null;
|
||||
}
|
||||
|
||||
public boolean hasCommand() {
|
||||
return command != null;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return valid;
|
||||
}
|
||||
|
||||
void setValid(boolean valid) {
|
||||
this.valid = valid;
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
package me.jaimemartz.lobbybalancer.utils;
|
||||
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.config.ConfigurationAdapter;
|
||||
import net.md_5.bungee.api.config.ListenerInfo;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class AdapterFix implements ConfigurationAdapter {
|
||||
private static final Map<String, ServerInfo> fakeServers = new HashMap<>();
|
||||
private static AdapterFix instance = null;
|
||||
|
||||
public static void inject(ProxyServer server) {
|
||||
if (instance == null) {
|
||||
instance = new AdapterFix(server.getConfigurationAdapter());
|
||||
}
|
||||
server.setConfigurationAdapter(instance);
|
||||
}
|
||||
|
||||
public static void addFakeServer(ServerInfo server) {
|
||||
fakeServers.put(server.getName(), server);
|
||||
}
|
||||
|
||||
public static void removeFakeServer(ServerInfo server) {
|
||||
fakeServers.remove(server.getName());
|
||||
}
|
||||
|
||||
public static Map<String, ServerInfo> getFakeServers() {
|
||||
return fakeServers;
|
||||
}
|
||||
|
||||
private final ConfigurationAdapter adapter;
|
||||
|
||||
public AdapterFix(ConfigurationAdapter adapter) {
|
||||
this.adapter = adapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
adapter.load();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(String path, int def) {
|
||||
return adapter.getInt(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString(String path, String def) {
|
||||
return adapter.getString(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean(String path, boolean def) {
|
||||
return adapter.getBoolean(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<?> getList(String path, Collection<?> def) {
|
||||
return adapter.getList(path, def);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ServerInfo> getServers() {
|
||||
Map<String, ServerInfo> res = adapter.getServers();
|
||||
res.putAll(fakeServers);
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ListenerInfo> getListeners() {
|
||||
return adapter.getListeners();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getGroups(String player) {
|
||||
return adapter.getGroups(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getPermissions(String group) {
|
||||
return adapter.getPermissions(group);
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package me.jaimemartz.lobbybalancer.utils;
|
||||
|
||||
public class ClassUtils {
|
||||
public static boolean isPresent(String className) {
|
||||
try {
|
||||
Class.forName(className);
|
||||
} catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package me.jaimemartz.lobbybalancer.utils;
|
||||
|
||||
import net.md_5.bungee.config.Configuration;
|
||||
|
||||
public class ConfigUtils {
|
||||
public static boolean isSet(Configuration config, String path) {
|
||||
return config.get(path) != null;
|
||||
}
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
package me.jaimemartz.lobbybalancer.utils;
|
||||
|
||||
import com.fasterxml.jackson.databind.ext.Java7Support;
|
||||
import com.maxmind.db.CHMCache;
|
||||
import com.maxmind.geoip2.DatabaseReader;
|
||||
import me.jaimemartz.lobbybalancer.LobbyBalancer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
public class GeolocationManager {
|
||||
private final DatabaseReader reader;
|
||||
|
||||
public GeolocationManager(LobbyBalancer plugin) throws IOException {
|
||||
Logger.getLogger(Java7Support.class.getName()).setLevel(Level.SEVERE);
|
||||
|
||||
File dir = new File(plugin.getDataFolder(), "database");
|
||||
if (!dir.exists()) {
|
||||
dir.mkdir();
|
||||
}
|
||||
|
||||
File packed = new File(dir, "GeoLite2-Country.mmdb.gz");
|
||||
File database = new File(dir, "GeoLite2-Country.mmdb");
|
||||
|
||||
if (!database.exists()) {
|
||||
LobbyBalancer.printStartupInfo("Downloading database");
|
||||
URL url = new URL("http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz");
|
||||
try (ReadableByteChannel rbc = Channels.newChannel(url.openStream())) {
|
||||
try (FileOutputStream fos = new FileOutputStream(packed)) {
|
||||
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
LobbyBalancer.printStartupInfo("Unpacking database");
|
||||
byte[] buffer = new byte[1024];
|
||||
try (GZIPInputStream in = new GZIPInputStream(new FileInputStream(packed))) {
|
||||
try (FileOutputStream out = new FileOutputStream(database)) {
|
||||
int len;
|
||||
while ((len = in.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LobbyBalancer.printStartupInfo("Deleting packed archive, success: " + (packed.delete() ? "yes" : "no"));
|
||||
} else {
|
||||
LobbyBalancer.printStartupInfo("Database exists, no need to download again");
|
||||
}
|
||||
|
||||
LobbyBalancer.printStartupInfo("Initializing database");
|
||||
reader = new DatabaseReader.Builder(database).withCache(new CHMCache()).build();
|
||||
}
|
||||
|
||||
public DatabaseReader getReader() {
|
||||
return reader;
|
||||
}
|
||||
}
|
108
src/main/java/me/jaimemartz/lobbybalancer/utils/PasteHelper.java
Normal file
108
src/main/java/me/jaimemartz/lobbybalancer/utils/PasteHelper.java
Normal file
@ -0,0 +1,108 @@
|
||||
package me.jaimemartz.lobbybalancer.utils;
|
||||
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
import net.md_5.bungee.api.scheduler.ScheduledTask;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.jpaste.exceptions.PasteException;
|
||||
import org.jpaste.pastebin.PasteExpireDate;
|
||||
import org.jpaste.pastebin.PastebinLink;
|
||||
import org.jpaste.pastebin.PastebinPaste;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public enum PasteHelper {
|
||||
PLUGIN {
|
||||
@Override
|
||||
public String paste(Plugin plugin) throws Exception {
|
||||
File file = new File(plugin.getDataFolder(), "config.yml");
|
||||
PastebinPaste paste = new PastebinPaste();
|
||||
paste.setPasteTitle("{name} ({version} on {bungee_version}) Configuration"
|
||||
.replace("{name}", plugin.getDescription().getName())
|
||||
.replace("{version}", plugin.getDescription().getVersion())
|
||||
.replace("{bungee_version}", plugin.getProxy().getVersion())
|
||||
);
|
||||
paste.setDeveloperKey(DEVELOPER_KEY);
|
||||
paste.setPasteExpireDate(PasteExpireDate.ONE_MONTH);
|
||||
paste.setVisibility(PastebinPaste.VISIBILITY_UNLISTED);
|
||||
paste.setPasteFormat("yaml");
|
||||
try (FileInputStream stream = new FileInputStream(file)) {
|
||||
paste.setContents(IOUtils.toString(stream, Charset.forName("UTF-8")));
|
||||
}
|
||||
PastebinLink link = paste.paste();
|
||||
return link.getLink().toString();
|
||||
}
|
||||
},
|
||||
BUNGEE {
|
||||
@Override
|
||||
public String paste(Plugin plugin) throws Exception {
|
||||
File file = new File(plugin.getDataFolder().getParentFile().getParentFile(), "config.yml");
|
||||
PastebinPaste paste = new PastebinPaste();
|
||||
paste.setPasteTitle("{name} ({version}) Configuration"
|
||||
.replace("{name}", plugin.getProxy().getName())
|
||||
.replace("{version}", plugin.getProxy().getVersion())
|
||||
);
|
||||
paste.setDeveloperKey(DEVELOPER_KEY);
|
||||
paste.setPasteExpireDate(PasteExpireDate.ONE_MONTH);
|
||||
paste.setVisibility(PastebinPaste.VISIBILITY_UNLISTED);
|
||||
paste.setPasteFormat("yaml");
|
||||
try (FileInputStream stream = new FileInputStream(file)) {
|
||||
paste.setContents(IOUtils.toString(stream, Charset.forName("UTF-8")));
|
||||
}
|
||||
PastebinLink link = paste.paste();
|
||||
return link.getLink().toString();
|
||||
}
|
||||
},
|
||||
LOGS {
|
||||
@Override
|
||||
public String paste(Plugin plugin) throws Exception {
|
||||
File file = new File(plugin.getDataFolder().getParentFile().getParentFile(), "proxy.log.0");
|
||||
PastebinPaste paste = new PastebinPaste();
|
||||
paste.setPasteTitle("{name} ({version}) Last Logs"
|
||||
.replace("{name}", plugin.getProxy().getName())
|
||||
.replace("{version}", plugin.getProxy().getVersion())
|
||||
);
|
||||
paste.setDeveloperKey(DEVELOPER_KEY);
|
||||
paste.setPasteExpireDate(PasteExpireDate.ONE_MONTH);
|
||||
paste.setVisibility(PastebinPaste.VISIBILITY_UNLISTED);
|
||||
paste.setPasteFormat("text");
|
||||
try (FileInputStream stream = new FileInputStream(file)) {
|
||||
paste.setContents(IOUtils.toString(stream, Charset.forName("UTF-8")));
|
||||
}
|
||||
PastebinLink link = paste.paste();
|
||||
return link.getLink().toString();
|
||||
}
|
||||
};
|
||||
|
||||
private String link;
|
||||
|
||||
private ScheduledTask task = null;
|
||||
public void send(Plugin plugin, CommandSender sender, String message) {
|
||||
try {
|
||||
sender.sendMessage(new ComponentBuilder(message.replace("{link}", link == null ? link = paste(plugin) : link)
|
||||
).color(ChatColor.GREEN).create());
|
||||
if (task != null) {
|
||||
plugin.getProxy().getScheduler().cancel(task);
|
||||
}
|
||||
task = plugin.getProxy().getScheduler().schedule(plugin, () -> link = null, 5, TimeUnit.MINUTES);
|
||||
} catch (PasteException e) {
|
||||
if (e.getMessage().equals("Failed to generate paste: Post limit, maximum pastes per 24h reached")) {
|
||||
sender.sendMessage(new ComponentBuilder("The file could not be pasted, your ip has reached the 10 pastes per day limit").color(ChatColor.RED).create());
|
||||
} else {
|
||||
sender.sendMessage(new ComponentBuilder("An unexpected error occurred while pasting the file").color(ChatColor.RED).create());
|
||||
}
|
||||
e.printStackTrace();
|
||||
} catch(Exception e) {
|
||||
sender.sendMessage(new ComponentBuilder("An internal error occurred while attempting to perform this command").color(ChatColor.RED).create());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract String paste(Plugin plugin) throws Exception;
|
||||
public static final String DEVELOPER_KEY = "e3ff18d8fb001a3ece08ae0d7d4a87bd";
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package me.jaimemartz.lobbybalancer.utils;
|
||||
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PlayerLocker {
|
||||
private static final Set<UUID> storage = Collections.synchronizedSet(new HashSet<UUID>());
|
||||
|
||||
public static boolean lock(ProxiedPlayer player) {
|
||||
if (storage.contains(player.getUniqueId())) {
|
||||
return false;
|
||||
} else {
|
||||
storage.add(player.getUniqueId());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean unlock(ProxiedPlayer player) {
|
||||
if (storage.contains(player.getUniqueId())) {
|
||||
storage.remove(player.getUniqueId());
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isLocked(ProxiedPlayer player) {
|
||||
return storage.contains(player.getUniqueId());
|
||||
}
|
||||
|
||||
public static void flush() {
|
||||
storage.clear();
|
||||
}
|
||||
}
|
59
src/main/java/org/jpaste/AbstractPaste.java
Normal file
59
src/main/java/org/jpaste/AbstractPaste.java
Normal file
@ -0,0 +1,59 @@
|
||||
package org.jpaste;
|
||||
|
||||
import org.jpaste.exceptions.PasteException;
|
||||
|
||||
/**
|
||||
*
|
||||
* An abstract representation of a paste.
|
||||
*
|
||||
* <p>
|
||||
* An abstract paste holds the paste contents and the {@link #paste()}
|
||||
* operation.
|
||||
* </p>
|
||||
*
|
||||
* @author Brian B
|
||||
*
|
||||
* @param <P>
|
||||
* PasteResult implementation
|
||||
*/
|
||||
public abstract class AbstractPaste<P extends AbstractPasteLink> {
|
||||
private String contents;
|
||||
|
||||
/**
|
||||
* Creates a new abstract <code>AbstractPaste</code> instance.
|
||||
*
|
||||
* @param contents
|
||||
* the contents of the paste
|
||||
*/
|
||||
public AbstractPaste(String contents) {
|
||||
this.contents = contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets paste contents
|
||||
*
|
||||
* @return paste contents
|
||||
*/
|
||||
public String getContents() {
|
||||
return contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the paste contents
|
||||
*
|
||||
* @param contents
|
||||
* contents of the paste
|
||||
*/
|
||||
public void setContents(String contents) {
|
||||
this.contents = contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to paste this paste and returns the results
|
||||
*
|
||||
* @return paste result
|
||||
* @throws PasteException if it failed to paste the paste
|
||||
*/
|
||||
public abstract P paste() throws PasteException;
|
||||
|
||||
}
|
25
src/main/java/org/jpaste/AbstractPasteLink.java
Normal file
25
src/main/java/org/jpaste/AbstractPasteLink.java
Normal file
@ -0,0 +1,25 @@
|
||||
package org.jpaste;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
*
|
||||
* An representation of an abstract PasteLink
|
||||
*
|
||||
* <p>
|
||||
* An AbstractPasteLink holds the link/URL to a paste.
|
||||
* </p>
|
||||
*
|
||||
* @author Brian B
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractPasteLink {
|
||||
|
||||
/**
|
||||
* Gets the URL to this paste
|
||||
*
|
||||
* @return URL to paste
|
||||
*/
|
||||
public abstract URL getLink();
|
||||
|
||||
}
|
13
src/main/java/org/jpaste/exceptions/PasteException.java
Normal file
13
src/main/java/org/jpaste/exceptions/PasteException.java
Normal file
@ -0,0 +1,13 @@
|
||||
package org.jpaste.exceptions;
|
||||
|
||||
public class PasteException extends Exception {
|
||||
private static final long serialVersionUID = -4230960075582953775L;
|
||||
|
||||
public PasteException() {
|
||||
}
|
||||
|
||||
public PasteException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
60
src/main/java/org/jpaste/pastebin/PasteExpireDate.java
Normal file
60
src/main/java/org/jpaste/pastebin/PasteExpireDate.java
Normal file
@ -0,0 +1,60 @@
|
||||
package org.jpaste.pastebin;
|
||||
|
||||
/**
|
||||
*
|
||||
* Represents a paste's expire date
|
||||
*
|
||||
* <p>
|
||||
* A list of all expire dates/times can be found at the <a
|
||||
* href="http://pastebin.com/api">pastebin API manual</a>.
|
||||
* </p>
|
||||
*
|
||||
* @author Brian B
|
||||
*
|
||||
*/
|
||||
public enum PasteExpireDate {
|
||||
NEVER("N", -1), TEN_MINUTES("10M", 10 * 60), ONE_HOUR("1H", 60 * 60), ONE_DAY(
|
||||
"1D", 60 * 60 * 24), ONE_WEEK("1W", 60 * 60 * 24 * 7), TWO_WEEKS(
|
||||
"2W", 60 * 60 * 24 * 14), ONE_MONTH("1M", -1);
|
||||
|
||||
private String val;
|
||||
private int timeSeconds;
|
||||
|
||||
/**
|
||||
* Creates a new <code>PasteExpireDate</code> instance.
|
||||
*
|
||||
* @param val
|
||||
* a valid expire date value
|
||||
*/
|
||||
PasteExpireDate(String val, int timeSeconds) {
|
||||
this.val = val;
|
||||
this.timeSeconds = timeSeconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get's the valid value for the 'api_paste_expire_date' parameter
|
||||
*
|
||||
* @return the valid value for the 'api_paste_expire_date' parameter
|
||||
*/
|
||||
public String getValue() {
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets PasteExpireDate based on: paste expire date minus paste date (in
|
||||
* seconds)
|
||||
*
|
||||
* @param timeSeconds
|
||||
* seconds between expire date and paste date
|
||||
* @return PasteExpireDate
|
||||
*/
|
||||
public static PasteExpireDate getExpireDate(int timeSeconds) {
|
||||
for (PasteExpireDate date : PasteExpireDate.values()) {
|
||||
if (date.timeSeconds == timeSeconds) {
|
||||
return date;
|
||||
}
|
||||
}
|
||||
return ONE_MONTH;
|
||||
}
|
||||
|
||||
}
|
207
src/main/java/org/jpaste/pastebin/Pastebin.java
Normal file
207
src/main/java/org/jpaste/pastebin/Pastebin.java
Normal file
@ -0,0 +1,207 @@
|
||||
package org.jpaste.pastebin;
|
||||
|
||||
import org.jpaste.exceptions.PasteException;
|
||||
import org.jpaste.pastebin.exceptions.ParseException;
|
||||
import org.jpaste.utils.web.Post;
|
||||
import org.jpaste.utils.web.Web;
|
||||
import org.jpaste.utils.xml.XMLUtils;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
*
|
||||
* A global representation of the pastebin site
|
||||
*
|
||||
* <p>
|
||||
* Holds various constants and method shortcuts
|
||||
* </p>
|
||||
*
|
||||
* @author Brian B
|
||||
*
|
||||
*/
|
||||
public class Pastebin {
|
||||
/**
|
||||
* Used to interact with the pastebin API
|
||||
*/
|
||||
public static final String API_POST_LINK = "http://pastebin.com/api/api_post.php";
|
||||
/**
|
||||
* Used for fetching an user session id
|
||||
*/
|
||||
public static final String API_LOGIN_LINK = "http://pastebin.com/api/api_login.php";
|
||||
|
||||
/**
|
||||
* Fetches a paste text from pastebin
|
||||
*
|
||||
* @param pasteKey
|
||||
* the unique paste key
|
||||
* @return contents of the paste
|
||||
*/
|
||||
public static String getContents(String pasteKey) {
|
||||
return PastebinLink.getContents(pasteKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a paste on pastebin and returns the URL to it
|
||||
*
|
||||
* @param developerKey
|
||||
* a developer key which can be fetched from the pastebin API
|
||||
* page
|
||||
* @param contents
|
||||
* contents of the paste
|
||||
* @return URL to paste
|
||||
* @throws PasteException
|
||||
* if it failed to push the paste
|
||||
*/
|
||||
public static URL pastePaste(String developerKey, String contents)
|
||||
throws PasteException {
|
||||
return pastePaste(developerKey, contents, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a paste on pastebin and returns the URL to it
|
||||
*
|
||||
* @param developerKey
|
||||
* a developer key which can be fetched from the pastebin API
|
||||
* page
|
||||
* @param contents
|
||||
* contents of the paste
|
||||
* @param title
|
||||
* title of the paste
|
||||
* @return URL to paste
|
||||
* @throws PasteException
|
||||
* if it failed to push the paste
|
||||
*/
|
||||
public static URL pastePaste(String developerKey, String contents,
|
||||
String title) throws PasteException {
|
||||
return newPaste(developerKey, contents, title).paste().getLink();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new paste and returns it
|
||||
*
|
||||
* @param developerKey
|
||||
* a developer key which can be fetched from the pastebin API
|
||||
* page
|
||||
* @param contents
|
||||
* contents of the paste
|
||||
* @param title
|
||||
* title of the paste
|
||||
* @return a new paste
|
||||
*/
|
||||
public static PastebinPaste newPaste(String developerKey, String contents,
|
||||
String title) {
|
||||
PastebinPaste paste = new PastebinPaste(developerKey, contents);
|
||||
paste.setPasteTitle(title);
|
||||
return paste;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new paste and returns it
|
||||
*
|
||||
* @param developerKey
|
||||
* a developer key which can be fetched from the pastebin API
|
||||
* page
|
||||
* @param contents
|
||||
* contents of the paste
|
||||
* @return a new paste
|
||||
*/
|
||||
public static PastebinPaste newPaste(String developerKey, String contents) {
|
||||
return newPaste(developerKey, contents, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current trending pastebin pastes
|
||||
*
|
||||
* @param developerKey
|
||||
* a developer key which can be fetched from the pastebin API
|
||||
* page
|
||||
* @return an array of {@link PastebinLink}
|
||||
* @throws ParseException
|
||||
* if it failed to parse the trending pastes
|
||||
*/
|
||||
public static PastebinLink[] getTrending(String developerKey)
|
||||
throws ParseException {
|
||||
if (developerKey == null || developerKey.isEmpty()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Developer key can't be null or empty.");
|
||||
}
|
||||
Post post = new Post();
|
||||
post.put("api_dev_key", developerKey);
|
||||
post.put("api_option", "trends");
|
||||
|
||||
String response = Web.getContents(API_POST_LINK, post);
|
||||
|
||||
if (response.startsWith("<paste>")) {
|
||||
// success
|
||||
try {
|
||||
DocumentBuilderFactory dbFactory = DocumentBuilderFactory
|
||||
.newInstance();
|
||||
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
|
||||
response = "<dummy>" + response + "</dummy>"; // requires root
|
||||
// element
|
||||
Document doc = dBuilder.parse(new InputSource(
|
||||
new ByteArrayInputStream(response.getBytes("utf-8"))));
|
||||
doc.getDocumentElement().normalize();
|
||||
|
||||
NodeList nodes = doc.getElementsByTagName("paste");
|
||||
ArrayList<PastebinLink> pastes = new ArrayList<PastebinLink>(
|
||||
nodes.getLength());
|
||||
for (int i = 0; i < nodes.getLength(); i++) {
|
||||
Node node = nodes.item(i);
|
||||
if (node.getNodeType() == Node.ELEMENT_NODE) {
|
||||
Element element = (Element) node;
|
||||
|
||||
String pasteFormat = XMLUtils.getText(element,
|
||||
"paste_format_short");
|
||||
String title = XMLUtils.getText(element, "paste_title");
|
||||
int visibility = Integer.parseInt(XMLUtils.getText(
|
||||
element, "paste_private"));
|
||||
int hits = Integer.parseInt(XMLUtils.getText(element,
|
||||
"paste_hits"));
|
||||
|
||||
long expireDate = Long.parseLong(XMLUtils.getText(
|
||||
element, "paste_expire_date"));
|
||||
long pasteDate = Long.parseLong(XMLUtils.getText(
|
||||
element, "paste_date"));
|
||||
|
||||
URL pasteURL = new URL(XMLUtils.getText(element,
|
||||
"paste_url"));
|
||||
|
||||
PastebinPaste paste = new PastebinPaste();
|
||||
paste.setPasteFormat(pasteFormat);
|
||||
paste.setPasteTitle(title);
|
||||
paste.setVisibility(visibility);
|
||||
paste.setPasteExpireDate(expireDate == 0L ? PasteExpireDate.NEVER
|
||||
: PasteExpireDate
|
||||
.getExpireDate((int) (expireDate - pasteDate)));
|
||||
|
||||
PastebinLink pastebinLink = new PastebinLink(paste,
|
||||
pasteURL, new Date(pasteDate * 1000));
|
||||
pastebinLink.setHits(hits);
|
||||
|
||||
pastes.add(pastebinLink);
|
||||
}
|
||||
}
|
||||
|
||||
return pastes.toArray(new PastebinLink[pastes.size()]);
|
||||
} catch (Exception e) {
|
||||
throw new ParseException("Failed to parse pastes: "
|
||||
+ e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
throw new ParseException("Failed to parse pastes: " + response);
|
||||
}
|
||||
|
||||
}
|
184
src/main/java/org/jpaste/pastebin/PastebinLink.java
Normal file
184
src/main/java/org/jpaste/pastebin/PastebinLink.java
Normal file
@ -0,0 +1,184 @@
|
||||
package org.jpaste.pastebin;
|
||||
|
||||
import org.jpaste.AbstractPasteLink;
|
||||
import org.jpaste.exceptions.PasteException;
|
||||
import org.jpaste.pastebin.account.PastebinAccount;
|
||||
import org.jpaste.utils.web.Post;
|
||||
import org.jpaste.utils.web.Web;
|
||||
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
*
|
||||
* A representation of an online pastebin paste.
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* This class represents an existing pastebin paste URL
|
||||
* </p>
|
||||
*
|
||||
* @author Brian B
|
||||
*
|
||||
*/
|
||||
public class PastebinLink extends AbstractPasteLink {
|
||||
private PastebinPaste paste;
|
||||
private URL link;
|
||||
private int hits;
|
||||
private String key;
|
||||
private Date pasteDate;
|
||||
|
||||
/**
|
||||
* Creates a new <code>PastebinLink</code> object, representing an existing
|
||||
* paste
|
||||
*
|
||||
* @param paste
|
||||
* paste details
|
||||
* @param url
|
||||
* link to paste
|
||||
*/
|
||||
public PastebinLink(PastebinPaste paste, URL url) {
|
||||
this(paste, url, new Date((System.currentTimeMillis() / 1000) * 1000));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>PastebinLink</code> object, representing an existing
|
||||
* paste
|
||||
*
|
||||
* @param paste
|
||||
* paste details
|
||||
* @param url
|
||||
* link to paste
|
||||
* @param pasteDate
|
||||
* date the paste has been pasted
|
||||
*/
|
||||
public PastebinLink(PastebinPaste paste, URL url, Date pasteDate) {
|
||||
this.paste = paste;
|
||||
this.link = url;
|
||||
this.pasteDate = pasteDate;
|
||||
try {
|
||||
this.key = url.toURI().getPath().substring(1);
|
||||
} catch (URISyntaxException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public URL getLink() {
|
||||
return link;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets pastebin paste details
|
||||
*
|
||||
* @return paste details
|
||||
*/
|
||||
public PastebinPaste getPaste() {
|
||||
return paste;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets pastebin unique paste key
|
||||
* @return unique paste key
|
||||
*/
|
||||
public String getKey() {
|
||||
return this.key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the pastebin link content
|
||||
* <p>
|
||||
* After parsing use the following methods: {@link #getPaste()} {@link PastebinPaste#getContents()}
|
||||
*/
|
||||
public void fetchContent() {
|
||||
if(getPaste().getContents() != null) {
|
||||
throw new IllegalStateException("Contents already fetched.");
|
||||
}
|
||||
getPaste().setContents(getContents(getKey()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the paste page hits
|
||||
*
|
||||
* @param hits
|
||||
* amount of times paste has been visited
|
||||
*/
|
||||
public void setHits(int hits) {
|
||||
if (hits < 0) {
|
||||
throw new IllegalArgumentException("Hits must be positive: " + hits);
|
||||
}
|
||||
this.hits = hits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the paste page hits
|
||||
*
|
||||
* @return paste page hits
|
||||
*/
|
||||
public int getHits() {
|
||||
return this.hits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the paste date
|
||||
*
|
||||
* @return paste date
|
||||
*/
|
||||
public Date getPasteDate() {
|
||||
return this.pasteDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes this paste
|
||||
*
|
||||
* @param account
|
||||
* the account which was used to create this paste
|
||||
* @param developerKey
|
||||
* a developer key which can be fetched from the pastebin API
|
||||
* page
|
||||
* @throws PasteException if it failed to delete the paste
|
||||
*/
|
||||
public void delete(String developerKey, PastebinAccount account) throws PasteException {
|
||||
if(developerKey == null || developerKey.isEmpty()) {
|
||||
throw new IllegalArgumentException("Developer key can't be null or empty.");
|
||||
}
|
||||
if(account.getUserSessionId() == null || account.getUserSessionId().isEmpty()) {
|
||||
throw new IllegalArgumentException("Account user session id is missing.");
|
||||
}
|
||||
Post post = new Post();
|
||||
post.put("api_dev_key", developerKey);
|
||||
post.put("api_user_key", account.getUserSessionId());
|
||||
post.put("api_paste_key", getKey());
|
||||
post.put("api_option", "delete");
|
||||
|
||||
String response = Web.getContents(Pastebin.API_POST_LINK, post);
|
||||
if(response.equals("Paste Removed")) {
|
||||
return;
|
||||
}
|
||||
throw new PasteException("Failed to delete paste: " + response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes this paste
|
||||
* @throws PasteException if it failed to delete the paste
|
||||
*/
|
||||
public void delete() throws PasteException {
|
||||
delete(getPaste().getDeveloperKey(), getPaste().getAccount());
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a paste text from pastebin
|
||||
*
|
||||
* @param pasteKey
|
||||
* the unique paste key
|
||||
* @return contents of the paste
|
||||
*/
|
||||
public static String getContents(String pasteKey) {
|
||||
return Web.getContents("http://pastebin.com/raw.php?i=" + pasteKey);
|
||||
}
|
||||
|
||||
}
|
312
src/main/java/org/jpaste/pastebin/PastebinPaste.java
Normal file
312
src/main/java/org/jpaste/pastebin/PastebinPaste.java
Normal file
@ -0,0 +1,312 @@
|
||||
package org.jpaste.pastebin;
|
||||
|
||||
import org.jpaste.AbstractPaste;
|
||||
import org.jpaste.exceptions.PasteException;
|
||||
import org.jpaste.pastebin.account.PastebinAccount;
|
||||
import org.jpaste.utils.web.Post;
|
||||
import org.jpaste.utils.web.Web;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
*
|
||||
* A representation of a new or existing paste.
|
||||
*
|
||||
* <p>
|
||||
* This class holds the contents of the paste itself. You can get and modify
|
||||
* settings and then 'push' this paste onto <a
|
||||
* href="http://pastebin.com/">pastebin.</a>
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This class has been programmed with the help of the <a
|
||||
* href="http://pastebin.com/api/">pastebin API manual.</a>
|
||||
* </p>
|
||||
*
|
||||
* @author Brian B
|
||||
*
|
||||
*/
|
||||
public class PastebinPaste extends AbstractPaste<PastebinLink> {
|
||||
/**
|
||||
* Makes a paste public.
|
||||
*/
|
||||
public static final int VISIBILITY_PUBLIC = 0;
|
||||
/**
|
||||
* Makes a paste unlisted.
|
||||
*/
|
||||
public static final int VISIBILITY_UNLISTED = 1;
|
||||
/**
|
||||
* Makes a paste private.
|
||||
* <p>
|
||||
* Requires an {@link PastebinAccount
|
||||
* org.jpaste.pastebin.account.PastebinAccount PastebinAccount}
|
||||
* </p>
|
||||
*/
|
||||
public static final int VISIBILITY_PRIVATE = 2;
|
||||
private String developerKey;
|
||||
private PastebinAccount account;
|
||||
private String pasteTitle;
|
||||
private String pasteFormat;
|
||||
private PasteExpireDate expireDate;
|
||||
private int visibility;
|
||||
|
||||
/**
|
||||
* Creates a new empty <code>PastebinPaste</code> instance.
|
||||
*/
|
||||
public PastebinPaste() {
|
||||
this(null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>PastebinPaste</code> instance.
|
||||
*
|
||||
* @param contents
|
||||
* the paste contents
|
||||
*/
|
||||
public PastebinPaste(String contents) {
|
||||
this(null, contents, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>PastebinPaste</code> instance.
|
||||
*
|
||||
* @param account
|
||||
* a pastebin account
|
||||
*/
|
||||
public PastebinPaste(PastebinAccount account) {
|
||||
this(account.getDeveloperKey(), null, account);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>PastebinPaste</code> instance.
|
||||
*
|
||||
* @param developerKey
|
||||
* a developer key which can be fetched from the pastebin API
|
||||
* page
|
||||
* @param contents
|
||||
* the contents of the paste
|
||||
*/
|
||||
public PastebinPaste(String developerKey, String contents) {
|
||||
this(developerKey, contents, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>PastebinPaste</code> instance.
|
||||
*
|
||||
* @param developerKey
|
||||
* a developer key which can be fetched from the pastebin API
|
||||
* page
|
||||
* @param contents
|
||||
* the contents of the paste
|
||||
* @param account
|
||||
* a pastebin account
|
||||
*/
|
||||
public PastebinPaste(String developerKey, String contents,
|
||||
PastebinAccount account) {
|
||||
super(contents);
|
||||
this.developerKey = developerKey;
|
||||
this.account = account;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the pastebin account If you set an account the pastes will be listed
|
||||
* on your account.
|
||||
*
|
||||
* @param account
|
||||
* a pastebin account
|
||||
*/
|
||||
public void setAccount(PastebinAccount account) {
|
||||
this.account = account;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the pastebin account
|
||||
*
|
||||
* @return pastebin account
|
||||
*/
|
||||
public PastebinAccount getAccount() {
|
||||
return this.account;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the developer key The developer key is required to paste contents on
|
||||
* pastebin
|
||||
*
|
||||
* @param developerKey
|
||||
* a developer key which can be fetched from the pastebin API
|
||||
* page
|
||||
*/
|
||||
public void setDeveloperKey(String developerKey) {
|
||||
if (developerKey == null || developerKey.isEmpty()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Developer key can not be null or empty.");
|
||||
}
|
||||
this.developerKey = developerKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the paste expire date
|
||||
*
|
||||
* @param date
|
||||
* date when the paste will be removed
|
||||
*/
|
||||
public void setPasteExpireDate(PasteExpireDate date) {
|
||||
this.expireDate = date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the developer key
|
||||
*
|
||||
* @return developer key
|
||||
*/
|
||||
public String getDeveloperKey() {
|
||||
return this.developerKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the paste title
|
||||
*
|
||||
* @param title
|
||||
* title of the paste
|
||||
*/
|
||||
public void setPasteTitle(String title) {
|
||||
this.pasteTitle = title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets paste title
|
||||
*
|
||||
* @return paste title
|
||||
*/
|
||||
public String getPasteTitle() {
|
||||
return this.pasteTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets paste expire date
|
||||
* @return paste expire date
|
||||
*/
|
||||
public PasteExpireDate getPasteExpireDate() {
|
||||
return this.expireDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the paste format The format is used for syntax highlighting
|
||||
*
|
||||
* @see <a href="http://pastebin.com/api#5">available syntax highlighting
|
||||
* formats</a>
|
||||
* @param format
|
||||
* format of the paste
|
||||
*/
|
||||
public void setPasteFormat(String format) {
|
||||
this.pasteFormat = format;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets paste format
|
||||
*
|
||||
* @return paste format
|
||||
*/
|
||||
public String getPasteFormat() {
|
||||
return this.pasteFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes this paste private, unlisted or public Default visibility is public
|
||||
* <p>
|
||||
* <strong>Valid visibilities</strong>
|
||||
* </p>
|
||||
* <p>
|
||||
* {@link PastebinPaste#VISIBILITY_PUBLIC}
|
||||
* </p>
|
||||
* <p>
|
||||
* {@link PastebinPaste#VISIBILITY_UNLISTED}
|
||||
* </p>
|
||||
* <p>
|
||||
* {@link PastebinPaste#VISIBILITY_PRIVATE}
|
||||
* </p>
|
||||
*
|
||||
* @param visibility
|
||||
* the paste it's visibility
|
||||
*/
|
||||
public void setVisibility(int visibility) {
|
||||
if (visibility < 0 || visibility > 2) {
|
||||
throw new IllegalArgumentException("Unknown visibility: "
|
||||
+ visibility);
|
||||
}
|
||||
this.visibility = visibility;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this paste visibility
|
||||
* <p>
|
||||
* <strong>Valid visibilities</strong>
|
||||
* </p>
|
||||
* <p>
|
||||
* {@link PastebinPaste#VISIBILITY_PUBLIC}
|
||||
* </p>
|
||||
* <p>
|
||||
* {@link PastebinPaste#VISIBILITY_UNLISTED}
|
||||
* </p>
|
||||
* <p>
|
||||
* {@link PastebinPaste#VISIBILITY_PRIVATE}
|
||||
* </p>
|
||||
*
|
||||
* @return visibility of this paste
|
||||
*/
|
||||
public int getVisibility() {
|
||||
return this.visibility;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public PastebinLink paste() throws PasteException {
|
||||
if (getContents() == null || getContents().isEmpty()) {
|
||||
throw new IllegalStateException("Paste can not be null or empty.");
|
||||
}
|
||||
if (getDeveloperKey() == null || getDeveloperKey().isEmpty()) {
|
||||
throw new IllegalStateException("Developer key is missing.");
|
||||
}
|
||||
|
||||
Post post = new Post();
|
||||
|
||||
// required parameters
|
||||
post.put("api_dev_key", getDeveloperKey());
|
||||
post.put("api_option", "paste");
|
||||
post.put("api_paste_code", getContents());
|
||||
|
||||
// optional parameters
|
||||
if (this.account != null && this.account.getUserSessionId() != null) {
|
||||
post.put("api_user_key", this.account.getUserSessionId());
|
||||
}
|
||||
if (this.pasteTitle != null) {
|
||||
post.put("api_paste_name", getPasteTitle());
|
||||
}
|
||||
if (this.pasteFormat != null) {
|
||||
post.put("api_paste_format", getPasteFormat());
|
||||
}
|
||||
post.put("api_paste_private", Integer.toString(getVisibility()));
|
||||
if (this.expireDate != null) {
|
||||
post.put("api_paste_expire_date", expireDate.getValue());
|
||||
}
|
||||
|
||||
try {
|
||||
String pageResponse = Web.getContents(Pastebin.API_POST_LINK, post);
|
||||
if (pageResponse.startsWith("http")) {
|
||||
// success
|
||||
PastebinLink result = new PastebinLink(this, new URL(
|
||||
pageResponse));
|
||||
return result;
|
||||
}
|
||||
throw new PasteException("Failed to generate paste: "
|
||||
+ pageResponse);
|
||||
} catch (MalformedURLException e) {
|
||||
// shouldn't happen
|
||||
throw new PasteException("Failed to generate paste: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
369
src/main/java/org/jpaste/pastebin/account/PastebinAccount.java
Normal file
369
src/main/java/org/jpaste/pastebin/account/PastebinAccount.java
Normal file
@ -0,0 +1,369 @@
|
||||
package org.jpaste.pastebin.account;
|
||||
|
||||
import org.jpaste.pastebin.PasteExpireDate;
|
||||
import org.jpaste.pastebin.Pastebin;
|
||||
import org.jpaste.pastebin.PastebinLink;
|
||||
import org.jpaste.pastebin.PastebinPaste;
|
||||
import org.jpaste.pastebin.exceptions.LoginException;
|
||||
import org.jpaste.pastebin.exceptions.ParseException;
|
||||
import org.jpaste.utils.web.Post;
|
||||
import org.jpaste.utils.web.Web;
|
||||
import org.jpaste.utils.xml.XMLUtils;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
*
|
||||
* Represents an account on <a href="http://pastebin.com/">Pastebin</a>.
|
||||
*
|
||||
* <p>
|
||||
* This class can fetch a non-expiring user session id. This session id is used
|
||||
* for generating private pasted, fetching user details, fetching user his
|
||||
* pastes, adding pastes to his account & more account based interactions.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* A reference manual for generating a user session id can be found <a
|
||||
* href="http://pastebin.com/api#8">here</a>.
|
||||
*
|
||||
* @author Brian B
|
||||
*
|
||||
*/
|
||||
public class PastebinAccount {
|
||||
private String username, password, userSessionId, developerKey;
|
||||
|
||||
/**
|
||||
* Creates a new empty <code>PastebinAccount</code> instance.
|
||||
*/
|
||||
public PastebinAccount() {
|
||||
this(null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>PastebinAccount</code> instance.
|
||||
*
|
||||
* When you use this constructor, you'll need to use the {@link #login()} to
|
||||
* fetch an user session id
|
||||
*
|
||||
* @param developerKey
|
||||
* a developer key which can be fetched from the pastebin API
|
||||
* page
|
||||
* @param username
|
||||
* the username of the pastebin account
|
||||
* @param password
|
||||
* the password of the pastebin account
|
||||
*/
|
||||
public PastebinAccount(String developerKey, String username, String password) {
|
||||
this.developerKey = developerKey;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>PastebinAccount</code> instance.
|
||||
*
|
||||
* @param userSessionId
|
||||
* the user session id of the pastebin account.
|
||||
*/
|
||||
public PastebinAccount(String userSessionId) {
|
||||
this(null, userSessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>PastebinAccount</code> instance.
|
||||
*
|
||||
* @param developerKey
|
||||
* a developer key which can be fetched from the pastebin API
|
||||
* page
|
||||
* @param userSessionId
|
||||
* the user session id of the pastebin account.
|
||||
*/
|
||||
public PastebinAccount(String developerKey, String userSessionId) {
|
||||
this.developerKey = developerKey;
|
||||
this.userSessionId = userSessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the user session id The user session id can be used to paste private
|
||||
* pastes and will add pastes to your account
|
||||
*
|
||||
* @param userSessionId
|
||||
* the user session id of the pastebin account
|
||||
*/
|
||||
public void setUserSessionId(String userSessionId) {
|
||||
this.userSessionId = userSessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user session id
|
||||
*
|
||||
* @return user session id
|
||||
*/
|
||||
public String getUserSessionId() {
|
||||
return this.userSessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the username
|
||||
*
|
||||
* @param username
|
||||
* the username of the pastebin account
|
||||
*/
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets username of the pastebin account
|
||||
*
|
||||
* @return username of the pastebin account. Could be null if only an user
|
||||
* session is was provided.
|
||||
*/
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the password
|
||||
*
|
||||
* @param password
|
||||
* the password of the pastebin account
|
||||
*/
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets password of the pastebin account
|
||||
*
|
||||
* @return password of the pastebin account. Could be null if only an user
|
||||
* session id was provided.
|
||||
*/
|
||||
public String getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the developer key The developer key is required to paste contents on
|
||||
* pastebin
|
||||
*
|
||||
* @param developerKey
|
||||
* a developer key which can be fetched from the pastebin API
|
||||
* page
|
||||
*/
|
||||
public void setDeveloperKey(String developerKey) {
|
||||
if (developerKey == null || developerKey.isEmpty()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Developer key can not be null or empty.");
|
||||
}
|
||||
this.developerKey = developerKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the developer key
|
||||
*
|
||||
* @return developer key
|
||||
*/
|
||||
public String getDeveloperKey() {
|
||||
return this.developerKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches an user session id.
|
||||
*
|
||||
* @throws LoginException
|
||||
* if fetching the user session id failed
|
||||
*/
|
||||
public void login() throws LoginException {
|
||||
if (getUserSessionId() != null) {
|
||||
throw new IllegalStateException("Already logged in.");
|
||||
}
|
||||
if (getUsername() == null || getPassword() == null) {
|
||||
throw new IllegalStateException("Username or password null.");
|
||||
}
|
||||
if (getDeveloperKey() == null || getDeveloperKey().isEmpty()) {
|
||||
throw new IllegalStateException("Developer key is missing.");
|
||||
}
|
||||
|
||||
Post post = new Post();
|
||||
|
||||
post.put("api_dev_key", getDeveloperKey());
|
||||
post.put("api_user_name", username);
|
||||
post.put("api_user_password", password);
|
||||
|
||||
String response = Web.getContents(Pastebin.API_LOGIN_LINK, post);
|
||||
if (response == null || response.isEmpty()) {
|
||||
throw new LoginException("Empty response from login API server.");
|
||||
}
|
||||
if (response.toLowerCase().startsWith("bad")) {
|
||||
throw new LoginException("Failed to login: " + response);
|
||||
}
|
||||
|
||||
this.userSessionId = response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all pasted pastes by this user
|
||||
*
|
||||
* @param limit
|
||||
* maximum amount of pastes to receive
|
||||
* <p>
|
||||
* <code>0 > limit > 1000</code>
|
||||
* </p>
|
||||
* @return all pasted pastes made by this user/account
|
||||
* @throws ParseException
|
||||
* if it failed to parse the pastes
|
||||
*/
|
||||
public PastebinLink[] getPastes(int limit) throws ParseException {
|
||||
if (limit > 1000) {
|
||||
limit = 1000;
|
||||
}
|
||||
if (limit < 1) {
|
||||
limit = 1;
|
||||
}
|
||||
if (getUserSessionId() == null) {
|
||||
throw new IllegalStateException("User session id missing.");
|
||||
}
|
||||
if (getDeveloperKey() == null || getDeveloperKey().isEmpty()) {
|
||||
throw new IllegalStateException("Developer key is missing.");
|
||||
}
|
||||
|
||||
Post post = new Post();
|
||||
|
||||
post.put("api_dev_key", getDeveloperKey());
|
||||
post.put("api_user_key", getUserSessionId());
|
||||
post.put("api_results_limit", Integer.toString(limit));
|
||||
post.put("api_option", "list");
|
||||
|
||||
String response = Web.getContents(Pastebin.API_POST_LINK, post);
|
||||
if (response.equals("No pastes found.")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (response.startsWith("<paste>")) {
|
||||
// success
|
||||
try {
|
||||
DocumentBuilderFactory dbFactory = DocumentBuilderFactory
|
||||
.newInstance();
|
||||
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
|
||||
response = "<dummy>" + response + "</dummy>"; // requires root
|
||||
// element
|
||||
Document doc = dBuilder.parse(new InputSource(
|
||||
new ByteArrayInputStream(response.getBytes("utf-8"))));
|
||||
doc.getDocumentElement().normalize();
|
||||
|
||||
NodeList nodes = doc.getElementsByTagName("paste");
|
||||
ArrayList<PastebinLink> pastes = new ArrayList<PastebinLink>(
|
||||
nodes.getLength());
|
||||
for (int i = 0; i < nodes.getLength(); i++) {
|
||||
Node node = nodes.item(i);
|
||||
if (node.getNodeType() == Node.ELEMENT_NODE) {
|
||||
Element element = (Element) node;
|
||||
|
||||
String pasteFormat = XMLUtils.getText(element,
|
||||
"paste_format_short");
|
||||
String title = XMLUtils.getText(element, "paste_title");
|
||||
int visibility = Integer.parseInt(XMLUtils.getText(
|
||||
element, "paste_private"));
|
||||
int hits = Integer.parseInt(XMLUtils.getText(element,
|
||||
"paste_hits"));
|
||||
|
||||
long expireDate = Long.parseLong(XMLUtils.getText(
|
||||
element, "paste_expire_date"));
|
||||
long pasteDate = Long.parseLong(XMLUtils.getText(
|
||||
element, "paste_date"));
|
||||
|
||||
URL pasteURL = new URL(XMLUtils.getText(element,
|
||||
"paste_url"));
|
||||
|
||||
PastebinPaste paste = new PastebinPaste(this);
|
||||
paste.setPasteFormat(pasteFormat);
|
||||
paste.setPasteTitle(title);
|
||||
paste.setVisibility(visibility);
|
||||
paste.setPasteExpireDate(expireDate == 0L ? PasteExpireDate.NEVER
|
||||
: PasteExpireDate
|
||||
.getExpireDate((int) (expireDate - pasteDate)));
|
||||
|
||||
PastebinLink pastebinLink = new PastebinLink(paste,
|
||||
pasteURL, new Date(pasteDate * 1000));
|
||||
pastebinLink.setHits(hits);
|
||||
|
||||
pastes.add(pastebinLink);
|
||||
}
|
||||
}
|
||||
|
||||
return pastes.toArray(new PastebinLink[pastes.size()]);
|
||||
} catch (Exception e) {
|
||||
throw new ParseException("Failed to parse pastes: "
|
||||
+ e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
throw new ParseException("Failed to parse pastes: " + response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets pasted pastes (max 50) by this user
|
||||
*
|
||||
* @return all pasted pastes made by this user/account
|
||||
* @throws ParseException
|
||||
* if it failed to parse the pastes
|
||||
*/
|
||||
public PastebinLink[] getPastes() throws ParseException {
|
||||
return getPastes(50);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the account details of this account
|
||||
*
|
||||
* @return account details
|
||||
* @throws ParseException
|
||||
* if it failed to parse the account details
|
||||
*/
|
||||
public PastebinAccountDetails getAccountDetails() throws ParseException {
|
||||
if (getUserSessionId() == null) {
|
||||
throw new IllegalStateException("User session id missing.");
|
||||
}
|
||||
if (getDeveloperKey() == null || getDeveloperKey().isEmpty()) {
|
||||
throw new IllegalStateException("Developer key is missing.");
|
||||
}
|
||||
|
||||
Post post = new Post();
|
||||
post.put("api_dev_key", getDeveloperKey());
|
||||
post.put("api_user_key", getUserSessionId());
|
||||
post.put("api_option", "userdetails");
|
||||
|
||||
String response = Web.getContents(Pastebin.API_POST_LINK, post);
|
||||
|
||||
if (!response.startsWith("<user>")) {
|
||||
throw new ParseException("Failed to parse account details: "
|
||||
+ response);
|
||||
}
|
||||
|
||||
try {
|
||||
DocumentBuilderFactory dbFactory = DocumentBuilderFactory
|
||||
.newInstance();
|
||||
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
|
||||
Document doc = dBuilder.parse(new InputSource(
|
||||
new ByteArrayInputStream(response.getBytes("utf-8"))));
|
||||
doc.getDocumentElement().normalize();
|
||||
|
||||
return new PastebinAccountDetails((Element) doc
|
||||
.getElementsByTagName("user").item(0));
|
||||
} catch (Exception e) {
|
||||
throw new ParseException("Failed to parse account details: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,134 @@
|
||||
package org.jpaste.pastebin.account;
|
||||
|
||||
import org.jpaste.utils.xml.XMLUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
*
|
||||
* Holds information and settings of a pastebin account.
|
||||
*
|
||||
* @author Brian B
|
||||
*
|
||||
*/
|
||||
public class PastebinAccountDetails {
|
||||
private String username, format, expiration, avatarURL, website, email, location;
|
||||
private int userPrivate, accountType;
|
||||
|
||||
/**
|
||||
* Creates a new <code>PastebinAccountDetails</code> instance.
|
||||
*
|
||||
* @param userElement
|
||||
* the 'user' xml elements received from the pastebin API
|
||||
*/
|
||||
public PastebinAccountDetails(Element userElement) {
|
||||
this.username = XMLUtils.getText(userElement, "user_name");
|
||||
this.format = XMLUtils.getText(userElement, "user_format_short");
|
||||
this.expiration = XMLUtils.getText(userElement, "user_expiration");
|
||||
this.avatarURL = XMLUtils.getText(userElement, "user_avatar_url");
|
||||
this.userPrivate = Integer.parseInt(XMLUtils.getText(userElement, "user_private"));
|
||||
this.website = XMLUtils.getText(userElement, "user_website");
|
||||
this.email = XMLUtils.getText(userElement, "user_email");
|
||||
this.location = XMLUtils.getText(userElement, "user_location");
|
||||
this.accountType = Integer.parseInt(XMLUtils.getText(userElement, "user_account_type"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the username of this account
|
||||
* @return username
|
||||
*/
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets user text format
|
||||
* @return user text format
|
||||
*/
|
||||
public String getFormat() {
|
||||
return this.format;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this account expiration time
|
||||
* <p>
|
||||
* <code>N = never (default)</code>
|
||||
* </p>
|
||||
* @return account expiration time
|
||||
*/
|
||||
public String getExpiration() {
|
||||
return this.expiration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets URL to avatar image
|
||||
* @return URL to avatar image
|
||||
* @throws MalformedURLException
|
||||
*/
|
||||
public URL getAvatarURL() throws MalformedURLException {
|
||||
return new URL(this.avatarURL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets user visibility
|
||||
* <pre>
|
||||
* 0 = public
|
||||
* 1 = unlisted
|
||||
* 2 = private
|
||||
* </pre>
|
||||
* @return visibility of account
|
||||
*/
|
||||
public int getPrivate() {
|
||||
return this.userPrivate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user's set website
|
||||
* @return url to website
|
||||
* @throws MalformedURLException
|
||||
*/
|
||||
public URL getWebsite() throws MalformedURLException {
|
||||
if(this.website.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return new URL(this.website);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user e-mail
|
||||
* @return user account e-mail
|
||||
*/
|
||||
public String getEmail() {
|
||||
return this.email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user's set location
|
||||
* @return location, city
|
||||
*/
|
||||
public String getLocation() {
|
||||
return this.location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if this account is a 'pro' account
|
||||
* @return <code>true</code> if this account is a pro account, otherwise <code>false</code>.
|
||||
*/
|
||||
public boolean isPro() {
|
||||
return accountType == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the user his avatar from {@link #getAvatarURL()}
|
||||
* @return image
|
||||
* @throws IOException if image was not read
|
||||
*/
|
||||
public BufferedImage getAvatar() throws IOException {
|
||||
return ImageIO.read(getAvatarURL());
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package org.jpaste.pastebin.exceptions;
|
||||
|
||||
public class LoginException extends Exception {
|
||||
private static final long serialVersionUID = -4230960075582953775L;
|
||||
|
||||
public LoginException() {
|
||||
}
|
||||
|
||||
public LoginException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package org.jpaste.pastebin.exceptions;
|
||||
|
||||
public class ParseException extends Exception {
|
||||
private static final long serialVersionUID = -4230960075582953775L;
|
||||
|
||||
public ParseException() {
|
||||
}
|
||||
|
||||
public ParseException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
66
src/main/java/org/jpaste/utils/web/Post.java
Normal file
66
src/main/java/org/jpaste/utils/web/Post.java
Normal file
@ -0,0 +1,66 @@
|
||||
package org.jpaste.utils.web;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
*
|
||||
* A representation of a HTTP post
|
||||
*
|
||||
* <p>
|
||||
* Encodes parameters with the UTF-8 Charset.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <a href="http://en.wikipedia.org/wiki/POST_(HTTP)">Reference manual</a>
|
||||
* </p>
|
||||
*
|
||||
* @author Brian B
|
||||
*
|
||||
*/
|
||||
public class Post {
|
||||
private static final String ENCODING = "UTF-8";
|
||||
private HashMap<String, String> post;
|
||||
|
||||
/**
|
||||
* Creates a new <code>Post</code> instance.
|
||||
*/
|
||||
public Post() {
|
||||
post = new HashMap<String, String>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a key value pair to the post parameters
|
||||
*
|
||||
* @param key
|
||||
* the key
|
||||
* @param value
|
||||
* the value
|
||||
*/
|
||||
public void put(String key, String value) {
|
||||
try {
|
||||
this.post.put(URLEncoder.encode(key, ENCODING),
|
||||
URLEncoder.encode(value, ENCODING));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP post string representation
|
||||
*
|
||||
* @return HTTP Post contents
|
||||
*/
|
||||
public String getPost() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (Entry<String, String> entry : post.entrySet()) {
|
||||
builder.append(entry.getKey()).append('=').append(entry.getValue())
|
||||
.append('&');
|
||||
}
|
||||
builder.deleteCharAt(builder.length() - 1);
|
||||
return new String(builder);
|
||||
}
|
||||
|
||||
}
|
75
src/main/java/org/jpaste/utils/web/Web.java
Normal file
75
src/main/java/org/jpaste/utils/web/Web.java
Normal file
@ -0,0 +1,75 @@
|
||||
package org.jpaste.utils.web;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
|
||||
/**
|
||||
*
|
||||
* Web utility class
|
||||
*
|
||||
* @author Brian B
|
||||
*
|
||||
*/
|
||||
public class Web {
|
||||
|
||||
/**
|
||||
* Submits a HTTP post and fetches and returns the response
|
||||
*
|
||||
* @param link
|
||||
* The link/URL
|
||||
* @param post
|
||||
* the HTTP post representation
|
||||
* @return response of the web page
|
||||
*/
|
||||
public static String getContents(String link, Post post) {
|
||||
try {
|
||||
URL url = new URL(link);
|
||||
|
||||
URLConnection connection = url.openConnection();
|
||||
|
||||
if(post != null) {
|
||||
connection.setDoOutput(true);
|
||||
OutputStreamWriter wr = new OutputStreamWriter(
|
||||
connection.getOutputStream());
|
||||
wr.write(post.getPost());
|
||||
wr.flush();
|
||||
wr.close();
|
||||
}
|
||||
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(
|
||||
connection.getInputStream()));
|
||||
StringBuilder builder = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (builder.length() > 0) {
|
||||
builder.append('\n');
|
||||
}
|
||||
builder.append(line);
|
||||
}
|
||||
reader.close();
|
||||
return new String(builder);
|
||||
} catch (MalformedURLException e) {
|
||||
throw new IllegalArgumentException("Malformed link: " + e);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Failed to fetch contents from link: "
|
||||
+ e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets text from a link
|
||||
*
|
||||
* @param link
|
||||
* The link/URL
|
||||
* @return response of the web page
|
||||
*/
|
||||
public static String getContents(String link) {
|
||||
return getContents(link, null);
|
||||
}
|
||||
|
||||
}
|
27
src/main/java/org/jpaste/utils/xml/XMLUtils.java
Normal file
27
src/main/java/org/jpaste/utils/xml/XMLUtils.java
Normal file
@ -0,0 +1,27 @@
|
||||
package org.jpaste.utils.xml;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
*
|
||||
* Holds various XML utility methods
|
||||
*
|
||||
* @author Brian B
|
||||
*
|
||||
*/
|
||||
public class XMLUtils {
|
||||
|
||||
/**
|
||||
* Fetches text from a element
|
||||
*
|
||||
* @param parent
|
||||
* the parent of the element you want to fetch text from
|
||||
* @param tagName
|
||||
* name of the element you want to fetch text from
|
||||
* @return text of tag
|
||||
*/
|
||||
public static String getText(Element parent, String tagName) {
|
||||
return parent.getElementsByTagName(tagName).item(0).getTextContent();
|
||||
}
|
||||
|
||||
}
|
142
src/main/resources/config.yml
Normal file
142
src/main/resources/config.yml
Normal file
@ -0,0 +1,142 @@
|
||||
version: '${project.version}'
|
||||
|
||||
# Providers of this plugin
|
||||
# NONE: Returns no server
|
||||
# DIRECT: Returns the only server in the list
|
||||
# LOCALIZED: Returns the server that matches a region (testing)
|
||||
# LOWEST: Returns the server with the least players online
|
||||
# RANDOM: Returns a random server
|
||||
# PROGRESSIVE: Returns the first server that is not full
|
||||
# FILLER: Returns the server with the most players online that is not full
|
||||
|
||||
settings:
|
||||
# The plugin will be disabled as default
|
||||
enabled: false
|
||||
|
||||
# Disable the messages the plugin prints out when loading
|
||||
silent-startup: false
|
||||
|
||||
# Whether the plugin should ask you to update or not
|
||||
check-updates: true
|
||||
|
||||
# Pings to the servers to see if they can be accessed or not
|
||||
server-check:
|
||||
# If this is disabled the players will connect to the first server available
|
||||
enabled: true
|
||||
|
||||
# Use either CUSTOM or GENERIC, the first one generally works the best
|
||||
tactic: CUSTOM
|
||||
|
||||
# The attempts before giving up on getting a server for a player
|
||||
attempts: 5
|
||||
|
||||
# The interval between every round of checks
|
||||
interval: 10000
|
||||
|
||||
# This prints info every time the plugin checks a server and prints its results
|
||||
print-info: false
|
||||
|
||||
# The descriptions that mark a server as non accessible
|
||||
marker-motds: ["Server is not accessible", "Gamemode has already started"]
|
||||
|
||||
# This will connect the players to a server
|
||||
reconnect-kick:
|
||||
enabled: true
|
||||
|
||||
# If enabled, the reasons will work as a blacklist instead of a whitelist
|
||||
inverted: false
|
||||
|
||||
# The reasons that determine if a player is reconnected or not, supports regex
|
||||
reasons: []
|
||||
|
||||
# Sections where this feature is ignored
|
||||
ignored: []
|
||||
|
||||
# This prints info every time a player gets kicked telling you the reason and if it matches the reasons
|
||||
print-info: false
|
||||
|
||||
# The message the player is sent when kicked, comment it out to remove the message
|
||||
message: '&cYou have been kicked from &a{from} &cand you are being moved to &a{to}&c, reason: &a{reason}'
|
||||
|
||||
# Override the behavior with rules
|
||||
rules: {}
|
||||
|
||||
backward-command:
|
||||
enabled: true
|
||||
name: 'backward'
|
||||
aliases: ['lobby', 'hub', 'back']
|
||||
permission: ''
|
||||
|
||||
# Sections where this command is ignored
|
||||
ignored: []
|
||||
|
||||
# Whether the command can accept the name of a section as a target
|
||||
arguments: false
|
||||
|
||||
# Override the behavior with rules
|
||||
rules: {}
|
||||
|
||||
# This gets the country of a player and decides to which server the player should go
|
||||
# WARNING: In testing stage
|
||||
geolocation:
|
||||
enabled: false
|
||||
rules: {}
|
||||
|
||||
# This will reload the plugin everytime you execute /greload
|
||||
auto-reload: true
|
||||
|
||||
# Support for getting the players on a server with RedisBungee
|
||||
redis-bungee: false
|
||||
|
||||
# Assign a target to a player instead of looking every time for one
|
||||
assign-targets: false
|
||||
|
||||
messages:
|
||||
connecting: '&aConnecting to {server}'
|
||||
failure: '&cCould not find a server to connect to'
|
||||
unavailable: '&cThis command cannot be executed on this server'
|
||||
unknown: '&cCould not find a section with that name'
|
||||
|
||||
# Here you have an example of what you can do with the sections
|
||||
# It is recommended to create your own sections
|
||||
# The plugin will print out info telling you if your config is right or not
|
||||
# The best way to understand this is to play around with it
|
||||
# You can use regex to match a set of servers
|
||||
sections:
|
||||
general-lobbies:
|
||||
principal: true
|
||||
provider: RANDOM
|
||||
server: 'general-lobbies'
|
||||
servers: ["Lobby1", "Lobby2", "Lobby3"]
|
||||
eggwars-lobbies:
|
||||
parent: 'general-lobbies'
|
||||
server: 'eggwars-lobbies'
|
||||
servers: ["EWLobby1", "EWLobby2", "EWLobby3"]
|
||||
eggwars-games:
|
||||
provider: FILLER
|
||||
parent: 'eggwars-lobbies'
|
||||
servers: ["EW1", "EW2", "EW3", "EW4", "EW5"]
|
||||
command:
|
||||
name: 'playeggwars'
|
||||
permission: ''
|
||||
aliases: []
|
||||
skywars-lobbies:
|
||||
parent: 'general-lobbies'
|
||||
server: 'skywars-lobbies'
|
||||
servers: ["SWLobby1", "SWLobby2", "SWLobby3"]
|
||||
skywars-games:
|
||||
provider: FILLER
|
||||
parent: 'skywars-lobbies'
|
||||
servers: ["SW1", "SW2", "SW3", "SW4", "SW5"]
|
||||
command:
|
||||
name: 'playskywars'
|
||||
permission: ''
|
||||
aliases: []
|
||||
practice:
|
||||
provider: LOCALIZED
|
||||
parent: 'general-lobbies'
|
||||
servers: ["EUPractice", "USPractice"]
|
||||
command:
|
||||
name: 'practice'
|
||||
permission: ''
|
||||
aliases: ["rektnoobs"]
|
5
src/main/resources/plugin.yml
Normal file
5
src/main/resources/plugin.yml
Normal file
@ -0,0 +1,5 @@
|
||||
name: LobbyBalancer
|
||||
main: me.jaimemartz.lobbybalancer.LobbyBalancer
|
||||
version: ${project.version}
|
||||
author: jaime29010
|
||||
softdepend: [RedisBungee]
|
23
src/test/java/Test1.java
Normal file
23
src/test/java/Test1.java
Normal file
@ -0,0 +1,23 @@
|
||||
import me.jaimemartz.lobbybalancer.connection.ProviderType;
|
||||
import org.junit.Test;
|
||||
|
||||
public class Test1 {
|
||||
//@Test
|
||||
public void test1() {
|
||||
for (int i = 0; i <= 500; i++) {
|
||||
int port = (int) Math.floor(Math.random() * (0xFFFF + 1));
|
||||
System.out.println(port);
|
||||
|
||||
if (port < 0 || port > 0xFFFF) {
|
||||
throw new IllegalArgumentException("port out of range:" + port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test2() {
|
||||
for (ProviderType provider : ProviderType.values()) {
|
||||
System.out.println(String.format("Provider %s: %s", provider.name(), provider.getDescription()));
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user