diff --git a/pom.xml b/pom.xml
index db21ff8e..334a47c7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -189,6 +189,7 @@
com.dumptruckman.minecraft:buscript
org.mcstats.bukkit:metrics
com.dumptruckman.minecraft:Logging
+ org.codehaus.jettison:jettison
@@ -216,6 +217,10 @@
com.dumptruckman.minecraft.util.DebugLog
com.onarandombox.MultiverseCore.utils.DebugFileLogger
+
+ org.codehaus.jettison.json
+ org.codehaus.jettison.json.multiverse
+
@@ -334,6 +339,13 @@
+
+
+ org.codehaus.jettison
+ jettison
+ 1.3.7
+
+
junit
diff --git a/src/main/java/com/onarandombox/MultiverseCore/commands/VersionCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commands/VersionCommand.java
index a1fbdb5c..37a6bf97 100644
--- a/src/main/java/com/onarandombox/MultiverseCore/commands/VersionCommand.java
+++ b/src/main/java/com/onarandombox/MultiverseCore/commands/VersionCommand.java
@@ -20,8 +20,12 @@ import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.permissions.PermissionDefault;
+import org.bukkit.scheduler.BukkitRunnable;
+import java.io.*;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
/**
* Dumps version info to the console.
@@ -32,7 +36,7 @@ public class VersionCommand extends MultiverseCommand {
public VersionCommand(MultiverseCore plugin) {
super(plugin);
this.setName("Multiverse Version");
- this.setCommandUsage("/mv version " + ChatColor.GOLD + "-[pb]");
+ this.setCommandUsage("/mv version " + ChatColor.GOLD + "-[pbg]");
this.setArgRange(0, 1);
this.addKey("mv version");
this.addKey("mvv");
@@ -41,6 +45,98 @@ public class VersionCommand extends MultiverseCommand {
"Dumps version info to the console, optionally to pastie.org with -p or pastebin.com with a -b.", PermissionDefault.TRUE);
}
+ private String getLegacyString() {
+ StringBuilder legacyFile = new StringBuilder();
+ legacyFile.append("[Multiverse-Core] Multiverse-Core Version: ").append(this.plugin.getDescription().getVersion()).append('\n');
+ legacyFile.append("[Multiverse-Core] Bukkit Version: ").append(this.plugin.getServer().getVersion()).append('\n');
+ legacyFile.append("[Multiverse-Core] Loaded Worlds: ").append(this.plugin.getMVWorldManager().getMVWorlds()).append('\n');
+ legacyFile.append("[Multiverse-Core] Multiverse Plugins Loaded: ").append(this.plugin.getPluginCount()).append('\n');
+ legacyFile.append("[Multiverse-Core] Economy being used: ").append(plugin.getEconomist().getEconomyName()).append('\n');
+ legacyFile.append("[Multiverse-Core] Permissions Plugin: ").append(this.plugin.getMVPerms().getType()).append('\n');
+ legacyFile.append("[Multiverse-Core] Dumping Config Values: (version ")
+ .append(this.plugin.getMVConfig().getVersion()).append(")").append('\n');
+ legacyFile.append("[Multiverse-Core] messagecooldown: ").append(plugin.getMessaging().getCooldown()).append('\n');
+ legacyFile.append("[Multiverse-Core] teleportcooldown: ").append(plugin.getMVConfig().getTeleportCooldown()).append('\n');
+ legacyFile.append("[Multiverse-Core] worldnameprefix: ").append(plugin.getMVConfig().getPrefixChat()).append('\n');
+ legacyFile.append("[Multiverse-Core] worldnameprefixFormat: ").append(plugin.getMVConfig().getPrefixChatFormat()).append('\n');
+ legacyFile.append("[Multiverse-Core] enforceaccess: ").append(plugin.getMVConfig().getEnforceAccess()).append('\n');
+ legacyFile.append("[Multiverse-Core] displaypermerrors: ").append(plugin.getMVConfig().getDisplayPermErrors()).append('\n');
+ legacyFile.append("[Multiverse-Core] teleportintercept: ").append(plugin.getMVConfig().getTeleportIntercept()).append('\n');
+ legacyFile.append("[Multiverse-Core] firstspawnoverride: ").append(plugin.getMVConfig().getFirstSpawnOverride()).append('\n');
+ legacyFile.append("[Multiverse-Core] firstspawnworld: ").append(plugin.getMVConfig().getFirstSpawnWorld()).append('\n');
+ legacyFile.append("[Multiverse-Core] debug: ").append(plugin.getMVConfig().getGlobalDebug()).append('\n');
+ legacyFile.append("[Multiverse-Core] Special Code: FRN002").append('\n');
+ return legacyFile.toString();
+ }
+
+ private String getMarkdownString() {
+ StringBuilder markdownString = new StringBuilder();
+ markdownString.append("# Multiverse-Core\n");
+ markdownString.append("## Overview\n");
+ markdownString.append("| Name | Value |\n");
+ markdownString.append("| --- | --- |\n");
+ markdownString.append("| Multiverse-Core Version | `").append(this.plugin.getDescription().getVersion()).append("` |\n");
+ markdownString.append("| Bukkit Version | `").append(this.plugin.getServer().getVersion()).append("` |\n");
+ //markdownString.append("| Loaded Worlds | `").append(this.plugin.getMVWorldManager().getMVWorlds()).append("` |\n");
+ markdownString.append("| Multiverse Plugins Loaded | `").append(this.plugin.getPluginCount()).append("` |\n");
+ markdownString.append("| Economy being used | `").append(plugin.getEconomist().getEconomyName()).append("` |\n");
+ markdownString.append("| Permissions Plugin | `").append(this.plugin.getMVPerms().getType()).append("` |\n");
+ markdownString.append("## Parsed Config\n");
+ markdownString.append("These are what Multiverse thought the in-memory values of the config were.\n\n");
+ markdownString.append("| Config Key | Value |\n");
+ markdownString.append("| --- | --- |\n");
+ markdownString.append("| version | `").append(this.plugin.getMVConfig().getVersion()).append("` |\n");
+ markdownString.append("| messagecooldown | `").append(plugin.getMessaging().getCooldown()).append("` |\n");
+ markdownString.append("| teleportcooldown | `").append(plugin.getMVConfig().getTeleportCooldown()).append("` |\n");
+ markdownString.append("| worldnameprefix | `").append(plugin.getMVConfig().getPrefixChat()).append("` |\n");
+ markdownString.append("| worldnameprefixFormat | `").append(plugin.getMVConfig().getPrefixChatFormat()).append("` |\n");
+ markdownString.append("| enforceaccess | `").append(plugin.getMVConfig().getEnforceAccess()).append("` |\n");
+ markdownString.append("| displaypermerrors | `").append(plugin.getMVConfig().getDisplayPermErrors()).append("` |\n");
+ markdownString.append("| teleportintercept | `").append(plugin.getMVConfig().getTeleportIntercept()).append("` |\n");
+ markdownString.append("| firstspawnoverride | `").append(plugin.getMVConfig().getFirstSpawnOverride()).append("` |\n");
+ markdownString.append("| firstspawnworld | `").append(plugin.getMVConfig().getFirstSpawnWorld()).append("` |\n");
+ markdownString.append("| debug | `").append(plugin.getMVConfig().getGlobalDebug()).append("` |\n");
+ return markdownString.toString();
+ }
+
+ private String readFile(final String filename) {
+ String result;
+ try {
+ FileReader reader = new FileReader(filename);
+ BufferedReader bufferedReader = new BufferedReader(reader);
+ String line;
+ result = "";
+ while ((line = bufferedReader.readLine()) != null) {
+ result += line + '\n';
+ }
+ } catch (FileNotFoundException e) {
+ Logging.severe("Unable to find %s. Here's the traceback: %s", filename, e.getMessage());
+ e.printStackTrace();
+ result = String.format("ERROR: Could not load: %s", filename);
+ } catch (IOException e) {
+ Logging.severe("Something bad happend when reading %s. Here's the traceback: %s", filename, e.getMessage());
+ e.printStackTrace();
+ result = String.format("ERROR: Could not load: %s", filename);
+ }
+ return result;
+ }
+
+ private Map getVersionFiles() {
+ Map files = new HashMap();
+
+ // Add the legacy file, but as markdown so it's readable
+ files.put("version.md", this.getMarkdownString());
+
+ // Add the config.yml
+ File configFile = new File(this.plugin.getDataFolder(), "config.yml");
+ files.put(configFile.getName(), this.readFile(configFile.getAbsolutePath()));
+
+ // Add the config.yml
+ File worldConfig = new File(this.plugin.getDataFolder(), "worlds.yml");
+ files.put(worldConfig.getName(), this.readFile(worldConfig.getAbsolutePath()));
+ return files;
+ }
+
@Override
public void runCommand(final CommandSender sender, final List args) {
// Check if the command was sent from a Player.
@@ -48,28 +144,8 @@ public class VersionCommand extends MultiverseCommand {
sender.sendMessage("Version info dumped to console. Please check your server logs.");
}
- StringBuilder buffer = new StringBuilder();
- buffer.append("[Multiverse-Core] Multiverse-Core Version: ").append(this.plugin.getDescription().getVersion()).append('\n');
- buffer.append("[Multiverse-Core] Bukkit Version: ").append(this.plugin.getServer().getVersion()).append('\n');
- buffer.append("[Multiverse-Core] Loaded Worlds: ").append(this.plugin.getMVWorldManager().getMVWorlds()).append('\n');
- buffer.append("[Multiverse-Core] Multiverse Plugins Loaded: ").append(this.plugin.getPluginCount()).append('\n');
- buffer.append("[Multiverse-Core] Economy being used: ").append(plugin.getEconomist().getEconomyName()).append('\n');
- buffer.append("[Multiverse-Core] Permissions Plugin: ").append(this.plugin.getMVPerms().getType()).append('\n');
- buffer.append("[Multiverse-Core] Dumping Config Values: (version ")
- .append(this.plugin.getMVConfig().getVersion()).append(")").append('\n');
- buffer.append("[Multiverse-Core] messagecooldown: ").append(plugin.getMessaging().getCooldown()).append('\n');
- buffer.append("[Multiverse-Core] teleportcooldown: ").append(plugin.getMVConfig().getTeleportCooldown()).append('\n');
- buffer.append("[Multiverse-Core] worldnameprefix: ").append(plugin.getMVConfig().getPrefixChat()).append('\n');
- buffer.append("[Multiverse-Core] worldnameprefixFormat: ").append(plugin.getMVConfig().getPrefixChatFormat()).append('\n');
- buffer.append("[Multiverse-Core] enforceaccess: ").append(plugin.getMVConfig().getEnforceAccess()).append('\n');
- buffer.append("[Multiverse-Core] displaypermerrors: ").append(plugin.getMVConfig().getDisplayPermErrors()).append('\n');
- buffer.append("[Multiverse-Core] teleportintercept: ").append(plugin.getMVConfig().getTeleportIntercept()).append('\n');
- buffer.append("[Multiverse-Core] firstspawnoverride: ").append(plugin.getMVConfig().getFirstSpawnOverride()).append('\n');
- buffer.append("[Multiverse-Core] firstspawnworld: ").append(plugin.getMVConfig().getFirstSpawnWorld()).append('\n');
- buffer.append("[Multiverse-Core] debug: ").append(plugin.getMVConfig().getGlobalDebug()).append('\n');
- buffer.append("[Multiverse-Core] Special Code: FRN002").append('\n');
-
- MVVersionEvent versionEvent = new MVVersionEvent(buffer.toString());
+ MVVersionEvent versionEvent = new MVVersionEvent(this.getLegacyString(), this.getVersionFiles());
+ final Map files = this.getVersionFiles();
this.plugin.getServer().getPluginManager().callEvent(versionEvent);
// log to console
@@ -85,9 +161,14 @@ public class VersionCommand extends MultiverseCommand {
if (args.size() == 1) {
String pasteUrl;
if (args.get(0).equalsIgnoreCase("-p")) {
- pasteUrl = postToService(PasteServiceType.PASTIE, true, data); // private post to pastie
+ // private post to pastie
+ pasteUrl = postToService(PasteServiceType.PASTIE, true, data, files);
} else if (args.get(0).equalsIgnoreCase("-b")) {
- pasteUrl = postToService(PasteServiceType.PASTEBIN, true, data); // private post to pastie
+ // private post to pastebin
+ pasteUrl = postToService(PasteServiceType.PASTEBIN, true, data, files);
+ } else if (args.get(0).equalsIgnoreCase("-g")) {
+ // private post to github
+ pasteUrl = postToService(PasteServiceType.GITHUB, true, data, files);
} else {
return;
}
@@ -102,14 +183,23 @@ public class VersionCommand extends MultiverseCommand {
/**
* Send the current contents of this.pasteBinBuffer to a web service.
*
- * @param type Service type to send to
- * @param isPrivate Should the paste be marked as private.
+ * @param type Service type to send paste data to.
+ * @param isPrivate Should the paste be marked as private.
+ * @param pasteData Legacy string only data to post to a service.
+ * @param pasteFiles Map of filenames/contents of debug info.
* @return URL of visible paste
*/
- private static String postToService(PasteServiceType type, boolean isPrivate, String pasteData) {
+ private static String postToService(PasteServiceType type, boolean isPrivate, String pasteData,
+ Map pasteFiles) {
PasteService ps = PasteServiceFactory.getService(type, isPrivate);
try {
- return SHORTENER.shorten(ps.postData(ps.encodeData(pasteData), ps.getPostURL()));
+ String result;
+ if (ps.supportsMultiFile()) {
+ result = ps.postData(ps.encodeData(pasteFiles), ps.getPostURL());
+ } else {
+ result = ps.postData(ps.encodeData(pasteData), ps.getPostURL());
+ }
+ return SHORTENER.shorten(result);
} catch (PasteFailedException e) {
System.out.print(e);
return "Error posting to service";
diff --git a/src/main/java/com/onarandombox/MultiverseCore/event/MVVersionEvent.java b/src/main/java/com/onarandombox/MultiverseCore/event/MVVersionEvent.java
index d1bbeeb7..43c1ddfc 100644
--- a/src/main/java/com/onarandombox/MultiverseCore/event/MVVersionEvent.java
+++ b/src/main/java/com/onarandombox/MultiverseCore/event/MVVersionEvent.java
@@ -3,15 +3,19 @@ package com.onarandombox.MultiverseCore.event;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
+import java.util.Map;
+
/**
* Called when somebody requests version information about Multiverse.
*/
public class MVVersionEvent extends Event {
private final StringBuilder versionInfoBuilder;
+ private final Map detailedVersionInfo;
- public MVVersionEvent(String versionInfo) {
- this.versionInfoBuilder = new StringBuilder(versionInfo);
+ public MVVersionEvent(String legacyVersionInfo, Map files) {
+ this.versionInfoBuilder = new StringBuilder(legacyVersionInfo);
+ this.detailedVersionInfo = files;
}
private static final HandlerList HANDLERS = new HandlerList();
@@ -40,6 +44,21 @@ public class MVVersionEvent extends Event {
return this.versionInfoBuilder.toString();
}
+ /**
+ * Gets the key/value pair of the detailed version info.
+ *
+ * This information is used for advanced paste services that would prefer
+ * to get the information as several files. Examples include config.yml or
+ * portals.yml.
+ *
+ * The keys are filenames, the values are the contents of the files.
+ *
+ * @return The key value mapping of files and the contents of those files.
+ */
+ public Map getDetailedVersionInfo() {
+ return this.detailedVersionInfo;
+ }
+
/**
* Appends more version-info to the version-info currently saved in this event.
* @param moreVersionInfo The version-info to add. Should end with '\n'.
diff --git a/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/GithubPasteService.java b/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/GithubPasteService.java
new file mode 100644
index 00000000..86f9888e
--- /dev/null
+++ b/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/GithubPasteService.java
@@ -0,0 +1,105 @@
+package com.onarandombox.MultiverseCore.utils.webpaste;
+
+import org.codehaus.jettison.json.JSONException;
+import org.codehaus.jettison.json.JSONObject;
+
+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;
+import java.util.HashMap;
+import java.util.Map;
+
+public class GithubPasteService implements PasteService {
+
+ private final boolean isPrivate;
+
+ public GithubPasteService(boolean isPrivate) {
+ this.isPrivate = isPrivate;
+ }
+
+ @Override
+ public String encodeData(String data) {
+ Map mapData = new HashMap();
+ mapData.put("multiverse.txt", data);
+ return this.encodeData(mapData);
+ }
+
+ @Override
+ public String encodeData(Map files) {
+ JSONObject root = new JSONObject();
+ String result = "";
+ try {
+ root.put("description", "Multiverse-Core Debug Info");
+ root.put("public", !this.isPrivate);
+ JSONObject fileList = new JSONObject();
+ for (Map.Entry entry : files.entrySet())
+ {
+ JSONObject fileObject = new JSONObject();
+ fileObject.put("content", entry.getValue());
+ fileList.put(entry.getKey(), fileObject);
+ }
+ root.put("files", fileList);
+ result = root.toString();
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ return result;
+ }
+
+ @Override
+ public URL getPostURL() {
+ try {
+ return new URL("https://api.github.com/gists");
+ //return new URL("http://jsonplaceholder.typicode.com/posts");
+ } catch (MalformedURLException e) {
+ return null; // should never hit here
+ }
+ }
+
+ @Override
+ public String postData(String encodedData, URL url) throws PasteFailedException {
+ OutputStreamWriter wr = null;
+ BufferedReader rd = null;
+ try {
+ URLConnection conn = url.openConnection();
+ conn.setDoOutput(true);
+ wr = new OutputStreamWriter(conn.getOutputStream());
+ wr.write(encodedData);
+ wr.flush();
+
+ rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
+ String line;
+ String pastieUrl = "";
+ //Pattern pastiePattern = this.getURLMatchingPattern();
+ StringBuilder responseString = new StringBuilder();
+
+ while ((line = rd.readLine()) != null) {
+ responseString.append(line);
+ }
+ JSONObject response = new JSONObject(responseString.toString());
+ return response.get("html_url").toString();
+ } catch (Exception e) {
+ throw new PasteFailedException(e);
+ } finally {
+ if (wr != null) {
+ try {
+ wr.close();
+ } catch (IOException ignore) { }
+ }
+ if (rd != null) {
+ try {
+ rd.close();
+ } catch (IOException ignore) { }
+ }
+ }
+ }
+
+ @Override
+ public boolean supportsMultiFile() {
+ return true;
+ }
+}
diff --git a/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PasteService.java b/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PasteService.java
index 2bc9324e..71ba3a8e 100644
--- a/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PasteService.java
+++ b/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PasteService.java
@@ -1,6 +1,7 @@
package com.onarandombox.MultiverseCore.utils.webpaste;
import java.net.URL;
+import java.util.Map;
/**
* An interface to a web-based text-pasting service. Classes implementing this
@@ -24,6 +25,14 @@ public interface PasteService {
*/
String encodeData(String data);
+ /**
+ * Encode the given Map data into a format suitable for transmission in an HTTP request.
+ *
+ * @param data The raw data to encode.
+ * @return A URL-encoded string.
+ */
+ String encodeData(Map data);
+
/**
* Get the URL to which this paste service sends new pastes.
*
@@ -42,4 +51,13 @@ public interface PasteService {
*/
String postData(String encodedData, URL url) throws PasteFailedException;
+ /**
+ * Does this service support uploading multiple files.
+ *
+ * Newer services like gist support multi-file which allows us to upload configs
+ * in addition to the standard logs.
+ *
+ * @return True if this service supports multiple file upload.
+ */
+ boolean supportsMultiFile();
}
diff --git a/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PasteServiceFactory.java b/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PasteServiceFactory.java
index e5a63f84..1319ac20 100644
--- a/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PasteServiceFactory.java
+++ b/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PasteServiceFactory.java
@@ -18,6 +18,8 @@ public class PasteServiceFactory {
return new PastebinPasteService(isPrivate);
case PASTIE:
return new PastiePasteService(isPrivate);
+ case GITHUB:
+ return new GithubPasteService(isPrivate);
default:
return null;
}
diff --git a/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PasteServiceType.java b/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PasteServiceType.java
index 51d3089a..5954dd88 100644
--- a/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PasteServiceType.java
+++ b/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PasteServiceType.java
@@ -14,5 +14,9 @@ public enum PasteServiceType {
/**
* @see PastiePasteService
*/
- PASTIE
+ PASTIE,
+ /**
+ * @see GithubPasteService
+ */
+ GITHUB
}
diff --git a/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PastebinPasteService.java b/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PastebinPasteService.java
index 8dce6b99..3f06f612 100644
--- a/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PastebinPasteService.java
+++ b/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PastebinPasteService.java
@@ -9,6 +9,7 @@ import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
+import java.util.Map;
/**
* Pastes to {@code pastebin.com}.
@@ -50,6 +51,11 @@ public class PastebinPasteService implements PasteService {
}
}
+ @Override
+ public String encodeData(Map data) {
+ return null;
+ }
+
/**
* {@inheritDoc}
*/
@@ -86,4 +92,9 @@ public class PastebinPasteService implements PasteService {
}
}
}
+
+ @Override
+ public boolean supportsMultiFile() {
+ return false;
+ }
}
diff --git a/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PastiePasteService.java b/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PastiePasteService.java
index 3cb0f169..16c062a2 100644
--- a/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PastiePasteService.java
+++ b/src/main/java/com/onarandombox/MultiverseCore/utils/webpaste/PastiePasteService.java
@@ -9,6 +9,7 @@ import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
+import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -51,6 +52,11 @@ public class PastiePasteService implements PasteService {
}
}
+ @Override
+ public String encodeData(Map data) {
+ return null;
+ }
+
/**
* {@inheritDoc}
*/
@@ -93,6 +99,11 @@ public class PastiePasteService implements PasteService {
}
}
+ @Override
+ public boolean supportsMultiFile() {
+ return false;
+ }
+
private Pattern getURLMatchingPattern() {
if (this.isPrivate) {
return Pattern.compile(".*http://pastie.org/.*key=([0-9a-z]+).*");