forked from GeyserMC/Geyser
Add dump command (#808)
* Add dump command Adds a command to collect and dump infomation about the Geyser install and bootstrap and submit it to a dumps site. * Finalize URL; misc. fixes; add 'architecture' param Co-authored-by: DoctorMacc <toy.fighter1@gmail.com>
This commit is contained in:
parent
75f470cb33
commit
7743f6d718
19 changed files with 699 additions and 6 deletions
|
@ -170,6 +170,11 @@
|
|||
<skipPoms>false</skipPoms>
|
||||
<excludeProperties>
|
||||
<excludeProperty>git.user.*</excludeProperty>
|
||||
<excludeProperty>git.*.user.*</excludeProperty>
|
||||
<excludeProperty>git.closest.*</excludeProperty>
|
||||
<excludeProperty>git.commit.id.describe</excludeProperty>
|
||||
<excludeProperty>git.commit.id.describe-short</excludeProperty>
|
||||
<excludeProperty>git.commit.message.short</excludeProperty>
|
||||
</excludeProperties>
|
||||
<commitIdGenerationMode>flat</commitIdGenerationMode>
|
||||
<gitDescribe>
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
package org.geysermc.connector.bootstrap;
|
||||
|
||||
import org.geysermc.connector.dump.BootstrapDumpInfo;
|
||||
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||
import org.geysermc.connector.configuration.GeyserConfiguration;
|
||||
import org.geysermc.connector.GeyserLogger;
|
||||
|
@ -92,4 +93,11 @@ public interface GeyserBootstrap {
|
|||
* @return Path location of data folder
|
||||
*/
|
||||
Path getConfigFolder();
|
||||
|
||||
/**
|
||||
* Information used for the bootstrap section of the debug dump
|
||||
*
|
||||
* @return The info about the bootstrap
|
||||
*/
|
||||
BootstrapDumpInfo getDumpInfo();
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ public abstract class CommandManager {
|
|||
registerCommand(new ReloadCommand(connector, "reload", "Reloads the Geyser configurations. Kicks all players when used!", "geyser.command.reload"));
|
||||
registerCommand(new StopCommand(connector, "stop", "Shuts down Geyser.", "geyser.command.stop"));
|
||||
registerCommand(new OffhandCommand(connector, "offhand", "Puts an items in your offhand.", "geyser.command.offhand"));
|
||||
registerCommand(new DumpCommand(connector, "dump", "Dumps Geyser debug infomation for bug reports.", "geyser.command.dump"));
|
||||
}
|
||||
|
||||
public void registerCommand(GeyserCommand command) {
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.command.defaults;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
|
||||
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
|
||||
import org.geysermc.common.ChatColor;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.command.CommandSender;
|
||||
import org.geysermc.connector.command.GeyserCommand;
|
||||
import org.geysermc.connector.dump.DumpInfo;
|
||||
import org.geysermc.connector.utils.WebUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class DumpCommand extends GeyserCommand {
|
||||
|
||||
private final GeyserConnector connector;
|
||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||
private static final String DUMP_URL = "https://dump.geysermc.org/";
|
||||
|
||||
public DumpCommand(GeyserConnector connector, String name, String description, String permission) {
|
||||
super(name, description, permission);
|
||||
|
||||
this.connector = connector;
|
||||
|
||||
final SimpleFilterProvider filter = new SimpleFilterProvider();
|
||||
filter.addFilter("dump_user_auth", SimpleBeanPropertyFilter.serializeAllExcept(new String[] {"password"}));
|
||||
|
||||
MAPPER.setFilterProvider(filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender, String[] args) {
|
||||
sender.sendMessage("Collecting dump info");
|
||||
String dumpData = "";
|
||||
try {
|
||||
dumpData = MAPPER.writeValueAsString(new DumpInfo());
|
||||
} catch (IOException e) {
|
||||
sender.sendMessage(ChatColor.RED + "Failed to collect dump info, check console for more information");
|
||||
connector.getLogger().error("Failed to collect dump info", e);
|
||||
return;
|
||||
}
|
||||
|
||||
sender.sendMessage("Uploading dump");
|
||||
String response;
|
||||
JsonNode responseNode;
|
||||
try {
|
||||
response = WebUtils.post(DUMP_URL + "documents", dumpData);
|
||||
responseNode = MAPPER.readTree(response);
|
||||
} catch (IOException e) {
|
||||
sender.sendMessage(ChatColor.RED + "Failed to upload dump, check console for more information");
|
||||
connector.getLogger().error("Failed to upload dump", e);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!responseNode.has("key")) {
|
||||
sender.sendMessage(ChatColor.RED + "Failed to upload dump: " + (responseNode.has("message") ? responseNode.get("message").asText() : response));
|
||||
return;
|
||||
}
|
||||
|
||||
String uploadedDumpUrl = DUMP_URL + responseNode.get("key").asText();
|
||||
sender.sendMessage("We've made a dump with useful information, report your issue and provide this url: " + ChatColor.DARK_AQUA + uploadedDumpUrl);
|
||||
if (!sender.isConsole()) {
|
||||
connector.getLogger().info(sender.getName() + " created a GeyserDump at " + uploadedDumpUrl);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -30,6 +30,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
|||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.geysermc.common.serializer.AsteriskSerializer;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
|
@ -111,16 +112,16 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
|
|||
@Setter
|
||||
private int port;
|
||||
|
||||
private String motd1;
|
||||
private String motd2;
|
||||
|
||||
@JsonProperty("auth-type")
|
||||
private String authType;
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class UserAuthenticationInfo implements IUserAuthenticationInfo {
|
||||
@AsteriskSerializer.Asterisk()
|
||||
private String email;
|
||||
|
||||
@AsteriskSerializer.Asterisk()
|
||||
private String password;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.dump;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.common.PlatformType;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
public class BootstrapDumpInfo {
|
||||
|
||||
private PlatformType platform;
|
||||
|
||||
public BootstrapDumpInfo() {
|
||||
this.platform = GeyserConnector.getInstance().getPlatformType();
|
||||
}
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public class PluginInfo {
|
||||
|
||||
public boolean enabled;
|
||||
public String name;
|
||||
public String version;
|
||||
public String main;
|
||||
public List<String> authors;
|
||||
}
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public class ListenerInfo {
|
||||
|
||||
public String ip;
|
||||
public int port;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2020 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*
|
||||
*/
|
||||
|
||||
package org.geysermc.connector.dump;
|
||||
|
||||
import com.github.steveice10.mc.protocol.MinecraftConstants;
|
||||
import lombok.Getter;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.configuration.GeyserConfiguration;
|
||||
import org.geysermc.connector.utils.DockerCheck;
|
||||
import org.geysermc.connector.utils.FileUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Properties;
|
||||
|
||||
@Getter
|
||||
public class DumpInfo {
|
||||
|
||||
private final DumpInfo.VersionInfo versionInfo;
|
||||
private Properties gitInfo;
|
||||
private final GeyserConfiguration config;
|
||||
private final BootstrapDumpInfo bootstrapInfo;
|
||||
|
||||
public DumpInfo() {
|
||||
try {
|
||||
this.gitInfo = new Properties();
|
||||
this.gitInfo.load(FileUtils.getResource("git.properties"));
|
||||
} catch (IOException ignored) { }
|
||||
|
||||
this.config = GeyserConnector.getInstance().getConfig();
|
||||
|
||||
this.versionInfo = new DumpInfo.VersionInfo();
|
||||
this.bootstrapInfo = GeyserConnector.getInstance().getBootstrap().getDumpInfo();
|
||||
}
|
||||
|
||||
@Getter
|
||||
public class VersionInfo {
|
||||
|
||||
private final String name;
|
||||
private final String version;
|
||||
private final String javaVersion;
|
||||
private final String architecture;
|
||||
private final String operatingSystem;
|
||||
|
||||
private final NetworkInfo network;
|
||||
private final MCInfo mcInfo;
|
||||
|
||||
VersionInfo() {
|
||||
this.name = GeyserConnector.NAME;
|
||||
this.version = GeyserConnector.VERSION;
|
||||
this.javaVersion = System.getProperty("java.version");
|
||||
this.architecture = System.getProperty("os.arch"); // Usually gives Java architecture but still may be helpful.
|
||||
this.operatingSystem = System.getProperty("os.name");
|
||||
|
||||
this.network = new NetworkInfo();
|
||||
this.mcInfo = new MCInfo();
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class NetworkInfo {
|
||||
|
||||
private String internalIP;
|
||||
private final boolean dockerCheck;
|
||||
|
||||
NetworkInfo() {
|
||||
try {
|
||||
// This is the most reliable for getting the main local IP
|
||||
Socket socket = new Socket();
|
||||
socket.connect(new InetSocketAddress("geysermc.org", 80));
|
||||
this.internalIP = socket.getLocalAddress().getHostAddress();
|
||||
} catch (IOException e1) {
|
||||
try {
|
||||
// Fallback to the normal way of getting the local IP
|
||||
this.internalIP = InetAddress.getLocalHost().getHostAddress();
|
||||
} catch (UnknownHostException ignored) { }
|
||||
}
|
||||
|
||||
this.dockerCheck = DockerCheck.checkBasic();
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
public static class MCInfo {
|
||||
|
||||
private final String bedrockVersion;
|
||||
private final int bedrockProtocol;
|
||||
private final String javaVersion;
|
||||
private final int javaProtocol;
|
||||
|
||||
MCInfo() {
|
||||
this.bedrockVersion = GeyserConnector.BEDROCK_PACKET_CODEC.getMinecraftVersion();
|
||||
this.bedrockProtocol = GeyserConnector.BEDROCK_PACKET_CODEC.getProtocolVersion();
|
||||
this.javaVersion = MinecraftConstants.GAME_VERSION;
|
||||
this.javaProtocol = MinecraftConstants.PROTOCOL_VERSION;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -55,4 +55,19 @@ public class DockerCheck {
|
|||
}
|
||||
} catch (Exception e) { } // Ignore any errors, inc ip failed to fetch, process could not run or access denied
|
||||
}
|
||||
|
||||
public static boolean checkBasic() {
|
||||
try {
|
||||
String OS = System.getProperty("os.name").toLowerCase();
|
||||
if (OS.indexOf("nix") >= 0 || OS.indexOf("nux") >= 0 || OS.indexOf("aix") > 0) {
|
||||
String output = new String(Files.readAllBytes(Paths.get("/proc/1/cgroup")));
|
||||
|
||||
if (output.contains("docker")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) { } // Ignore any errors, inc ip failed to fetch, process could not run or access denied
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,11 +25,10 @@
|
|||
|
||||
package org.geysermc.connector.utils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
|
@ -81,4 +80,31 @@ public class WebUtils {
|
|||
throw new AssertionError("Unable to download and save file: " + fileLocation + " (" + reqURL + ")", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static String post(String reqURL, String postContent) throws IOException {
|
||||
URL url = null;
|
||||
url = new URL(reqURL);
|
||||
HttpURLConnection con = (HttpURLConnection) url.openConnection();
|
||||
con.setRequestMethod("POST");
|
||||
con.setRequestProperty("Content-Type", "text/plain");
|
||||
con.setDoOutput(true);
|
||||
|
||||
OutputStream out = con.getOutputStream();
|
||||
out.write(postContent.getBytes(StandardCharsets.UTF_8));
|
||||
out.close();
|
||||
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
|
||||
String inputLine;
|
||||
StringBuffer content = new StringBuffer();
|
||||
|
||||
while ((inputLine = in.readLine()) != null) {
|
||||
content.append(inputLine);
|
||||
content.append("\n");
|
||||
}
|
||||
|
||||
in.close();
|
||||
con.disconnect();
|
||||
|
||||
return content.toString();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue