001/* 002 * PlotSquared, a land and world management plugin for Minecraft. 003 * Copyright (C) IntellectualSites <https://intellectualsites.com> 004 * Copyright (C) IntellectualSites team and contributors 005 * 006 * This program is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * This program is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with this program. If not, see <https://www.gnu.org/licenses/>. 018 */ 019package com.plotsquared.core.command; 020 021import com.google.gson.JsonObject; 022import com.google.gson.JsonParser; 023import com.google.inject.Inject; 024import com.intellectualsites.paster.IncendoPaster; 025import com.plotsquared.core.PlotSquared; 026import com.plotsquared.core.configuration.Settings; 027import com.plotsquared.core.configuration.Storage; 028import com.plotsquared.core.configuration.caption.TranslatableCaption; 029import com.plotsquared.core.inject.annotations.ConfigFile; 030import com.plotsquared.core.inject.annotations.WorldFile; 031import com.plotsquared.core.player.PlotPlayer; 032import com.plotsquared.core.util.PremiumVerification; 033import com.plotsquared.core.util.task.TaskManager; 034import net.kyori.adventure.text.minimessage.Template; 035import org.checkerframework.checker.nullness.qual.NonNull; 036 037import java.io.File; 038import java.io.IOException; 039import java.lang.management.ManagementFactory; 040import java.lang.management.RuntimeMXBean; 041import java.nio.file.Files; 042import java.util.concurrent.TimeUnit; 043 044@CommandDeclaration(command = "debugpaste", 045 aliases = "dp", 046 usage = "/plot debugpaste", 047 permission = "plots.debugpaste", 048 category = CommandCategory.DEBUG, 049 confirmation = true, 050 requiredType = RequiredType.NONE) 051public class DebugPaste extends SubCommand { 052 053 private final File configFile; 054 private final File worldfile; 055 056 @Inject 057 public DebugPaste( 058 @ConfigFile final @NonNull File configFile, 059 @WorldFile final @NonNull File worldFile 060 ) { 061 this.configFile = configFile; 062 this.worldfile = worldFile; 063 } 064 065 @Override 066 public boolean onCommand(final PlotPlayer<?> player, String[] args) { 067 TaskManager.runTaskAsync(() -> { 068 try { 069 StringBuilder b = new StringBuilder(); 070 b.append( 071 """ 072 # Welcome to this paste 073 # It is meant to provide us at IntellectualSites with better information about your problem 074 """ 075 ); 076 b.append("# PlotSquared Information\n"); 077 b.append("PlotSquared Version: ").append(PlotSquared.get().getVersion()) 078 .append("\n"); 079 b.append("Database Type: ").append(Storage.MySQL.USE ? "MySQL" : "SQLite").append("\n"); 080 b.append("Resource ID: ").append(PremiumVerification.getResourceID()).append("\n"); 081 b.append("Download ID: ").append(PremiumVerification.getDownloadID()).append("\n"); 082 b.append("This PlotSquared version is licensed to the spigot user ") 083 .append(PremiumVerification.getUserID()).append("\n\n"); 084 b.append("# WorldEdit implementation:\n"); 085 b.append(PlotSquared.platform().worldEditImplementations()).append("\n\n"); 086 b.append("# Server Information\n"); 087 b.append("Server Version: ").append(PlotSquared.platform().serverImplementation()) 088 .append("\n"); 089 b.append("online_mode: ").append(!Settings.UUID.OFFLINE).append(';') 090 .append(!Settings.UUID.OFFLINE).append('\n'); 091 b.append(PlotSquared.platform().pluginsFormatted()); 092 b.append("\n\n# YAY! Now, let's see what we can find in your JVM\n"); 093 Runtime runtime = Runtime.getRuntime(); 094 RuntimeMXBean rb = ManagementFactory.getRuntimeMXBean(); 095 b.append("Uptime: ") 096 .append(TimeUnit.MINUTES.convert(rb.getUptime(), TimeUnit.MILLISECONDS)) 097 .append(" minutes") 098 .append('\n'); 099 b.append("JVM Flags: ").append(rb.getInputArguments()).append('\n'); 100 b.append("Free Memory: ").append(runtime.freeMemory() / 1024 / 1024).append(" MB") 101 .append('\n'); 102 b.append("Max Memory: ").append(runtime.maxMemory() / 1024 / 1024).append(" MB") 103 .append('\n'); 104 b.append("Total Memory: ").append(runtime.totalMemory() / 1024 / 1024).append(" MB") 105 .append('\n'); 106 b.append("Available Processors: ").append(runtime.availableProcessors()).append('\n'); 107 b.append("Java Name: ").append(rb.getVmName()).append('\n'); 108 b.append("Java Version: '").append(System.getProperty("java.version")) 109 .append("'\n"); 110 b.append("Java Vendor: '").append(System.getProperty("java.vendor")).append("'\n"); 111 b.append("Operating System: '").append(System.getProperty("os.name")).append("'\n"); 112 b.append("OS Version: ").append(System.getProperty("os.version")).append('\n'); 113 b.append("OS Arch: ").append(System.getProperty("os.arch")).append('\n'); 114 b.append("# Okay :D Great. You are now ready to create your bug report!"); 115 b.append( 116 "\n# You can do so at https://github.com/IntellectualSites/PlotSquared/issues"); 117 b.append("\n# or via our Discord at https://discord.gg/intellectualsites"); 118 119 final IncendoPaster incendoPaster = new IncendoPaster("plotsquared"); 120 incendoPaster.addFile(new IncendoPaster.PasteFile("information", b.toString())); 121 122 try { 123 final File logFile = 124 new File("logs/latest.log"); 125 if (Files.size(logFile.toPath()) > 14_000_000) { 126 throw new IOException( 127 "The latest.log is larger than 14MB. Please reboot your server and submit a new paste."); 128 } 129 incendoPaster 130 .addFile(logFile); 131 } catch (IOException ignored) { 132 player.sendMessage( 133 TranslatableCaption.of("debugpaste.latest_log"), 134 Template.of("file", "latest.log"), 135 Template.of("size", "14MB") 136 ); 137 } 138 139 try { 140 incendoPaster.addFile(this.configFile); 141 } catch (final IllegalArgumentException ignored) { 142 player.sendMessage( 143 TranslatableCaption.of("debugpaste.empty_file"), 144 Template.of("file", "settings.yml") 145 ); 146 } 147 try { 148 incendoPaster.addFile(this.worldfile); 149 } catch (final IllegalArgumentException ignored) { 150 player.sendMessage( 151 TranslatableCaption.of("debugpaste.empty_file"), 152 Template.of("file", "worlds.yml") 153 ); 154 } 155 156 try { 157 final File MultiverseWorlds = new File( 158 PlotSquared.platform().getDirectory(), 159 "../Multiverse-Core/worlds.yml" 160 ); 161 incendoPaster.addFile(MultiverseWorlds, "Multiverse-Core/worlds.yml"); 162 } catch (final IOException ignored) { 163 player.sendMessage( 164 TranslatableCaption.of("debugpaste.skip_multiverse"), 165 Template.of("file", "worlds.yml") 166 ); 167 } 168 169 try { 170 final String rawResponse = incendoPaster.upload(); 171 final JsonObject jsonObject = 172 new JsonParser().parse(rawResponse).getAsJsonObject(); 173 174 if (jsonObject.has("created")) { 175 final String pasteId = jsonObject.get("paste_id").getAsString(); 176 final String link = 177 String.format("https://athion.net/ISPaster/paste/view/%s", pasteId); 178 player.sendMessage( 179 TranslatableCaption.of("debugpaste.debug_report_created"), 180 Template.of("url", link) 181 ); 182 } else { 183 final String responseMessage = jsonObject.get("response").getAsString(); 184 player.sendMessage( 185 TranslatableCaption.of("debugpaste.creation_failed"), 186 Template.of("value", responseMessage) 187 ); 188 } 189 } catch (final Throwable throwable) { 190 throwable.printStackTrace(); 191 player.sendMessage( 192 TranslatableCaption.of("debugpaste.creation_failed"), 193 Template.of("value", throwable.getMessage()) 194 ); 195 } 196 } catch (IOException e) { 197 e.printStackTrace(); 198 } 199 }); 200 return true; 201 } 202 203}